diff --git a/internal_packages/composer-templates/lib/preferences-templates.cjsx b/internal_packages/composer-templates/lib/preferences-templates.cjsx deleted file mode 100644 index 92cbb8381..000000000 --- a/internal_packages/composer-templates/lib/preferences-templates.cjsx +++ /dev/null @@ -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) -> - {template.name} - - - {options} - - - _renderEditableTemplate: -> - - - _renderHTMLTemplate: -> - - - _renderModeToggle: -> - if @state.editAsHTML - return @setState(editAsHTML: false); return}>Edit live preview - else - return @setState(editAsHTML: true); return}>Edit raw HTML - - - - # TEMPLATE NAME EDITING - _renderEditName: -> - - Template Name: - Save Name - Cancel - - - _renderName: -> - rawText = if @state.editAsHTML then "Raw HTML " else "" - - {rawText}Template: {@_renderTemplatePicker()} - New - @setState(editState: "name") }>Rename - - - _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 = Cancel - - Template Name: - Save - {if @state.templates.length then cancel} - - - - # MAIN RENDER - render: => - deleteBtn = - - - - - editor = - - - {if @state.editAsHTML then @_renderHTMLTemplate() else @_renderEditableTemplate()} - - - - { if _.size(@_templateSaveQueue) > 0 then "Saving changes..." else "Changes saved." } - - {if @state.editState == null then deleteBtn else ""} - - - {@_renderModeToggle()} - - - - noTemplatesMessage = - - You don't have any templates! Enter a template name and press Save to create one. - - - - - { - 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} - - - - - 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: {"{{"}variable_name{"}}"} - - - Reply templates are saved in the ~/.nylas/templates 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. - - - 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. - - - - -module.exports = PreferencesTemplates diff --git a/internal_packages/composer-templates/lib/preferences-templates.jsx b/internal_packages/composer-templates/lib/preferences-templates.jsx new file mode 100644 index 000000000..7bd746a3d --- /dev/null +++ b/internal_packages/composer-templates/lib/preferences-templates.jsx @@ -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 {template.name} + }); + + return ( + + {options} + + ); + } + + _renderEditableTemplate() { + return ( + + ); + } + + _renderHTMLTemplate() { + return ( + + ); + } + + _renderModeToggle() { + if (this.state.editAsHTML) { + return ( {this.setState({editAsHTML: false});}}>Edit live preview); + } + return ( {this.setState({editAsHTML: true});}}>Edit raw HTML); + } + + // TEMPLATE NAME EDITING + _renderEditName() { + return ( + + Template Name: + Save Name + Cancel + + ); + } + + _renderName() { + const rawText = this.state.editAsHTML ? "Raw HTML " : ""; + return ( + + {rawText}Template: {this._renderTemplatePicker()} + New + {this.setState({editState: "name"});}}>Rename + + ); + } + + _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 = (Cancel); + return ( + + Template Name: + Save + {this.state.templates.length ? cancel : null} + + ); + } + + // MAIN RENDER + render() { + const deleteBtn = ( + + + + ); + + const editor = ( + + + {this.state.editAsHTML ? this._renderHTMLTemplate() : this._renderEditableTemplate()} + + + + {_.size(this._templateSaveQueue) > 0 ? "Saving changes..." : "Changes saved."} + + {this.state.editState === null ? deleteBtn : ""} + + + {this._renderModeToggle()} + + + ); + + let editContainer = this._renderName(); + if (this.state.editState === "name") { + editContainer = this._renderEditName(); + } else if (this.state.editState === "new") { + editContainer = this._renderCreateNew(); + } + + const noTemplatesMessage = ( + + {`You don't have any templates! Enter a template name and press save to create one.`} + + ); + + return ( + + + {editContainer} + {this.state.editState !== "new" ? editor : null} + {this.state.templates.length === 0 ? noTemplatesMessage : null} + + + + + 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`}: {"{{"}variable_name{"}}"} + + + Reply templates are saved in the ~/.nylas/templates 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. + + + 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. + + + + ); + } + +} + +export default PreferencesTemplates;
- 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: {"{{"}variable_name{"}}"} -
- Reply templates are saved in the ~/.nylas/templates 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. -
- 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. -
+ 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`}: {"{{"}variable_name{"}}"} +
+ Reply templates are saved in the ~/.nylas/templates 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. +
+ 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. +