mirror of
https://github.com/Foundry376/Mailspring.git
synced 2024-09-21 15:56:10 +08:00
fix(templates): Convert to ES6 and allow creation of new templates
This commit is contained in:
parent
6e07dce03c
commit
e2480c1e36
|
@ -1,265 +0,0 @@
|
||||||
_ = require 'underscore'
|
|
||||||
{Contenteditable, RetinaImg, Flexbox} = require 'nylas-component-kit'
|
|
||||||
{AccountStore, Utils, React} = require 'nylas-exports'
|
|
||||||
TemplateStore = require './template-store'
|
|
||||||
TemplateEditor = require './template-editor'
|
|
||||||
|
|
||||||
class PreferencesTemplates extends React.Component
|
|
||||||
@displayName: 'PreferencesTemplates'
|
|
||||||
|
|
||||||
constructor: (@props) ->
|
|
||||||
@_templateSaveQueue = {}
|
|
||||||
|
|
||||||
{templates, selectedTemplate, selectedTemplateName} = @_getStateFromStores()
|
|
||||||
@state =
|
|
||||||
editAsHTML: false
|
|
||||||
editState: if templates.length==0 then "new" else null
|
|
||||||
templates: templates
|
|
||||||
selectedTemplate: selectedTemplate
|
|
||||||
selectedTemplateName: selectedTemplateName
|
|
||||||
contents: null
|
|
||||||
|
|
||||||
componentDidMount: ->
|
|
||||||
@usub = TemplateStore.listen @_onChange
|
|
||||||
|
|
||||||
componentWillUnmount: ->
|
|
||||||
@usub()
|
|
||||||
if @state.selectedTemplate?
|
|
||||||
@_saveTemplateNow(@state.selectedTemplate.name, @state.contents)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#SAVING AND LOADING TEMPLATES
|
|
||||||
_loadTemplateContents: (template) =>
|
|
||||||
if template
|
|
||||||
TemplateStore.getTemplateContents(template.id, (contents) =>
|
|
||||||
@setState({contents: contents})
|
|
||||||
)
|
|
||||||
|
|
||||||
_saveTemplateNow: (name, contents, callback) =>
|
|
||||||
TemplateStore.saveTemplate(name, contents, callback)
|
|
||||||
|
|
||||||
_saveTemplateSoon: (name, contents) =>
|
|
||||||
@_templateSaveQueue[name] = contents
|
|
||||||
@_saveTemplatesFromCache()
|
|
||||||
|
|
||||||
__saveTemplatesFromCache: =>
|
|
||||||
for name, contents of @_templateSaveQueue
|
|
||||||
@_saveTemplateNow(name, contents)
|
|
||||||
|
|
||||||
@_templateSaveQueue = {}
|
|
||||||
|
|
||||||
_saveTemplatesFromCache: _.debounce(PreferencesTemplates::__saveTemplatesFromCache, 500)
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# OVERALL STATE HANDLING
|
|
||||||
_onChange: =>
|
|
||||||
@setState @_getStateFromStores()
|
|
||||||
|
|
||||||
_getStateFromStores: ->
|
|
||||||
templates = TemplateStore.items()
|
|
||||||
#selectedTemplate = _.findWhere(templates, {id: @state?.selectedTemplate?.id}) || templates[0]
|
|
||||||
|
|
||||||
selectedTemplate = @state?.selectedTemplate
|
|
||||||
# deleted
|
|
||||||
if selectedTemplate? and selectedTemplate.id not in _.pluck(templates, "id")
|
|
||||||
selectedTemplate = null
|
|
||||||
# none selected
|
|
||||||
else if not selectedTemplate
|
|
||||||
selectedTemplate = if templates.length > 0 then templates[0] else null
|
|
||||||
@_loadTemplateContents(selectedTemplate)
|
|
||||||
if selectedTemplate
|
|
||||||
selectedTemplateName = @state?.selectedTemplateName || selectedTemplate.name
|
|
||||||
return {templates, selectedTemplate, selectedTemplateName}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# TEMPLATE CONTENT EDITING
|
|
||||||
|
|
||||||
_onEditTemplate: (event) =>
|
|
||||||
html = event.target.value
|
|
||||||
@setState contents: html
|
|
||||||
if @state.selectedTemplate?
|
|
||||||
@_saveTemplateSoon(@state.selectedTemplate.name, html)
|
|
||||||
|
|
||||||
|
|
||||||
_onSelectTemplate: (event) =>
|
|
||||||
if @state.selectedTemplate?
|
|
||||||
@_saveTemplateNow(@state.selectedTemplate.name, @state.contents)
|
|
||||||
selectedTemplate = null
|
|
||||||
for template in @state.templates
|
|
||||||
if template.id == event.target.value
|
|
||||||
selectedTemplate = template
|
|
||||||
@setState
|
|
||||||
selectedTemplate: selectedTemplate
|
|
||||||
selectedTemplateName: selectedTemplate?.name
|
|
||||||
contents: null
|
|
||||||
@_loadTemplateContents(selectedTemplate)
|
|
||||||
|
|
||||||
_renderTemplatePicker: ->
|
|
||||||
options = @state.templates.map (template) ->
|
|
||||||
<option value={template.id} key={template.id}>{template.name}</option>
|
|
||||||
|
|
||||||
<select value={@state.selectedTemplate?.id} onChange={@_onSelectTemplate}>
|
|
||||||
{options}
|
|
||||||
</select>
|
|
||||||
|
|
||||||
_renderEditableTemplate: ->
|
|
||||||
<Contenteditable
|
|
||||||
ref="templateInput"
|
|
||||||
value={@state.contents || ""}
|
|
||||||
onChange={@_onEditTemplate}
|
|
||||||
extensions={[TemplateEditor]}
|
|
||||||
spellcheck={false} />
|
|
||||||
|
|
||||||
_renderHTMLTemplate: ->
|
|
||||||
<textarea ref="templateHTMLInput"
|
|
||||||
value={@state.contents || ""}
|
|
||||||
onChange={@_onEditTemplate}/>
|
|
||||||
|
|
||||||
_renderModeToggle: ->
|
|
||||||
if @state.editAsHTML
|
|
||||||
return <a onClick={=> @setState(editAsHTML: false); return}>Edit live preview</a>
|
|
||||||
else
|
|
||||||
return <a onClick={=> @setState(editAsHTML: true); return}>Edit raw HTML</a>
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# TEMPLATE NAME EDITING
|
|
||||||
_renderEditName: ->
|
|
||||||
<div className="section-title">
|
|
||||||
Template Name: <input type="text" className="template-name-input" value={@state.selectedTemplateName} onChange={@_onEditName}/>
|
|
||||||
<button className="btn template-name-btn" onClick={@_saveName}>Save Name</button>
|
|
||||||
<button className="btn template-name-btn" onClick={@_cancelEditName}>Cancel</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
_renderName: ->
|
|
||||||
rawText = if @state.editAsHTML then "Raw HTML " else ""
|
|
||||||
<div className="section-title">
|
|
||||||
{rawText}Template: {@_renderTemplatePicker()}
|
|
||||||
<button className="btn template-name-btn" title="New template" onClick={@_startNewTemplate}>New</button>
|
|
||||||
<button className="btn template-name-btn" onClick={ => @setState(editState: "name") }>Rename</button>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
_onEditName: =>
|
|
||||||
@setState({selectedTemplateName: event.target.value})
|
|
||||||
|
|
||||||
_cancelEditName: =>
|
|
||||||
@setState
|
|
||||||
selectedTemplateName: @state.selectedTemplate?.name
|
|
||||||
editState: null
|
|
||||||
|
|
||||||
_saveName: =>
|
|
||||||
if @state.selectedTemplate?.name != @state.selectedTemplateName
|
|
||||||
TemplateStore.renameTemplate(@state.selectedTemplate.name, @state.selectedTemplateName, (renamedTemplate) =>
|
|
||||||
@setState
|
|
||||||
selectedTemplate: renamedTemplate
|
|
||||||
editState: null
|
|
||||||
)
|
|
||||||
else
|
|
||||||
@setState
|
|
||||||
editState: null
|
|
||||||
|
|
||||||
|
|
||||||
# DELETE AND NEW
|
|
||||||
_deleteTemplate: =>
|
|
||||||
numTemplates = @state.templates.length
|
|
||||||
if @state.selectedTemplate?
|
|
||||||
TemplateStore.deleteTemplate(@state.selectedTemplate.name)
|
|
||||||
if numTemplates==1
|
|
||||||
@setState
|
|
||||||
editState: "new"
|
|
||||||
selectedTemplate: null
|
|
||||||
selectedTemplateName: ""
|
|
||||||
contents: ""
|
|
||||||
|
|
||||||
_startNewTemplate: =>
|
|
||||||
@setState
|
|
||||||
editState: "new"
|
|
||||||
selectedTemplate: null
|
|
||||||
selectedTemplateName: ""
|
|
||||||
contents: ""
|
|
||||||
|
|
||||||
_saveNewTemplate: =>
|
|
||||||
TemplateStore.saveNewTemplate(@state.selectedTemplateName, @state.contents || "", (template) =>
|
|
||||||
@setState
|
|
||||||
selectedTemplate: template
|
|
||||||
editState: null
|
|
||||||
)
|
|
||||||
|
|
||||||
_cancelNewTemplate: =>
|
|
||||||
template = if @state.templates.length>0 then @state.templates[0] else null
|
|
||||||
@setState
|
|
||||||
selectedTemplate: template
|
|
||||||
selectedTemplateName: template?.name
|
|
||||||
editState: null
|
|
||||||
@_loadTemplateContents(template)
|
|
||||||
|
|
||||||
_renderCreateNew: ->
|
|
||||||
cancel = <button className="btn template-name-btn" onClick={@_cancelNewTemplate}>Cancel</button>
|
|
||||||
<div className="section-title">
|
|
||||||
Template Name: <input type="text" className="template-name-input" value={@state.selectedTemplateName} onChange={@_onEditName}/>
|
|
||||||
<button className="btn btn-emphasis template-name-btn" onClick={@_saveNewTemplate}>Save</button>
|
|
||||||
{if @state.templates.length then cancel}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
# MAIN RENDER
|
|
||||||
render: =>
|
|
||||||
deleteBtn =
|
|
||||||
<button className="btn" title="Delete template" onClick={@_deleteTemplate}>
|
|
||||||
<RetinaImg name="icon-composer-trash.png" mode={RetinaImg.Mode.ContentIsMask} />
|
|
||||||
</button>
|
|
||||||
|
|
||||||
editor =
|
|
||||||
<div>
|
|
||||||
<div className="template-wrap">
|
|
||||||
{if @state.editAsHTML then @_renderHTMLTemplate() else @_renderEditableTemplate()}
|
|
||||||
</div>
|
|
||||||
<div style={marginTop: "5px"}>
|
|
||||||
<span className="editor-note">
|
|
||||||
{ if _.size(@_templateSaveQueue) > 0 then "Saving changes..." else "Changes saved." }
|
|
||||||
</span>
|
|
||||||
<span style={float:"right"}>{if @state.editState == null then deleteBtn else ""}</span>
|
|
||||||
</div>
|
|
||||||
<div className="toggle-mode" style={marginTop: "1em"}>
|
|
||||||
{@_renderModeToggle()}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
noTemplatesMessage =
|
|
||||||
<div className="template-status-bar no-templates-message">
|
|
||||||
You don't have any templates! Enter a template name and press Save to create one.
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="container-templates">
|
|
||||||
<section style={if @state.editState is "new" then {marginBottom:50}}>
|
|
||||||
{
|
|
||||||
switch @state.editState
|
|
||||||
when "name" then @_renderEditName()
|
|
||||||
when "new" then @_renderCreateNew()
|
|
||||||
else @_renderName()
|
|
||||||
}
|
|
||||||
{if @state.editState isnt "new" then editor}
|
|
||||||
{if @state.templates.length==0 then noTemplatesMessage}
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section className="templates-instructions">
|
|
||||||
<p>
|
|
||||||
The Quick Replies plugin allows you to create templated email replies, with variables that
|
|
||||||
you can quickly fill in before sending your email message. To create a variable, type a set of double curly
|
|
||||||
brackets wrapping the variable's name, like this: <strong>{"{{"}variable_name{"}}"}</strong>
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
Reply templates are saved in the <strong>~/.nylas/templates</strong> directory on your computer. Each template
|
|
||||||
is an HTML file - the name of the file is the name of the template, and its contents are the default message body.
|
|
||||||
</p>
|
|
||||||
<p>
|
|
||||||
In raw HTML, variables are defined as HTML <code> tags with class "var empty". Typing curly brackets creates a tag
|
|
||||||
automatically. The code tags are colored yellow to show the variable regions, but will be stripped out before the message is sent.
|
|
||||||
</p>
|
|
||||||
</section>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
module.exports = PreferencesTemplates
|
|
|
@ -0,0 +1,325 @@
|
||||||
|
import _ from 'underscore';
|
||||||
|
import {Contenteditable, RetinaImg} from 'nylas-component-kit';
|
||||||
|
import {React} from 'nylas-exports';
|
||||||
|
|
||||||
|
import TemplateStore from './template-store';
|
||||||
|
import TemplateEditor from './template-editor';
|
||||||
|
|
||||||
|
|
||||||
|
class PreferencesTemplates extends React.Component {
|
||||||
|
static displayName = 'PreferencesTemplates';
|
||||||
|
|
||||||
|
constructor() {
|
||||||
|
super();
|
||||||
|
this._templateSaveQueue = {};
|
||||||
|
|
||||||
|
const {templates, selectedTemplate, selectedTemplateName} = this._getStateFromStores();
|
||||||
|
this.state = {
|
||||||
|
editAsHTML: false,
|
||||||
|
editState: templates.length === 0 ? "new" : null,
|
||||||
|
templates: templates,
|
||||||
|
selectedTemplate: selectedTemplate,
|
||||||
|
selectedTemplateName: selectedTemplateName,
|
||||||
|
contents: null,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.unsub = TemplateStore.listen(this._onChange);
|
||||||
|
}
|
||||||
|
|
||||||
|
componentWillUnmount() {
|
||||||
|
this.unsub();
|
||||||
|
if (this.state.selectedTemplate) {
|
||||||
|
this._saveTemplateNow(this.state.selectedTemplate.name, this.state.contents);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAVING AND LOADING TEMPLATES
|
||||||
|
_loadTemplateContents = (template) => {
|
||||||
|
if (template) {
|
||||||
|
TemplateStore.getTemplateContents(template.id, (contents) => {
|
||||||
|
this.setState({contents: contents});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveTemplateNow(name, contents, callback) {
|
||||||
|
TemplateStore.saveTemplate(name, contents, callback);
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveTemplateSoon(name, contents) {
|
||||||
|
this._templateSaveQueue[name] = contents;
|
||||||
|
this._saveTemplatesFromCache();
|
||||||
|
}
|
||||||
|
|
||||||
|
__saveTemplatesFromCache() {
|
||||||
|
for (const name in this._templateSaveQueue) {
|
||||||
|
if (this._templateSaveQueue.hasOwnProperty(name)) {
|
||||||
|
this._saveTemplateNow(name, this._templateSaveQueue[name]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this._templateSaveQueue = {};
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveTemplatesFromCache = _.debounce(PreferencesTemplates.prototype.__saveTemplatesFromCache, 500);
|
||||||
|
|
||||||
|
// OVERALL STATE HANDLING
|
||||||
|
_onChange = () => {
|
||||||
|
this.setState(this._getStateFromStores());
|
||||||
|
}
|
||||||
|
|
||||||
|
_getStateFromStores() {
|
||||||
|
const templates = TemplateStore.items();
|
||||||
|
let selectedTemplate = this.state ? this.state.selectedTemplate : null;
|
||||||
|
if (selectedTemplate && _.pluck(templates, "id").indexOf(selectedTemplate.id) === -1) {
|
||||||
|
selectedTemplate = null;
|
||||||
|
} else if (!selectedTemplate) {
|
||||||
|
selectedTemplate = templates.length > 0 ? templates[0] : null;
|
||||||
|
}
|
||||||
|
this._loadTemplateContents(selectedTemplate);
|
||||||
|
let selectedTemplateName = null;
|
||||||
|
if (selectedTemplate) {
|
||||||
|
selectedTemplateName = this.state ? this.state.selectedTemplateName : selectedTemplate.name;
|
||||||
|
}
|
||||||
|
return {templates, selectedTemplate, selectedTemplateName};
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEMPLATE CONTENT EDITING
|
||||||
|
_onEditTemplate = (event) => {
|
||||||
|
const html = event.target.value;
|
||||||
|
this.setState({contents: html});
|
||||||
|
if (this.state.selectedTemplate) {
|
||||||
|
this._saveTemplateSoon(this.state.selectedTemplate.name, html);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
_onSelectTemplate = (event) => {
|
||||||
|
if (this.state.selectedTemplate) {
|
||||||
|
this._saveTemplateNow(this.state.selectedTemplate.name, this.state.contents);
|
||||||
|
}
|
||||||
|
let selectedTemplate = null;
|
||||||
|
for (const template in this.state.templates) {
|
||||||
|
if (template.id === event.target.value) {
|
||||||
|
selectedTemplate = template;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.setState({
|
||||||
|
selectedTemplate: selectedTemplate,
|
||||||
|
selectedTemplateName: selectedTemplate ? selectedTemplate.name : null,
|
||||||
|
contents: null,
|
||||||
|
});
|
||||||
|
this._loadTemplateContents(selectedTemplate);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderTemplatePicker() {
|
||||||
|
const options = this.state.templates.map((template) => {
|
||||||
|
return <option value={template.id} key={template.id}>{template.name}</option>
|
||||||
|
});
|
||||||
|
|
||||||
|
return (
|
||||||
|
<select value={this.state.selectedTemplate ? this.state.selectedTemplate.id : null} onChange={this._onSelectTemplate}>
|
||||||
|
{options}
|
||||||
|
</select>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderEditableTemplate() {
|
||||||
|
return (
|
||||||
|
<Contenteditable
|
||||||
|
ref="templateInput"
|
||||||
|
value={this.state.contents || ""}
|
||||||
|
onChange={this._onEditTemplate}
|
||||||
|
extensions={[TemplateEditor]}
|
||||||
|
spellcheck={false} />
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderHTMLTemplate() {
|
||||||
|
return (
|
||||||
|
<textarea ref="templateHTMLInput"
|
||||||
|
value={this.state.contents || ""}
|
||||||
|
onChange={this._onEditTemplate}/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderModeToggle() {
|
||||||
|
if (this.state.editAsHTML) {
|
||||||
|
return (<a onClick={() => {this.setState({editAsHTML: false});}}>Edit live preview</a>);
|
||||||
|
}
|
||||||
|
return (<a onClick={() => {this.setState({editAsHTML: true});}}>Edit raw HTML</a>);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TEMPLATE NAME EDITING
|
||||||
|
_renderEditName() {
|
||||||
|
return (
|
||||||
|
<div className="section-title">
|
||||||
|
Template Name: <input type="text" className="template-name-input" value={this.state.selectedTemplateName} onChange={this._onEditName}/>
|
||||||
|
<button className="btn template-name-btn" onClick={this._saveName}>Save Name</button>
|
||||||
|
<button className="btn template-name-btn" onClick={this._cancelEditName}>Cancel</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderName() {
|
||||||
|
const rawText = this.state.editAsHTML ? "Raw HTML " : "";
|
||||||
|
return (
|
||||||
|
<div className="section-title">
|
||||||
|
{rawText}Template: {this._renderTemplatePicker()}
|
||||||
|
<button className="btn template-name-btn" title="New template" onClick={this._startNewTemplate}>New</button>
|
||||||
|
<button className="btn template-name-btn" onClick={() => {this.setState({editState: "name"});}}>Rename</button>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
_onEditName = (event) => {
|
||||||
|
this.setState({selectedTemplateName: event.target.value});
|
||||||
|
}
|
||||||
|
|
||||||
|
_cancelEditName = () => {
|
||||||
|
this.setState({
|
||||||
|
selectedTemplateName: this.state.selectedTemplate ? this.state.selectedTemplate.name : null,
|
||||||
|
editState: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveName = () => {
|
||||||
|
if (this.state.selectedTemplate && this.state.selectedTemplate.name !== this.state.selectedTemplateName) {
|
||||||
|
TemplateStore.renameTemplate(this.state.selectedTemplate.name, this.state.selectedTemplateName, (renamedTemplate) => {
|
||||||
|
this.setState({
|
||||||
|
selectedTemplate: renamedTemplate,
|
||||||
|
editState: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
this.setState({
|
||||||
|
editState: null,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DELETE AND NEW
|
||||||
|
_deleteTemplate = () => {
|
||||||
|
const numTemplates = this.state.templates.length;
|
||||||
|
if (this.state.selectedTemplate) {
|
||||||
|
TemplateStore.deleteTemplate(this.state.selectedTemplate.name);
|
||||||
|
}
|
||||||
|
if (numTemplates === 1) {
|
||||||
|
this.setState({
|
||||||
|
editState: "new",
|
||||||
|
selectedTemplate: null,
|
||||||
|
selectedTemplateName: "",
|
||||||
|
contents: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_startNewTemplate = () => {
|
||||||
|
this.setState({
|
||||||
|
editState: "new",
|
||||||
|
selectedTemplate: null,
|
||||||
|
selectedTemplateName: "",
|
||||||
|
contents: "",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_saveNewTemplate = () => {
|
||||||
|
TemplateStore.saveNewTemplate(this.state.selectedTemplateName, this.state.contents || "", (template) => {
|
||||||
|
this.setState({
|
||||||
|
selectedTemplate: template,
|
||||||
|
editState: null,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_cancelNewTemplate = () => {
|
||||||
|
const template = this.state.templates.length > 0 ? this.state.templates[0] : null;
|
||||||
|
this.setState({
|
||||||
|
selectedTemplate: template,
|
||||||
|
selectedTemplateName: template ? template.name : null,
|
||||||
|
editState: null,
|
||||||
|
});
|
||||||
|
this._loadTemplateContents(template);
|
||||||
|
}
|
||||||
|
|
||||||
|
_renderCreateNew() {
|
||||||
|
const cancel = (<button className="btn template-name-btn" onClick={this._cancelNewTemplate}>Cancel</button>);
|
||||||
|
return (
|
||||||
|
<div className="section-title">
|
||||||
|
Template Name: <input type="text" className="template-name-input" value={this.state.selectedTemplateName} onChange={this._onEditName}/>
|
||||||
|
<button className="btn btn-emphasis template-name-btn" onClick={this._saveNewTemplate}>Save</button>
|
||||||
|
{this.state.templates.length ? cancel : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// MAIN RENDER
|
||||||
|
render() {
|
||||||
|
const deleteBtn = (
|
||||||
|
<button className="btn" title="Delete template" onClick={this._deleteTemplate}>
|
||||||
|
<RetinaImg name="icon-composer-trash.png" mode={RetinaImg.Mode.ContentIsMask} />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
|
||||||
|
const editor = (
|
||||||
|
<div>
|
||||||
|
<div className="template-wrap">
|
||||||
|
{this.state.editAsHTML ? this._renderHTMLTemplate() : this._renderEditableTemplate()}
|
||||||
|
</div>
|
||||||
|
<div style={{marginTop: "5px"}}>
|
||||||
|
<span className="editor-note">
|
||||||
|
{_.size(this._templateSaveQueue) > 0 ? "Saving changes..." : "Changes saved."}
|
||||||
|
</span>
|
||||||
|
<span style={{float: "right"}}>{this.state.editState === null ? deleteBtn : ""}</span>
|
||||||
|
</div>
|
||||||
|
<div className="toggle-mode" style={{marginTop: "1em"}}>
|
||||||
|
{this._renderModeToggle()}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
let editContainer = this._renderName();
|
||||||
|
if (this.state.editState === "name") {
|
||||||
|
editContainer = this._renderEditName();
|
||||||
|
} else if (this.state.editState === "new") {
|
||||||
|
editContainer = this._renderCreateNew();
|
||||||
|
}
|
||||||
|
|
||||||
|
const noTemplatesMessage = (
|
||||||
|
<div className="template-status-bar no-templates-message">
|
||||||
|
{`You don't have any templates! Enter a template name and press save to create one.`}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="container-templates">
|
||||||
|
<section style={this.state.editState === "new" ? {marginBottom: 50} : null}>
|
||||||
|
{editContainer}
|
||||||
|
{this.state.editState !== "new" ? editor : null}
|
||||||
|
{this.state.templates.length === 0 ? noTemplatesMessage : null}
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section className="templates-instructions">
|
||||||
|
<p>
|
||||||
|
The Quick Replies plugin allows you to create templated email replies, with variables that
|
||||||
|
you can quickly replace before sending your email message. {`To create a variable, type a set of double curly
|
||||||
|
brackets wrapping the variable's name, like this`}: <strong>{"{{"}variable_name{"}}"}</strong>
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
Reply templates are saved in the <strong>~/.nylas/templates</strong> directory on your computer. Each template
|
||||||
|
is an HTML file—the name of the file is the name of the template, and its contents are the default message body.
|
||||||
|
</p>
|
||||||
|
<p>
|
||||||
|
In raw HTML, variables are defined as HTML <code> tags with class "var empty". Typing curly brackets creates a tag
|
||||||
|
automatically. The code tags are colored yellow to show the variable regions but will be removed before the message is
|
||||||
|
sent.
|
||||||
|
</p>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
export default PreferencesTemplates;
|
Loading…
Reference in a new issue