diff --git a/app/components/gh-koenig-editor.hbs b/app/components/gh-koenig-editor.hbs index df377e2b1..9fe784fe6 100644 --- a/app/components/gh-koenig-editor.hbs +++ b/app/components/gh-koenig-editor.hbs @@ -30,5 +30,7 @@ @scrollOffsetTopSelector={{this.scrollOffsetTopSelector}} @scrollOffsetBottomSelector={{this.scrollOffsetBottomSelector}} @wordCountDidChange={{action this.onWordCountChange}} + @snippets={{@snippets}} + @saveSnippet={{@saveSnippet}} /> \ No newline at end of file diff --git a/app/controllers/editor.js b/app/controllers/editor.js index d4caee5d4..05ab7fe64 100644 --- a/app/controllers/editor.js +++ b/app/controllers/editor.js @@ -138,6 +138,14 @@ export default Controller.extend({ } }), + _snippets: computed(function () { + return this.store.peekAll('snippet'); + }), + + snippets: computed('_snippets.@each.isNew', function () { + return this._snippets.reject(snippet => snippet.get('isNew')); + }), + _autosaveRunning: computed('_autosave.isRunning', '_timedSave.isRunning', function () { let autosave = this.get('_autosave.isRunning'); let timedsave = this.get('_timedSave.isRunning'); @@ -281,6 +289,27 @@ export default Controller.extend({ updateWordCount(counts) { this.set('wordCount', counts); + }, + + saveSnippet(snippet) { + let snippetRecord = this.store.createRecord('snippet', snippet); + return snippetRecord.save().then(() => { + this.notifications.closeAlerts('snippet.save'); + this.notifications.showNotification( + `Snippet saved as "${snippet.title}"`, + {type: 'success'} + ); + return snippetRecord; + }).catch((error) => { + if (!snippetRecord.errors.isEmpty) { + this.notifications.showAlert( + `Snippet save failed: ${snippetRecord.errors.messages.join('. ')}`, + {type: 'error', key: 'snippet.save'} + ); + } + snippetRecord.rollbackAttributes(); + throw error; + }); } }, diff --git a/app/controllers/posts.js b/app/controllers/posts.js index d3613111f..d816216e8 100644 --- a/app/controllers/posts.js +++ b/app/controllers/posts.js @@ -56,6 +56,7 @@ export default Controller.extend({ _hasLoadedTags: false, _hasLoadedAuthors: false, + _hasLoadedSnippets: false, availableTypes: null, availableVisibilities: null, @@ -133,6 +134,10 @@ export default Controller.extend({ return authors.findBy('slug', author) || {slug: '!unknown'}; }), + snippets: computed(function () { + return this.store.peekAll('snippet'); + }), + actions: { changeType(type) { this.set('type', get(type, 'value')); diff --git a/app/mixins/validation-engine.js b/app/mixins/validation-engine.js index b6082af78..0a074d2da 100644 --- a/app/mixins/validation-engine.js +++ b/app/mixins/validation-engine.js @@ -17,6 +17,7 @@ import SetupValidator from 'ghost-admin/validators/setup'; import SigninValidator from 'ghost-admin/validators/signin'; import SignupValidator from 'ghost-admin/validators/signup'; import SlackIntegrationValidator from 'ghost-admin/validators/slack-integration'; +import SnippetValidator from 'ghost-admin/validators/snippet'; import TagSettingsValidator from 'ghost-admin/validators/tag-settings'; import UserValidator from 'ghost-admin/validators/user'; import WebhookValidator from 'ghost-admin/validators/webhook'; @@ -52,7 +53,8 @@ export default Mixin.create({ member: MemberValidator, integration: IntegrationValidator, webhook: WebhookValidator, - label: LabelValidator + label: LabelValidator, + snippet: SnippetValidator }, // This adds the Errors object to the validation engine, and shouldn't affect diff --git a/app/models/snippet.js b/app/models/snippet.js new file mode 100644 index 000000000..6e3268b44 --- /dev/null +++ b/app/models/snippet.js @@ -0,0 +1,11 @@ +import Model, {attr} from '@ember-data/model'; +import ValidationEngine from 'ghost-admin/mixins/validation-engine'; + +export default Model.extend(ValidationEngine, { + validationType: 'snippet', + + title: attr('string'), + mobiledoc: attr('json-string'), + createdAtUTC: attr('moment-utc'), + updatedAtUTC: attr('moment-utc') +}); diff --git a/app/routes/posts.js b/app/routes/posts.js index d30d86fa0..40a439a54 100644 --- a/app/routes/posts.js +++ b/app/routes/posts.js @@ -79,7 +79,7 @@ export default AuthenticatedRoute.extend({ }); }, - // trigger a background load of all tags and authors for use in the filter dropdowns + // trigger a background load of all tags, authors, and snipps for use in filter dropdowns and card menu setupController(controller) { this._super(...arguments); @@ -96,6 +96,12 @@ export default AuthenticatedRoute.extend({ }); } }); + + if (!controller._hasLoadedSnippets) { + this.store.query('snippet', {limit: 'all'}).then(() => { + controller._hasLoadedSnippets = true; + }); + } }, actions: { diff --git a/app/templates/editor.hbs b/app/templates/editor.hbs index 18b03993e..d04fb7150 100644 --- a/app/templates/editor.hbs +++ b/app/templates/editor.hbs @@ -81,6 +81,8 @@ @scrollOffsetBottomSelector=".gh-mobile-nav-bar" @onEditorCreated={{action "setKoenigEditor"}} @onWordCountChange={{action "updateWordCount"}} + @snippets={{this.snippets}} + @saveSnippet={{action "saveSnippet"}} />