diff --git a/core/client/app/controllers/post-settings-menu.js b/core/client/app/controllers/post-settings-menu.js index b29b87dd44..320dc20737 100644 --- a/core/client/app/controllers/post-settings-menu.js +++ b/core/client/app/controllers/post-settings-menu.js @@ -1,7 +1,6 @@ import Ember from 'ember'; import {parseDateString} from 'ghost/utils/date-formatting'; import SettingsMenuMixin from 'ghost/mixins/settings-menu-controller'; -import SlugGenerator from 'ghost/models/slug-generator'; import boundOneWay from 'ghost/utils/bound-one-way'; import isNumber from 'ghost/utils/isNumber'; @@ -18,6 +17,7 @@ export default Controller.extend(SettingsMenuMixin, { ghostPaths: inject.service('ghost-paths'), notifications: inject.service(), session: inject.service(), + slugGenerator: inject.service('slug-generator'), initializeSelectedAuthor: observer('model', function () { return this.get('model.author').then((author) => { @@ -45,14 +45,6 @@ export default Controller.extend(SettingsMenuMixin, { slugValue: boundOneWay('model.slug'), - // Lazy load the slug generator - slugGenerator: computed(function () { - return SlugGenerator.create({ - ghostPaths: this.get('ghostPaths'), - slugType: 'post' - }); - }), - // Requests slug from title generateAndSetSlug(destination) { let title = this.get('model.titleScratch'); @@ -65,7 +57,7 @@ export default Controller.extend(SettingsMenuMixin, { } promise = RSVP.resolve(afterSave).then(() => { - return this.get('slugGenerator').generateSlug(title).then((slug) => { + return this.get('slugGenerator').generateSlug('post', title).then((slug) => { if (!isBlank(slug)) { this.set(destination, slug); } @@ -232,7 +224,7 @@ export default Controller.extend(SettingsMenuMixin, { return; } - this.get('slugGenerator').generateSlug(newSlug).then((serverSlug) => { + this.get('slugGenerator').generateSlug('post', newSlug).then((serverSlug) => { // If after getting the sanitized and unique slug back from the API // we end up with a slug that matches the existing slug, abort the change if (serverSlug === slug) { diff --git a/core/client/app/controllers/team/user.js b/core/client/app/controllers/team/user.js index 6638555c1a..a22b62ffcf 100644 --- a/core/client/app/controllers/team/user.js +++ b/core/client/app/controllers/team/user.js @@ -1,6 +1,5 @@ import Ember from 'ember'; import {request as ajax} from 'ic-ajax'; -import SlugGenerator from 'ghost/models/slug-generator'; import isNumber from 'ghost/utils/isNumber'; import boundOneWay from 'ghost/utils/bound-one-way'; import ValidationEngine from 'ghost/mixins/validation-engine'; @@ -22,6 +21,7 @@ export default Controller.extend(ValidationEngine, { ghostPaths: inject.service('ghost-paths'), notifications: inject.service(), session: inject.service(), + slugGenerator: inject.service('slug-generator'), user: alias('model'), currentUser: alias('session.user'), @@ -74,14 +74,6 @@ export default Controller.extend(ValidationEngine, { return `${this.get('user.name')}'s Cover Image`; }), - // Lazy load the slug generator for slugPlaceholder - slugGenerator: computed(function () { - return SlugGenerator.create({ - ghostPaths: this.get('ghostPaths'), - slugType: 'user' - }); - }), - roles: computed(function () { return this.store.query('role', {permissions: 'assign'}); }), @@ -210,7 +202,7 @@ export default Controller.extend(ValidationEngine, { return; } - return this.get('slugGenerator').generateSlug(newSlug).then((serverSlug) => { + return this.get('slugGenerator').generateSlug('user', newSlug).then((serverSlug) => { // If after getting the sanitized and unique slug back from the API // we end up with a slug that matches the existing slug, abort the change if (serverSlug === slug) { diff --git a/core/client/app/models/slug-generator.js b/core/client/app/models/slug-generator.js deleted file mode 100644 index 3f4311202a..0000000000 --- a/core/client/app/models/slug-generator.js +++ /dev/null @@ -1,36 +0,0 @@ -import Ember from 'ember'; -import {request as ajax} from 'ic-ajax'; - -const {RSVP, inject} = Ember; - -export default Ember.Object.extend({ - slugType: null, - value: null, - - ghostPaths: inject.service('ghost-paths'), - - toString() { - return this.get('value'); - }, - - generateSlug(textToSlugify) { - let url; - - if (!textToSlugify) { - return RSVP.resolve(''); - } - - url = this.get('ghostPaths.url').api('slugs', this.get('slugType'), encodeURIComponent(textToSlugify)); - - return ajax(url, { - type: 'GET' - }).then((response) => { - let [firstSlug] = response.slugs; - let {slug} = firstSlug; - - this.set('value', slug); - - return slug; - }); - } -}); diff --git a/core/client/app/services/slug-generator.js b/core/client/app/services/slug-generator.js new file mode 100644 index 0000000000..c88232a048 --- /dev/null +++ b/core/client/app/services/slug-generator.js @@ -0,0 +1,25 @@ +import Ember from 'ember'; +import {request as ajax} from 'ic-ajax'; + +const {RSVP, inject, Service} = Ember; + +export default Service.extend({ + ghostPaths: inject.service('ghost-paths'), + + generateSlug(slugType, textToSlugify) { + let url; + + if (!textToSlugify) { + return RSVP.resolve(''); + } + + url = this.get('ghostPaths.url').api('slugs', slugType, encodeURIComponent(textToSlugify)); + + return ajax(url).then((response) => { + let [firstSlug] = response.slugs; + let {slug} = firstSlug; + + return slug; + }); + } +}); diff --git a/core/client/tests/integration/services/slug-generator-test.js b/core/client/tests/integration/services/slug-generator-test.js new file mode 100644 index 0000000000..c1f5adf6db --- /dev/null +++ b/core/client/tests/integration/services/slug-generator-test.js @@ -0,0 +1,62 @@ +import { expect } from 'chai'; +import { + describeModule, + it +} from 'ember-mocha'; +import Pretender from 'pretender'; +import Ember from 'ember'; + +const {dasherize} = Ember.String; + +function stubSlugEndpoint(server, type, slug) { + server.get('/ghost/api/v0.1/slugs/:type/:slug/', function (request) { + expect(request.params.type).to.equal(type); + expect(request.params.slug).to.equal(slug); + + return [ + 200, + {'Content-Type': 'application/json'}, + JSON.stringify({slugs: [{slug: dasherize(slug)}]}) + ]; + }); +} + +describeModule( + 'service:slug-generator', + 'Integration: Service: slug-generator', + { + integration: true + }, + function () { + let server; + + beforeEach(function () { + server = new Pretender(); + }); + + afterEach(function () { + server.shutdown(); + }); + + it('returns empty if no slug is provided', function (done) { + let service = this.subject(); + + service.generateSlug('post', '').then(function (slug) { + expect(slug).to.equal(''); + done(); + }); + }); + + it('calls correct endpoint and returns correct data', function (done) { + let rawSlug = 'a test post'; + stubSlugEndpoint(server, 'post', rawSlug); + + let service = this.subject(); + + service.generateSlug('post', rawSlug).then(function (slug) { + expect(slug).to.equal(dasherize(rawSlug)); + done(); + }); + }); + } +); diff --git a/core/client/tests/unit/controllers/post-settings-menu-test.js b/core/client/tests/unit/controllers/post-settings-menu-test.js index b418ab02e3..7718068453 100644 --- a/core/client/tests/unit/controllers/post-settings-menu-test.js +++ b/core/client/tests/unit/controllers/post-settings-menu-test.js @@ -15,7 +15,7 @@ describeModule( 'controller:post-settings-menu', 'Unit: Controller: post-settings-menu', { - needs: ['controller:application', 'service:notifications'] + needs: ['controller:application', 'service:notifications', 'service:slug-generator'] }, function () { @@ -389,7 +389,7 @@ describeModule( it('should generate a slug and set it on the destination', function (done) { let controller = this.subject({ slugGenerator: Ember.Object.create({ - generateSlug(str) { + generateSlug(slugType, str) { return Ember.RSVP.resolve(`${str}-slug`); } }), @@ -413,7 +413,7 @@ describeModule( it('should not set the destination if the title is "(Untitled)" and the post already has a slug', function (done) { let controller = this.subject({ slugGenerator: Ember.Object.create({ - generateSlug(str) { + generateSlug(slugType, str) { return Ember.RSVP.resolve(`${str}-slug`); } }), @@ -567,7 +567,7 @@ describeModule( it('should not set a new slug if the server-generated slug matches existing slug', function (done) { let controller = this.subject({ slugGenerator: Ember.Object.create({ - generateSlug(str) { + generateSlug(slugType, str) { let promise = Ember.RSVP.resolve(str.split('#')[0]); this.set('lastPromise', promise); return promise; @@ -593,7 +593,7 @@ describeModule( it('should not set a new slug if the only change is to the appended increment value', function (done) { let controller = this.subject({ slugGenerator: Ember.Object.create({ - generateSlug(str) { + generateSlug(slugType, str) { let sanitizedStr = str.replace(/[^a-zA-Z]/g, ''); let promise = Ember.RSVP.resolve(`${sanitizedStr}-2`); this.set('lastPromise', promise); @@ -620,7 +620,7 @@ describeModule( it('should set the slug if the new slug is different', function (done) { let controller = this.subject({ slugGenerator: Ember.Object.create({ - generateSlug(str) { + generateSlug(slugType, str) { let promise = Ember.RSVP.resolve(str); this.set('lastPromise', promise); return promise; @@ -647,7 +647,7 @@ describeModule( it('should save the post when the slug changes and the post is not new', function (done) { let controller = this.subject({ slugGenerator: Ember.Object.create({ - generateSlug(str) { + generateSlug(slugType, str) { let promise = Ember.RSVP.resolve(str); this.set('lastPromise', promise); return promise; @@ -679,7 +679,7 @@ describeModule( it('should not save the post when the slug changes and the post is new', function (done) { let controller = this.subject({ slugGenerator: Ember.Object.create({ - generateSlug(str) { + generateSlug(slugType, str) { let promise = Ember.RSVP.resolve(str); this.set('lastPromise', promise); return promise;