mirror of
https://github.com/TryGhost/Ghost.git
synced 2024-12-01 05:50:35 +03:00
Merge pull request #4335 from jaswilli/jscs
Enable JSCS checking on client.
This commit is contained in:
commit
20fbcc1e59
@ -189,7 +189,8 @@ var _ = require('lodash'),
|
||||
},
|
||||
client: {
|
||||
options: {
|
||||
config: '.jscsrc'
|
||||
config: '.jscsrc',
|
||||
esnext: true
|
||||
}
|
||||
},
|
||||
test: {
|
||||
@ -199,12 +200,6 @@ var _ = require('lodash'),
|
||||
}
|
||||
}, lintFiles);
|
||||
|
||||
// JSCS depends on Esprima which doesn't yet support ES6 module
|
||||
// syntax. As such we cannot run JSCS on the client code yet.
|
||||
// Related JSCS issue: https://github.com/jscs-dev/node-jscs/issues/561
|
||||
// @TODO(hswolff): remove this once JSCS supports ES6.
|
||||
delete jscsConfig.client;
|
||||
|
||||
return jscsConfig;
|
||||
})(),
|
||||
|
||||
|
@ -12,7 +12,7 @@ var ApplicationAdapter = DS.RESTAdapter.extend({
|
||||
delete query.id;
|
||||
}
|
||||
|
||||
return this.ajax(this.buildURL(type.typeKey, id), 'GET', { data: query });
|
||||
return this.ajax(this.buildURL(type.typeKey, id), 'GET', {data: query});
|
||||
},
|
||||
|
||||
buildURL: function (type, id) {
|
||||
|
@ -36,7 +36,6 @@ var EmbeddedRelationAdapter = ApplicationAdapter.extend({
|
||||
if (meta.kind === 'hasMany' &&
|
||||
Object.prototype.hasOwnProperty.call(meta.options, 'embedded') &&
|
||||
meta.options.embedded === 'always') {
|
||||
|
||||
toInclude.push(name);
|
||||
}
|
||||
});
|
||||
@ -46,12 +45,11 @@ var EmbeddedRelationAdapter = ApplicationAdapter.extend({
|
||||
if (typeof options === 'string' || typeof options === 'number') {
|
||||
query.id = options;
|
||||
query.include = toInclude.join(',');
|
||||
}
|
||||
// If this is a find all (no existing query object) build one and attach
|
||||
// the includes.
|
||||
// If this is a find with an existing query object then merge the includes
|
||||
// into the existing object. Existing properties and includes are preserved.
|
||||
else if (typeof options === 'object' || Ember.isNone(options)) {
|
||||
} else if (typeof options === 'object' || Ember.isNone(options)) {
|
||||
// If this is a find all (no existing query object) build one and attach
|
||||
// the includes.
|
||||
// If this is a find with an existing query object then merge the includes
|
||||
// into the existing object. Existing properties and includes are preserved.
|
||||
query = options || query;
|
||||
toInclude = toInclude.concat(query.include ? query.include.split(',') : []);
|
||||
|
||||
|
@ -13,7 +13,7 @@ var PostAdapter = EmbeddedRelationAdapter.extend({
|
||||
// an array with a post object like the API expects
|
||||
serializer.serializeIntoHash(data, type, record);
|
||||
|
||||
return this.ajax(url, 'POST', { data: data });
|
||||
return this.ajax(url, 'POST', {data: data});
|
||||
},
|
||||
|
||||
updateRecord: function (store, type, record) {
|
||||
@ -30,7 +30,7 @@ var PostAdapter = EmbeddedRelationAdapter.extend({
|
||||
serializer.serializeIntoHash(data, type, record);
|
||||
|
||||
// use the ApplicationAdapter's buildURL method
|
||||
return this.ajax(url, 'PUT', { data: data });
|
||||
return this.ajax(url, 'PUT', {data: data});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -14,7 +14,7 @@ var SettingAdapter = ApplicationAdapter.extend({
|
||||
|
||||
// use the ApplicationAdapter's buildURL method but do not
|
||||
// pass in an id.
|
||||
return this.ajax(this.buildURL(type.typeKey), 'PUT', { data: data });
|
||||
return this.ajax(this.buildURL(type.typeKey), 'PUT', {data: data});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -14,7 +14,7 @@ var UserAdapter = EmbeddedRelationAdapter.extend({
|
||||
serializer.serializeIntoHash(data, type, record);
|
||||
|
||||
// Use the url from the ApplicationAdapter's buildURL method
|
||||
return this.ajax(url, 'POST', { data: data });
|
||||
return this.ajax(url, 'POST', {data: data});
|
||||
},
|
||||
|
||||
updateRecord: function (store, type, record) {
|
||||
@ -31,7 +31,7 @@ var UserAdapter = EmbeddedRelationAdapter.extend({
|
||||
serializer.serializeIntoHash(data, type, record);
|
||||
|
||||
// Use the url from the ApplicationAdapter's buildURL method
|
||||
return this.ajax(url, 'PUT', { data: data });
|
||||
return this.ajax(url, 'PUT', {data: data});
|
||||
},
|
||||
|
||||
find: function (store, type, id) {
|
||||
|
@ -5,11 +5,12 @@ var createTouchEditor = function createTouchEditor() {
|
||||
TouchEditor = function (el, options) {
|
||||
/*jshint unused:false*/
|
||||
this.textarea = el;
|
||||
this.win = { document : this.textarea };
|
||||
this.win = {document: this.textarea};
|
||||
this.ready = true;
|
||||
this.wrapping = document.createElement('div');
|
||||
|
||||
var textareaParent = this.textarea.parentNode;
|
||||
|
||||
this.wrapping.appendChild(this.textarea);
|
||||
textareaParent.appendChild(this.wrapping);
|
||||
|
||||
@ -33,14 +34,14 @@ var createTouchEditor = function createTouchEditor() {
|
||||
},
|
||||
focus: noop,
|
||||
getCursor: function () {
|
||||
return { line: 0, ch: 0 };
|
||||
return {line: 0, ch: 0};
|
||||
},
|
||||
setCursor: noop,
|
||||
currentLine: function () {
|
||||
return 0;
|
||||
},
|
||||
cursorPosition: function () {
|
||||
return { character: 0 };
|
||||
return {character: 0};
|
||||
},
|
||||
addMarkdown: noop,
|
||||
nthLine: noop,
|
||||
|
@ -4,18 +4,17 @@ var UploadUi,
|
||||
upload,
|
||||
Ghost = ghostPaths();
|
||||
|
||||
|
||||
UploadUi = function ($dropzone, settings) {
|
||||
var $url = '<div class="js-url"><input class="url js-upload-url" type="url" placeholder="http://"/></div>',
|
||||
$cancel = '<a class="image-cancel js-cancel" title="Delete"><span class="hidden">Delete</span></a>',
|
||||
$progress = $('<div />', {
|
||||
'class' : 'js-upload-progress progress progress-success active',
|
||||
'role': 'progressbar',
|
||||
class: 'js-upload-progress progress progress-success active',
|
||||
role: 'progressbar',
|
||||
'aria-valuemin': '0',
|
||||
'aria-valuemax': '100'
|
||||
}).append($('<div />', {
|
||||
'class': 'js-upload-progress-bar bar',
|
||||
'style': 'width:0%'
|
||||
class: 'js-upload-progress-bar bar',
|
||||
style: 'width:0%'
|
||||
}));
|
||||
|
||||
$.extend(this, {
|
||||
@ -23,9 +22,9 @@ UploadUi = function ($dropzone, settings) {
|
||||
var self = this;
|
||||
|
||||
function showImage(width, height) {
|
||||
$dropzone.find('img.js-upload-target').attr({'width': width, 'height': height}).css({'display': 'block'});
|
||||
$dropzone.find('img.js-upload-target').attr({width: width, height: height}).css({display: 'block'});
|
||||
$dropzone.find('.fileupload-loading').remove();
|
||||
$dropzone.css({'height': 'auto'});
|
||||
$dropzone.css({height: 'auto'});
|
||||
$dropzone.delay(250).animate({opacity: 100}, 1000, function () {
|
||||
$('.js-button-accept').prop('disabled', false);
|
||||
self.init();
|
||||
@ -45,11 +44,11 @@ UploadUi = function ($dropzone, settings) {
|
||||
|
||||
function preLoadImage() {
|
||||
var $img = $dropzone.find('img.js-upload-target')
|
||||
.attr({'src': '', 'width': 'auto', 'height': 'auto'});
|
||||
.attr({src: '', width: 'auto', height: 'auto'});
|
||||
|
||||
$progress.animate({'opacity': 0}, 250, function () {
|
||||
$progress.animate({opacity: 0}, 250, function () {
|
||||
$dropzone.find('span.media').after('<img class="fileupload-loading" src="' + Ghost.subdir + '/ghost/img/loadingcat.gif" />');
|
||||
if (!settings.editor) {$progress.find('.fileupload-loading').css({'top': '56px'}); }
|
||||
if (!settings.editor) {$progress.find('.fileupload-loading').css({top: '56px'}); }
|
||||
});
|
||||
$dropzone.trigger('uploadsuccess', [result]);
|
||||
$img.one('load', function () {
|
||||
@ -73,7 +72,7 @@ UploadUi = function ($dropzone, settings) {
|
||||
$dropzone.trigger('uploadstart', [$dropzone.attr('id')]);
|
||||
$dropzone.find('span.media, div.description, a.image-url, a.image-webcam')
|
||||
.animate({opacity: 0}, 250, function () {
|
||||
$dropzone.find('div.description').hide().css({'opacity': 100});
|
||||
$dropzone.find('div.description').hide().css({opacity: 100});
|
||||
if (settings.progressbar) {
|
||||
$dropzone.find('div.js-fail').after($progress);
|
||||
$progress.animate({opacity: 100}, 250);
|
||||
@ -85,7 +84,7 @@ UploadUi = function ($dropzone, settings) {
|
||||
progressall: function (e, data) {
|
||||
/*jshint unused:false*/
|
||||
var progress = parseInt(data.loaded / data.total * 100, 10);
|
||||
if (!settings.editor) {$progress.find('div.js-progress').css({'position': 'absolute', 'top': '40px'}); }
|
||||
if (!settings.editor) {$progress.find('div.js-progress').css({position: 'absolute', top: '40px'}); }
|
||||
if (settings.progressbar) {
|
||||
$dropzone.trigger('uploadprogress', [progress, data]);
|
||||
$progress.find('.js-upload-progress-bar').css('width', progress + '%');
|
||||
@ -134,9 +133,9 @@ UploadUi = function ($dropzone, settings) {
|
||||
if (!$dropzone.find('a.image-url')[0]) {
|
||||
$dropzone.append('<a class="image-url" title="Add image from URL"><span class="hidden">URL</span></a>');
|
||||
}
|
||||
// if (!$dropzone.find('a.image-webcam')[0]) {
|
||||
// $dropzone.append('<a class="image-webcam" title="Add image from webcam"><span class="hidden">Webcam</span></a>');
|
||||
// }
|
||||
// if (!$dropzone.find('a.image-webcam')[0]) {
|
||||
// $dropzone.append('<a class="image-webcam" title="Add image from webcam"><span class="hidden">Webcam</span></a>');
|
||||
// }
|
||||
},
|
||||
|
||||
removeExtras: function () {
|
||||
@ -145,8 +144,9 @@ UploadUi = function ($dropzone, settings) {
|
||||
|
||||
initWithDropzone: function () {
|
||||
var self = this;
|
||||
//This is the start point if no image exists
|
||||
$dropzone.find('img.js-upload-target').css({'display': 'none'});
|
||||
|
||||
// This is the start point if no image exists
|
||||
$dropzone.find('img.js-upload-target').css({display: 'none'});
|
||||
$dropzone.removeClass('pre-image-uploader image-uploader-url').addClass('image-uploader');
|
||||
this.removeExtras();
|
||||
this.buildExtras();
|
||||
@ -203,16 +203,17 @@ UploadUi = function ($dropzone, settings) {
|
||||
$dropzone.find('.js-fileupload').removeClass('right');
|
||||
self.initWithDropzone();
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
initWithImage: function () {
|
||||
var self = this;
|
||||
|
||||
// This is the start point if an image already exists
|
||||
$dropzone.removeClass('image-uploader image-uploader-url').addClass('pre-image-uploader');
|
||||
$dropzone.find('div.description').hide();
|
||||
$dropzone.append($cancel);
|
||||
$dropzone.find('.js-cancel').on('click', function () {
|
||||
$dropzone.find('img.js-upload-target').attr({'src': ''});
|
||||
$dropzone.find('img.js-upload-target').attr({src: ''});
|
||||
$dropzone.find('div.description').show();
|
||||
$dropzone.delay(2500).animate({opacity: 100}, 1000, function () {
|
||||
self.init();
|
||||
@ -240,13 +241,13 @@ UploadUi = function ($dropzone, settings) {
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
upload = function (options) {
|
||||
var settings = $.extend({
|
||||
progressbar: true,
|
||||
editor: false,
|
||||
fileStorage: true
|
||||
}, options);
|
||||
|
||||
return this.each(function () {
|
||||
var $dropzone = $(this),
|
||||
ui;
|
||||
|
@ -5,9 +5,13 @@ import mobileCodeMirror from 'ghost/utils/codemirror-mobile';
|
||||
import setScrollClassName from 'ghost/utils/set-scroll-classname';
|
||||
import codeMirrorShortcuts from 'ghost/utils/codemirror-shortcuts';
|
||||
|
||||
var onChangeHandler,
|
||||
onScrollHandler,
|
||||
Codemirror;
|
||||
|
||||
codeMirrorShortcuts.init();
|
||||
|
||||
var onChangeHandler = function (cm, changeObj) {
|
||||
onChangeHandler = function (cm, changeObj) {
|
||||
var line,
|
||||
component = cm.component;
|
||||
|
||||
@ -24,7 +28,7 @@ var onChangeHandler = function (cm, changeObj) {
|
||||
component.sendAction('typingPause');
|
||||
};
|
||||
|
||||
var onScrollHandler = function (cm) {
|
||||
onScrollHandler = function (cm) {
|
||||
var scrollInfo = cm.getScrollInfo(),
|
||||
component = cm.component;
|
||||
|
||||
@ -36,7 +40,7 @@ var onScrollHandler = function (cm) {
|
||||
}, 10);
|
||||
};
|
||||
|
||||
var Codemirror = Ember.TextArea.extend(MarkerManager, {
|
||||
Codemirror = Ember.TextArea.extend(MarkerManager, {
|
||||
focus: true,
|
||||
|
||||
setFocus: function () {
|
||||
@ -51,8 +55,9 @@ var Codemirror = Ember.TextArea.extend(MarkerManager, {
|
||||
|
||||
afterRenderEvent: function () {
|
||||
var self = this;
|
||||
function initMarkers () {
|
||||
self.initMarkers.apply(self, arguments);
|
||||
|
||||
function initMarkers() {
|
||||
self.initMarkers.apply(self, arguments);
|
||||
}
|
||||
|
||||
// replaces CodeMirror with TouchEditor only if we're on mobile
|
||||
|
@ -2,13 +2,15 @@ import DropdownMixin from 'ghost/mixins/dropdown-mixin';
|
||||
|
||||
var DropdownButton = Ember.Component.extend(DropdownMixin, {
|
||||
tagName: 'button',
|
||||
/*matches with the dropdown this button toggles*/
|
||||
|
||||
// matches with the dropdown this button toggles
|
||||
dropdownName: null,
|
||||
/*Notify dropdown service this dropdown should be toggled*/
|
||||
|
||||
// Notify dropdown service this dropdown should be toggled
|
||||
click: function (event) {
|
||||
this._super(event);
|
||||
this.get('dropdown').toggleDropdown(this.get('dropdownName'), this);
|
||||
}
|
||||
});
|
||||
|
||||
export default DropdownButton;
|
||||
export default DropdownButton;
|
||||
|
@ -4,11 +4,14 @@ var GhostDropdown = Ember.Component.extend(DropdownMixin, {
|
||||
classNames: 'ghost-dropdown',
|
||||
name: null,
|
||||
closeOnClick: false,
|
||||
//Helps track the user re-opening the menu while it's fading out.
|
||||
|
||||
// Helps track the user re-opening the menu while it's fading out.
|
||||
closing: false,
|
||||
//Helps track whether the dropdown is open or closes, or in a transition to either
|
||||
|
||||
// Helps track whether the dropdown is open or closes, or in a transition to either
|
||||
isOpen: false,
|
||||
//Managed the toggle between the fade-in and fade-out classes
|
||||
|
||||
// Managed the toggle between the fade-in and fade-out classes
|
||||
fadeIn: Ember.computed('isOpen', 'closing', function () {
|
||||
return this.get('isOpen') && !this.get('closing');
|
||||
}),
|
||||
@ -20,9 +23,12 @@ var GhostDropdown = Ember.Component.extend(DropdownMixin, {
|
||||
this.set('closing', false);
|
||||
this.set('button.isOpen', true);
|
||||
},
|
||||
|
||||
close: function () {
|
||||
var self = this;
|
||||
|
||||
this.set('closing', true);
|
||||
|
||||
if (this.get('button')) {
|
||||
this.set('button.isOpen', false);
|
||||
}
|
||||
@ -35,7 +41,8 @@ var GhostDropdown = Ember.Component.extend(DropdownMixin, {
|
||||
}
|
||||
});
|
||||
},
|
||||
//Called by the dropdown service when any dropdown button is clicked.
|
||||
|
||||
// Called by the dropdown service when any dropdown button is clicked.
|
||||
toggle: function (options) {
|
||||
var isClosing = this.get('closing'),
|
||||
isOpen = this.get('isOpen'),
|
||||
@ -56,6 +63,7 @@ var GhostDropdown = Ember.Component.extend(DropdownMixin, {
|
||||
|
||||
click: function (event) {
|
||||
this._super(event);
|
||||
|
||||
if (this.get('closeOnClick')) {
|
||||
return this.close();
|
||||
}
|
||||
@ -63,13 +71,16 @@ var GhostDropdown = Ember.Component.extend(DropdownMixin, {
|
||||
|
||||
didInsertElement: function () {
|
||||
this._super();
|
||||
|
||||
var dropdownService = this.get('dropdown');
|
||||
|
||||
dropdownService.on('close', this, this.close);
|
||||
dropdownService.on('toggle', this, this.toggle);
|
||||
},
|
||||
|
||||
willDestroyElement: function () {
|
||||
this._super();
|
||||
|
||||
var dropdownService = this.get('dropdown');
|
||||
|
||||
dropdownService.off('close', this, this.close);
|
||||
@ -77,4 +88,4 @@ var GhostDropdown = Ember.Component.extend(DropdownMixin, {
|
||||
}
|
||||
});
|
||||
|
||||
export default GhostDropdown;
|
||||
export default GhostDropdown;
|
||||
|
@ -10,7 +10,6 @@ var ModalDialog = Ember.Component.extend({
|
||||
},
|
||||
|
||||
willDestroyElement: function () {
|
||||
|
||||
this.$('.js-modal').removeClass('in');
|
||||
|
||||
this.$('.js-modal-background').removeClass('in');
|
||||
|
@ -11,8 +11,7 @@ var NotificationComponent = Ember.Component.extend({
|
||||
if (typeof message.toJSON === 'function') {
|
||||
type = message.get('type');
|
||||
dismissible = message.get('dismissible');
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
type = message.type;
|
||||
dismissible = message.dismissible;
|
||||
}
|
||||
|
@ -2,14 +2,16 @@ import DropdownButton from 'ghost/components/gh-dropdown-button';
|
||||
|
||||
var PopoverButton = DropdownButton.extend({
|
||||
click: Ember.K, // We don't want clicks on popovers, but dropdowns have them. So `K`ill them here.
|
||||
|
||||
mouseEnter: function (event) {
|
||||
this._super(event);
|
||||
this.get('dropdown').toggleDropdown(this.get('popoverName'), this);
|
||||
},
|
||||
|
||||
mouseLeave: function (event) {
|
||||
this._super(event);
|
||||
this.get('dropdown').toggleDropdown(this.get('popoverName'), this);
|
||||
}
|
||||
});
|
||||
|
||||
export default PopoverButton;
|
||||
export default PopoverButton;
|
||||
|
@ -4,4 +4,4 @@ var GhostPopover = GhostDropdown.extend({
|
||||
classNames: 'ghost-popover'
|
||||
});
|
||||
|
||||
export default GhostPopover;
|
||||
export default GhostPopover;
|
||||
|
@ -2,8 +2,9 @@ import GhostSelect from 'ghost/components/gh-select';
|
||||
|
||||
var RolesSelector = GhostSelect.extend({
|
||||
roles: Ember.computed.alias('options'),
|
||||
|
||||
options: Ember.computed(function () {
|
||||
var rolesPromise = this.store.find('role', { permissions: 'assign' });
|
||||
var rolesPromise = this.store.find('role', {permissions: 'assign'});
|
||||
|
||||
return Ember.ArrayProxy.extend(Ember.PromiseProxyMixin)
|
||||
.create({promise: rolesPromise});
|
||||
|
@ -1,17 +1,17 @@
|
||||
//GhostSelect is a solution to Ember.Select being evil and worthless.
|
||||
// GhostSelect is a solution to Ember.Select being evil and worthless.
|
||||
// (Namely, this solves problems with async data in Ember.Select)
|
||||
//Inspired by (that is, totally ripped off from) this JSBin
|
||||
//http://emberjs.jsbin.com/rwjblue/40/edit
|
||||
// Inspired by (that is, totally ripped off from) this JSBin
|
||||
// http://emberjs.jsbin.com/rwjblue/40/edit
|
||||
|
||||
//Usage:
|
||||
//Extend this component and create a template for your component.
|
||||
//Your component must define the `options` property.
|
||||
//Optionally use `initialValue` to set the object
|
||||
// Usage:
|
||||
// Extend this component and create a template for your component.
|
||||
// Your component must define the `options` property.
|
||||
// Optionally use `initialValue` to set the object
|
||||
// you want to have selected to start with.
|
||||
//Both options and initalValue are promise safe.
|
||||
//Set onChange in your template to be the name
|
||||
// Both options and initalValue are promise safe.
|
||||
// Set onChange in your template to be the name
|
||||
// of the action you want called in your
|
||||
//For an example, see gh-roles-selector
|
||||
// For an example, see gh-roles-selector
|
||||
|
||||
var GhostSelect = Ember.Component.extend({
|
||||
tagName: 'span',
|
||||
@ -26,9 +26,10 @@ var GhostSelect = Ember.Component.extend({
|
||||
resolvedOptions: null,
|
||||
resolvedInitialValue: null,
|
||||
|
||||
//Convert promises to their values
|
||||
// Convert promises to their values
|
||||
init: function () {
|
||||
var self = this;
|
||||
|
||||
this._super.apply(this, arguments);
|
||||
|
||||
Ember.RSVP.hash({
|
||||
@ -37,7 +38,7 @@ var GhostSelect = Ember.Component.extend({
|
||||
}).then(function (resolvedHash) {
|
||||
self.setProperties(resolvedHash);
|
||||
|
||||
//Run after render to ensure the <option>s have rendered
|
||||
// Run after render to ensure the <option>s have rendered
|
||||
Ember.run.schedule('afterRender', function () {
|
||||
self.setInitialValue();
|
||||
});
|
||||
@ -48,20 +49,25 @@ var GhostSelect = Ember.Component.extend({
|
||||
var initialValue = this.get('resolvedInitialValue'),
|
||||
options = this.get('resolvedOptions'),
|
||||
initialValueIndex = options.indexOf(initialValue);
|
||||
|
||||
if (initialValueIndex > -1) {
|
||||
this.$('option:eq(' + initialValueIndex + ')').prop('selected', true);
|
||||
}
|
||||
},
|
||||
//Called by DOM events, weee!
|
||||
|
||||
// Called by DOM events
|
||||
change: function () {
|
||||
this._changeSelection();
|
||||
},
|
||||
//Send value to specified action
|
||||
|
||||
// Send value to specified action
|
||||
_changeSelection: function () {
|
||||
var value = this._selectedValue();
|
||||
|
||||
Ember.set(this, 'value', value);
|
||||
this.sendAction('onChange', value);
|
||||
},
|
||||
|
||||
_selectedValue: function () {
|
||||
var selectedIndex = this.$('select')[0].selectedIndex;
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
//See gh-tabs-manager.js for use
|
||||
// See gh-tabs-manager.js for use
|
||||
var TabPane = Ember.Component.extend({
|
||||
classNameBindings: ['active'],
|
||||
|
||||
@ -6,8 +6,7 @@ var TabPane = Ember.Component.extend({
|
||||
return this.nearestWithProperty('isTabsManager');
|
||||
}),
|
||||
|
||||
tab: Ember.computed('tabsManager.tabs.[]', 'tabsManager.tabPanes.[]',
|
||||
function () {
|
||||
tab: Ember.computed('tabsManager.tabs.[]', 'tabsManager.tabPanes.[]', function () {
|
||||
var index = this.get('tabsManager.tabPanes').indexOf(this),
|
||||
tabs = this.get('tabsManager.tabs');
|
||||
|
||||
@ -20,6 +19,7 @@ var TabPane = Ember.Component.extend({
|
||||
registerWithTabs: function () {
|
||||
this.get('tabsManager').registerTabPane(this);
|
||||
}.on('didInsertElement'),
|
||||
|
||||
unregisterWithTabs: function () {
|
||||
this.get('tabsManager').unregisterTabPane(this);
|
||||
}.on('willDestroyElement')
|
||||
|
@ -1,4 +1,4 @@
|
||||
//See gh-tabs-manager.js for use
|
||||
// See gh-tabs-manager.js for use
|
||||
var Tab = Ember.Component.extend({
|
||||
tabsManager: Ember.computed(function () {
|
||||
return this.nearestWithProperty('isTabsManager');
|
||||
|
@ -32,7 +32,6 @@ the second pane within that manager.
|
||||
{{/gh-tab-pane}}
|
||||
{{/gh-tabs-manager}}
|
||||
```
|
||||
|
||||
## Options:
|
||||
|
||||
the tabs-manager will send a "selected" action whenever one of its
|
||||
@ -59,19 +58,23 @@ var TabsManager = Ember.Component.extend({
|
||||
this.sendAction('selected');
|
||||
},
|
||||
|
||||
//Used by children to find this tabsManager
|
||||
// Used by children to find this tabsManager
|
||||
isTabsManager: true,
|
||||
|
||||
// Register tabs and their panes to allow for
|
||||
// interaction between components.
|
||||
registerTab: function (tab) {
|
||||
this.get('tabs').addObject(tab);
|
||||
},
|
||||
|
||||
unregisterTab: function (tab) {
|
||||
this.get('tabs').removeObject(tab);
|
||||
},
|
||||
|
||||
registerTabPane: function (tabPane) {
|
||||
this.get('tabPanes').addObject(tabPane);
|
||||
},
|
||||
|
||||
unregisterTabPane: function (tabPane) {
|
||||
this.get('tabPanes').removeObject(tabPane);
|
||||
}
|
||||
|
@ -25,9 +25,10 @@ var PostImageUploader = Ember.Component.extend({
|
||||
|
||||
removeListeners: function () {
|
||||
var $this = this.$();
|
||||
|
||||
$this.off();
|
||||
$this.find('.js-cancel').off();
|
||||
}.on('willDestroyElement')
|
||||
});
|
||||
|
||||
export default PostImageUploader;
|
||||
export default PostImageUploader;
|
||||
|
@ -1,5 +1,7 @@
|
||||
var ApplicationController = Ember.Controller.extend({
|
||||
// jscs: disable
|
||||
hideNav: Ember.computed.match('currentPath', /(error|signin|signup|setup|forgotten|reset)/),
|
||||
// jscs: enable
|
||||
|
||||
topNotificationCount: 0,
|
||||
showGlobalMobileNav: false,
|
||||
|
@ -25,6 +25,7 @@ var DebugController = Ember.Controller.extend(Ember.Evented, {
|
||||
if (response && response.jqXHR && response.jqXHR.responseJSON && response.jqXHR.responseJSON.errors) {
|
||||
self.set('importErrors', response.jqXHR.responseJSON.errors);
|
||||
}
|
||||
|
||||
self.notifications.showError('Import Failed');
|
||||
}).finally(function () {
|
||||
self.set('uploadButtonText', 'Import');
|
||||
@ -38,7 +39,7 @@ var DebugController = Ember.Controller.extend(Ember.Evented, {
|
||||
'?access_token=' + this.get('session.access_token');
|
||||
|
||||
if (iframe.length === 0) {
|
||||
iframe = $('<iframe>', { id: 'iframeDownload' }).hide().appendTo('body');
|
||||
iframe = $('<iframe>', {id: 'iframeDownload'}).hide().appendTo('body');
|
||||
}
|
||||
|
||||
iframe.attr('src', downloadURL);
|
||||
|
@ -1,44 +1,44 @@
|
||||
/* jshint unused: false */
|
||||
import ajax from 'ghost/utils/ajax';
|
||||
import ValidationEngine from 'ghost/mixins/validation-engine';
|
||||
|
||||
var ForgottenController = Ember.Controller.extend(ValidationEngine, {
|
||||
email: '',
|
||||
submitting: false,
|
||||
|
||||
// ValidationEngine settings
|
||||
validationType: 'forgotten',
|
||||
|
||||
actions: {
|
||||
submit: function () {
|
||||
var self = this,
|
||||
data = self.getProperties('email');
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
this.validate({ format: false }).then(function () {
|
||||
ajax({
|
||||
url: self.get('ghostPaths.url').api('authentication', 'passwordreset'),
|
||||
type: 'POST',
|
||||
data: {
|
||||
passwordreset: [{
|
||||
email: data.email
|
||||
}]
|
||||
}
|
||||
}).then(function (resp) {
|
||||
self.toggleProperty('submitting');
|
||||
self.notifications.showSuccess('Please check your email for instructions.', {delayed: true});
|
||||
self.set('email', '');
|
||||
self.transitionToRoute('signin');
|
||||
}).catch(function (resp) {
|
||||
self.toggleProperty('submitting');
|
||||
self.notifications.showAPIError(resp, { defaultErrorText: 'There was a problem logging in, please try again.' });
|
||||
});
|
||||
}).catch(function (errors) {
|
||||
self.toggleProperty('submitting');
|
||||
self.notifications.showErrors(errors);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default ForgottenController;
|
||||
/* jshint unused: false */
|
||||
import ajax from 'ghost/utils/ajax';
|
||||
import ValidationEngine from 'ghost/mixins/validation-engine';
|
||||
|
||||
var ForgottenController = Ember.Controller.extend(ValidationEngine, {
|
||||
email: '',
|
||||
submitting: false,
|
||||
|
||||
// ValidationEngine settings
|
||||
validationType: 'forgotten',
|
||||
|
||||
actions: {
|
||||
submit: function () {
|
||||
var self = this,
|
||||
data = self.getProperties('email');
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
this.validate({format: false}).then(function () {
|
||||
ajax({
|
||||
url: self.get('ghostPaths.url').api('authentication', 'passwordreset'),
|
||||
type: 'POST',
|
||||
data: {
|
||||
passwordreset: [{
|
||||
email: data.email
|
||||
}]
|
||||
}
|
||||
}).then(function (resp) {
|
||||
self.toggleProperty('submitting');
|
||||
self.notifications.showSuccess('Please check your email for instructions.', {delayed: true});
|
||||
self.set('email', '');
|
||||
self.transitionToRoute('signin');
|
||||
}).catch(function (resp) {
|
||||
self.toggleProperty('submitting');
|
||||
self.notifications.showAPIError(resp, {defaultErrorText: 'There was a problem logging in, please try again.'});
|
||||
});
|
||||
}).catch(function (errors) {
|
||||
self.toggleProperty('submitting');
|
||||
self.notifications.showErrors(errors);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default ForgottenController;
|
||||
|
@ -15,7 +15,6 @@ var AuthFailedUnsavedController = Ember.Controller.extend({
|
||||
},
|
||||
|
||||
confirmReject: function () {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -10,17 +10,17 @@ var DeletePostController = Ember.Controller.extend({
|
||||
model.destroyRecord().then(function () {
|
||||
self.get('dropdown').closeDropdowns();
|
||||
self.transitionToRoute('posts.index');
|
||||
self.notifications.showSuccess('Your post has been deleted.', { delayed: true });
|
||||
self.notifications.showSuccess('Your post has been deleted.', {delayed: true});
|
||||
}, function () {
|
||||
self.notifications.showError('Your post could not be deleted. Please try again.');
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
confirmReject: function () {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
confirm: {
|
||||
accept: {
|
||||
text: 'Delete',
|
||||
|
@ -7,17 +7,17 @@ var DeleteUserController = Ember.Controller.extend({
|
||||
user.destroyRecord().then(function () {
|
||||
self.store.unloadAll('post');
|
||||
self.transitionToRoute('settings.users');
|
||||
self.notifications.showSuccess('The user has been deleted.', { delayed: true });
|
||||
self.notifications.showSuccess('The user has been deleted.', {delayed: true});
|
||||
}, function () {
|
||||
self.notifications.showError('The user could not be deleted. Please try again.');
|
||||
});
|
||||
|
||||
},
|
||||
|
||||
confirmReject: function () {
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
confirm: {
|
||||
accept: {
|
||||
text: 'Delete User',
|
||||
|
@ -1,16 +1,19 @@
|
||||
var InviteNewUserController = Ember.Controller.extend({
|
||||
//Used to set the initial value for the dropdown
|
||||
// Used to set the initial value for the dropdown
|
||||
authorRole: Ember.computed(function () {
|
||||
var self = this;
|
||||
|
||||
return this.store.find('role').then(function (roles) {
|
||||
var authorRole = roles.findBy('name', 'Author');
|
||||
//Initialize role as well.
|
||||
|
||||
// Initialize role as well.
|
||||
self.set('role', authorRole);
|
||||
self.set('authorRole', authorRole);
|
||||
|
||||
return authorRole;
|
||||
});
|
||||
}),
|
||||
|
||||
|
||||
confirm: {
|
||||
accept: {
|
||||
text: 'send invitation now'
|
||||
@ -19,7 +22,7 @@ var InviteNewUserController = Ember.Controller.extend({
|
||||
buttonClass: 'hidden'
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
actions: {
|
||||
setRole: function (role) {
|
||||
this.set('role', role);
|
||||
@ -38,13 +41,13 @@ var InviteNewUserController = Ember.Controller.extend({
|
||||
|
||||
this.store.find('user').then(function (result) {
|
||||
var invitedUser = result.findBy('email', email);
|
||||
|
||||
if (invitedUser) {
|
||||
if (invitedUser.get('status') === 'invited' || invitedUser.get('status') === 'invited-pending') {
|
||||
self.notifications.showWarn('A user with that email address was already invited.');
|
||||
} else {
|
||||
self.notifications.showWarn('A user with that email address already exists.');
|
||||
}
|
||||
|
||||
} else {
|
||||
newUser = self.store.createRecord('user', {
|
||||
email: email,
|
||||
|
@ -16,6 +16,7 @@ var LeaveEditorController = Ember.Controller.extend({
|
||||
|
||||
if (!transition || !editorController) {
|
||||
this.notifications.showError('Sorry, there was an error in the application. Please let the Ghost team know what happened.');
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -40,7 +41,6 @@ var LeaveEditorController = Ember.Controller.extend({
|
||||
},
|
||||
|
||||
confirmReject: function () {
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
|
@ -11,7 +11,7 @@ var TransferOwnerController = Ember.Controller.extend({
|
||||
type: 'PUT',
|
||||
data: {
|
||||
owner: [{
|
||||
'id': user.get('id')
|
||||
id: user.get('id')
|
||||
}]
|
||||
}
|
||||
}).then(function (response) {
|
||||
@ -49,4 +49,4 @@ var TransferOwnerController = Ember.Controller.extend({
|
||||
}
|
||||
});
|
||||
|
||||
export default TransferOwnerController;
|
||||
export default TransferOwnerController;
|
||||
|
@ -5,7 +5,7 @@ import boundOneWay from 'ghost/utils/bound-one-way';
|
||||
import isNumber from 'ghost/utils/isNumber';
|
||||
|
||||
var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
//State for if the user is viewing a tab's pane.
|
||||
// State for if the user is viewing a tab's pane.
|
||||
needs: 'application',
|
||||
|
||||
lastPromise: null,
|
||||
@ -18,8 +18,10 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
if (arguments.length > 1) {
|
||||
return value;
|
||||
}
|
||||
|
||||
return false;
|
||||
}),
|
||||
|
||||
selectedAuthor: null,
|
||||
initializeSelectedAuthor: function () {
|
||||
var self = this;
|
||||
@ -35,13 +37,15 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
selectedAuthor = this.get('selectedAuthor'),
|
||||
model = this.get('model'),
|
||||
self = this;
|
||||
//return if nothing changed
|
||||
|
||||
// return if nothing changed
|
||||
if (selectedAuthor.get('id') === author.get('id')) {
|
||||
return;
|
||||
}
|
||||
|
||||
model.set('author', selectedAuthor);
|
||||
|
||||
//if this is a new post (never been saved before), don't try to save it
|
||||
// if this is a new post (never been saved before), don't try to save it
|
||||
if (this.get('isNew')) {
|
||||
return;
|
||||
}
|
||||
@ -52,8 +56,9 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
model.rollback();
|
||||
});
|
||||
}.observes('selectedAuthor'),
|
||||
|
||||
authors: Ember.computed(function () {
|
||||
//Loaded asynchronously, so must use promise proxies.
|
||||
// Loaded asynchronously, so must use promise proxies.
|
||||
var deferred = {};
|
||||
|
||||
deferred.promise = this.store.find('user', {limit: 'all'}).then(function (users) {
|
||||
@ -71,22 +76,25 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
|
||||
publishedAtValue: Ember.computed('published_at', function () {
|
||||
var pubDate = this.get('published_at');
|
||||
|
||||
if (pubDate) {
|
||||
return formatDate(pubDate);
|
||||
}
|
||||
|
||||
return formatDate(moment());
|
||||
}),
|
||||
|
||||
slugValue: boundOneWay('slug'),
|
||||
|
||||
//Lazy load the slug generator
|
||||
// Lazy load the slug generator
|
||||
slugGenerator: Ember.computed(function () {
|
||||
return SlugGenerator.create({
|
||||
ghostPaths: this.get('ghostPaths'),
|
||||
slugType: 'post'
|
||||
});
|
||||
}),
|
||||
//Requests slug from title
|
||||
|
||||
// Requests slug from title
|
||||
generateAndSetSlug: function (destination) {
|
||||
var self = this,
|
||||
title = this.get('titleScratch'),
|
||||
@ -143,9 +151,11 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
}
|
||||
|
||||
// Strip HTML
|
||||
placeholder = $('<div />', { html: html }).text();
|
||||
placeholder = $('<div />', {html: html}).text();
|
||||
// Replace new lines and trim
|
||||
// jscs: disable
|
||||
placeholder = placeholder.replace(/\n+/g, ' ').trim();
|
||||
// jscs: enable
|
||||
}
|
||||
|
||||
if (placeholder.length > 156) {
|
||||
@ -189,7 +199,7 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
title = this.get('title'),
|
||||
slug = this.get('slug');
|
||||
|
||||
// generate a slug if a post is new and doesn't have a title yet or
|
||||
// generate a slug if a post is new and doesn't have a title yet or
|
||||
// if the title is still '(Untitled)' and the slug is unaltered.
|
||||
if ((this.get('isNew') && !title) || title === '(Untitled)' && /^untitled(-\d+){0,1}$/.test(slug)) {
|
||||
debounceId = Ember.run.debounce(this, 'generateAndSetSlug', ['slug'], 700);
|
||||
@ -202,9 +212,11 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
errors = Ember.isArray(errors) ? errors : [errors];
|
||||
this.notifications.showErrors(errors);
|
||||
},
|
||||
|
||||
showSuccess: function (message) {
|
||||
this.notifications.showSuccess(message);
|
||||
},
|
||||
|
||||
actions: {
|
||||
togglePage: function () {
|
||||
var self = this;
|
||||
@ -226,6 +238,7 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
var self = this;
|
||||
|
||||
this.toggleProperty('featured');
|
||||
|
||||
// If this is a new post. Don't save the model. Defer the save
|
||||
// to the user pressing the save button
|
||||
if (this.get('isNew')) {
|
||||
@ -237,6 +250,7 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
self.get('model').rollback();
|
||||
});
|
||||
},
|
||||
|
||||
/**
|
||||
* triggered by user manually changing slug
|
||||
*/
|
||||
@ -314,10 +328,11 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
self = this;
|
||||
|
||||
if (!userInput) {
|
||||
//Clear out the published_at field for a draft
|
||||
// Clear out the published_at field for a draft
|
||||
if (this.get('isDraft')) {
|
||||
this.set('published_at', null);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -330,9 +345,10 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
errMessage = 'Published Date cannot currently be in the future.';
|
||||
}
|
||||
|
||||
//If errors, notify and exit.
|
||||
// If errors, notify and exit.
|
||||
if (errMessage) {
|
||||
this.showErrors(errMessage);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -341,7 +357,7 @@ var PostSettingsMenuController = Ember.ObjectController.extend({
|
||||
return;
|
||||
}
|
||||
|
||||
//Validation complete
|
||||
// Validation complete
|
||||
this.set('published_at', newPublishedAt);
|
||||
|
||||
// If this is a new post. Don't save the model. Defer the save
|
||||
|
@ -1,5 +1,4 @@
|
||||
var PostTagsInputController = Ember.Controller.extend({
|
||||
|
||||
tagEnteredOrder: Ember.A(),
|
||||
|
||||
tags: Ember.computed('parentController.tags', function () {
|
||||
@ -132,7 +131,10 @@ var PostTagsInputController = Ember.Controller.extend({
|
||||
|
||||
addSelectedSuggestion: function () {
|
||||
var suggestion = this.get('selectedSuggestion');
|
||||
if (Ember.isEmpty(suggestion)) { return; }
|
||||
|
||||
if (Ember.isEmpty(suggestion)) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.send('addTag', suggestion.get('tag'));
|
||||
},
|
||||
@ -143,9 +145,9 @@ var PostTagsInputController = Ember.Controller.extend({
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
selectedSuggestion: Ember.computed('suggestions.@each.selected', function () {
|
||||
var suggestions = this.get('suggestions');
|
||||
|
||||
if (suggestions && suggestions.get('length')) {
|
||||
return suggestions.filterBy('selected').get('firstObject');
|
||||
} else {
|
||||
@ -153,7 +155,6 @@ var PostTagsInputController = Ember.Controller.extend({
|
||||
}
|
||||
}),
|
||||
|
||||
|
||||
updateSuggestionsList: function () {
|
||||
var searchTerm = this.get('newTagText'),
|
||||
matchingTags,
|
||||
@ -178,7 +179,6 @@ var PostTagsInputController = Ember.Controller.extend({
|
||||
this.set('suggestions', suggestions);
|
||||
}.observes('newTagText'),
|
||||
|
||||
|
||||
findMatchingTags: function (searchTerm) {
|
||||
var matchingTags,
|
||||
self = this,
|
||||
@ -209,7 +209,9 @@ var PostTagsInputController = Ember.Controller.extend({
|
||||
|
||||
makeSuggestionObject: function (matchingTag, _searchTerm) {
|
||||
var searchTerm = Ember.Handlebars.Utils.escapeExpression(_searchTerm),
|
||||
// jscs:disable
|
||||
regexEscapedSearchTerm = searchTerm.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'),
|
||||
// jscs:enable
|
||||
tagName = Ember.Handlebars.Utils.escapeExpression(matchingTag.get('name')),
|
||||
regex = new RegExp('(' + regexEscapedSearchTerm + ')', 'gi'),
|
||||
highlightedName,
|
||||
@ -222,8 +224,7 @@ var PostTagsInputController = Ember.Controller.extend({
|
||||
suggestion.set('highlightedName', highlightedName);
|
||||
|
||||
return suggestion;
|
||||
},
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
export default PostTagsInputController;
|
||||
|
@ -19,7 +19,6 @@ function publishedAtCompare(item1, item2) {
|
||||
return Ember.compare(published1.valueOf(), published2.valueOf());
|
||||
}
|
||||
|
||||
|
||||
var PostsController = Ember.ArrayController.extend(PaginationControllerMixin, {
|
||||
// this will cause the list to re-sort when any of these properties change on any of the models
|
||||
sortProperties: ['status', 'published_at', 'updated_at'],
|
||||
@ -68,9 +67,9 @@ var PostsController = Ember.ArrayController.extend(PaginationControllerMixin, {
|
||||
},
|
||||
|
||||
init: function () {
|
||||
//let the PaginationControllerMixin know what type of model we will be paginating
|
||||
//this is necesariy because we do not have access to the model inside the Controller::init method
|
||||
this._super({'modelType': 'post'});
|
||||
// let the PaginationControllerMixin know what type of model we will be paginating
|
||||
// this is necesariy because we do not have access to the model inside the Controller::init method
|
||||
this._super({modelType: 'post'});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -1,48 +1,52 @@
|
||||
/*global alert */
|
||||
|
||||
var AppStates = {
|
||||
var appStates,
|
||||
SettingsAppController;
|
||||
|
||||
appStates = {
|
||||
active: 'active',
|
||||
working: 'working',
|
||||
inactive: 'inactive'
|
||||
};
|
||||
|
||||
var SettingsAppController = Ember.ObjectController.extend({
|
||||
appState: AppStates.active,
|
||||
SettingsAppController = Ember.ObjectController.extend({
|
||||
appState: appStates.active,
|
||||
buttonText: '',
|
||||
|
||||
|
||||
setAppState: function () {
|
||||
this.set('appState', this.get('active') ? AppStates.active : AppStates.inactive);
|
||||
this.set('appState', this.get('active') ? appStates.active : appStates.inactive);
|
||||
}.on('init'),
|
||||
|
||||
buttonTextSetter: function () {
|
||||
switch (this.get('appState')) {
|
||||
case AppStates.active:
|
||||
case appStates.active:
|
||||
this.set('buttonText', 'Deactivate');
|
||||
break;
|
||||
case AppStates.inactive:
|
||||
case appStates.inactive:
|
||||
this.set('buttonText', 'Activate');
|
||||
break;
|
||||
case AppStates.working:
|
||||
case appStates.working:
|
||||
this.set('buttonText', 'Working');
|
||||
break;
|
||||
}
|
||||
}.observes('appState').on('init'),
|
||||
|
||||
activeClass: Ember.computed('appState', function () {
|
||||
return this.appState === AppStates.active ? true : false;
|
||||
return this.appState === appStates.active ? true : false;
|
||||
}),
|
||||
|
||||
inactiveClass: Ember.computed('appState', function () {
|
||||
return this.appState === AppStates.inactive ? true : false;
|
||||
return this.appState === appStates.inactive ? true : false;
|
||||
}),
|
||||
|
||||
actions: {
|
||||
toggleApp: function (app) {
|
||||
var self = this;
|
||||
this.set('appState', AppStates.working);
|
||||
|
||||
|
||||
this.set('appState', appStates.working);
|
||||
|
||||
app.set('active', !app.get('active'));
|
||||
|
||||
|
||||
app.save().then(function () {
|
||||
self.setAppState();
|
||||
})
|
||||
|
@ -2,9 +2,9 @@ import PaginationControllerMixin from 'ghost/mixins/pagination-controller';
|
||||
|
||||
var UsersIndexController = Ember.ArrayController.extend(PaginationControllerMixin, {
|
||||
init: function () {
|
||||
//let the PaginationControllerMixin know what type of model we will be paginating
|
||||
//this is necessary because we do not have access to the model inside the Controller::init method
|
||||
this._super({'modelType': 'user'});
|
||||
// let the PaginationControllerMixin know what type of model we will be paginating
|
||||
// this is necessary because we do not have access to the model inside the Controller::init method
|
||||
this._super({modelType: 'user'});
|
||||
},
|
||||
|
||||
users: Ember.computed.alias('model'),
|
||||
|
@ -21,9 +21,11 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
|
||||
cover: Ember.computed('user.cover', 'coverDefault', function () {
|
||||
var cover = this.get('user.cover');
|
||||
|
||||
if (Ember.isBlank(cover)) {
|
||||
cover = this.get('coverDefault');
|
||||
}
|
||||
|
||||
return 'background-image: url(' + cover + ')';
|
||||
}),
|
||||
|
||||
@ -32,7 +34,7 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
}),
|
||||
|
||||
image: Ember.computed('imageUrl', function () {
|
||||
return 'background-image: url(' + this.get('imageUrl') + ')';
|
||||
return 'background-image: url(' + this.get('imageUrl') + ')';
|
||||
}),
|
||||
|
||||
imageUrl: Ember.computed('user.image', function () {
|
||||
@ -51,7 +53,7 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
return createdAt ? createdAt.fromNow() : '';
|
||||
}),
|
||||
|
||||
//Lazy load the slug generator for slugPlaceholder
|
||||
// Lazy load the slug generator for slugPlaceholder
|
||||
slugGenerator: Ember.computed(function () {
|
||||
return SlugGenerator.create({
|
||||
ghostPaths: this.get('ghostPaths'),
|
||||
@ -63,12 +65,13 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
changeRole: function (newRole) {
|
||||
this.set('model.role', newRole);
|
||||
},
|
||||
|
||||
revoke: function () {
|
||||
var self = this,
|
||||
model = this.get('model'),
|
||||
email = this.get('email');
|
||||
|
||||
//reload the model to get the most up-to-date user information
|
||||
// reload the model to get the most up-to-date user information
|
||||
model.reload().then(function () {
|
||||
if (self.get('invited')) {
|
||||
model.destroyRecord().then(function () {
|
||||
@ -78,7 +81,7 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
self.notifications.showAPIError(error);
|
||||
});
|
||||
} else {
|
||||
//if the user is no longer marked as "invited", then show a warning and reload the route
|
||||
// if the user is no longer marked as "invited", then show a warning and reload the route
|
||||
self.get('target').send('reload');
|
||||
self.notifications.showError('This user has already accepted the invitation.', {delayed: 500});
|
||||
}
|
||||
@ -117,7 +120,7 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
}
|
||||
|
||||
promise = Ember.RSVP.resolve(afterUpdateSlug).then(function () {
|
||||
return user.save({ format: false });
|
||||
return user.save({format: false});
|
||||
}).then(function (model) {
|
||||
var currentPath,
|
||||
newPath;
|
||||
@ -133,7 +136,7 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
newPath[newPath.length - 2] = model.get('slug');
|
||||
newPath = newPath.join('/');
|
||||
|
||||
window.history.replaceState({ path: newPath }, '', newPath);
|
||||
window.history.replaceState({path: newPath}, '', newPath);
|
||||
}
|
||||
|
||||
return model;
|
||||
@ -150,12 +153,11 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
|
||||
if (user.get('isPasswordValid')) {
|
||||
user.saveNewPassword().then(function (model) {
|
||||
|
||||
// Clear properties from view
|
||||
user.setProperties({
|
||||
'password': '',
|
||||
'newPassword': '',
|
||||
'ne2Password': ''
|
||||
password: '',
|
||||
newPassword: '',
|
||||
ne2Password: ''
|
||||
});
|
||||
|
||||
self.notifications.showSuccess('Password updated.');
|
||||
@ -189,7 +191,6 @@ var SettingsUserController = Ember.ObjectController.extend({
|
||||
}
|
||||
|
||||
return self.get('slugGenerator').generateSlug(newSlug).then(function (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) {
|
||||
|
@ -19,7 +19,7 @@ var SetupController = Ember.ObjectController.extend(ValidationEngine, {
|
||||
self.notifications.closePassive();
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
this.validate({ format: false }).then(function () {
|
||||
this.validate({format: false}).then(function () {
|
||||
ajax({
|
||||
url: self.get('ghostPaths.url').api('authentication', 'setup'),
|
||||
type: 'POST',
|
||||
|
@ -15,7 +15,7 @@ var SigninController = Ember.Controller.extend(SimpleAuth.AuthenticationControll
|
||||
validateAndAuthenticate: function () {
|
||||
var self = this;
|
||||
|
||||
this.validate({ format: false }).then(function () {
|
||||
this.validate({format: false}).then(function () {
|
||||
self.notifications.closePassive();
|
||||
self.send('authenticate');
|
||||
}).catch(function (errors) {
|
||||
|
@ -15,7 +15,7 @@ var SignupController = Ember.ObjectController.extend(ValidationEngine, {
|
||||
self.notifications.closePassive();
|
||||
|
||||
this.toggleProperty('submitting');
|
||||
this.validate({ format: false }).then(function () {
|
||||
this.validate({format: false}).then(function () {
|
||||
ajax({
|
||||
url: self.get('ghostPaths.url').api('authentication', 'invitation'),
|
||||
type: 'POST',
|
||||
|
@ -1,6 +1,5 @@
|
||||
var blogUrl = Ember.Handlebars.makeBoundHelper(function () {
|
||||
|
||||
return new Ember.Handlebars.SafeString(this.get('config.blogUrl'));
|
||||
});
|
||||
|
||||
export default blogUrl;
|
||||
export default blogUrl;
|
||||
|
@ -3,6 +3,7 @@ var countCharacters = Ember.Handlebars.makeBoundHelper(function (content) {
|
||||
length = content ? content.length : 0;
|
||||
|
||||
el.className = 'word-count';
|
||||
|
||||
if (length > 180) {
|
||||
el.style.color = '#E25440';
|
||||
} else {
|
||||
@ -14,4 +15,4 @@ var countCharacters = Ember.Handlebars.makeBoundHelper(function (content) {
|
||||
return new Ember.Handlebars.SafeString(el.outerHTML);
|
||||
});
|
||||
|
||||
export default countCharacters;
|
||||
export default countCharacters;
|
||||
|
@ -3,6 +3,7 @@ var countDownCharacters = Ember.Handlebars.makeBoundHelper(function (content, ma
|
||||
length = content ? content.length : 0;
|
||||
|
||||
el.className = 'word-count';
|
||||
|
||||
if (length > maxCharacters) {
|
||||
el.style.color = '#E25440';
|
||||
} else {
|
||||
@ -14,4 +15,4 @@ var countDownCharacters = Ember.Handlebars.makeBoundHelper(function (content, ma
|
||||
return new Ember.Handlebars.SafeString(el.outerHTML);
|
||||
});
|
||||
|
||||
export default countDownCharacters;
|
||||
export default countDownCharacters;
|
||||
|
@ -6,7 +6,8 @@ var countWords = Ember.Handlebars.makeBoundHelper(function (markdown) {
|
||||
}
|
||||
|
||||
var count = counter(markdown || '');
|
||||
|
||||
return count + (count === 1 ? ' word' : ' words');
|
||||
});
|
||||
|
||||
export default countWords;
|
||||
export default countWords;
|
||||
|
@ -5,14 +5,19 @@ var formatHTML = Ember.Handlebars.makeBoundHelper(function (html) {
|
||||
var escapedhtml = html || '';
|
||||
|
||||
// replace script and iFrame
|
||||
// jscs:disable
|
||||
escapedhtml = escapedhtml.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
||||
'<pre class="js-embed-placeholder">Embedded JavaScript</pre>');
|
||||
escapedhtml = escapedhtml.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,
|
||||
'<pre class="iframe-embed-placeholder">Embedded iFrame</pre>');
|
||||
// jscs:enable
|
||||
|
||||
// sanitize HTML
|
||||
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
|
||||
escapedhtml = html_sanitize(escapedhtml, cajaSanitizers.url, cajaSanitizers.id);
|
||||
// jscs:enable requireCamelCaseOrUpperCaseIdentifiers
|
||||
|
||||
return new Handlebars.SafeString(escapedhtml);
|
||||
});
|
||||
|
||||
export default formatHTML;
|
||||
export default formatHTML;
|
||||
|
@ -1,23 +1,31 @@
|
||||
/* global Showdown, Handlebars, html_sanitize*/
|
||||
import cajaSanitizers from 'ghost/utils/caja-sanitizers';
|
||||
|
||||
var showdown = new Showdown.converter({extensions: ['ghostimagepreview', 'ghostgfm']});
|
||||
var showdown,
|
||||
formatMarkdown;
|
||||
|
||||
var formatMarkdown = Ember.Handlebars.makeBoundHelper(function (markdown) {
|
||||
showdown = new Showdown.converter({extensions: ['ghostimagepreview', 'ghostgfm']});
|
||||
|
||||
formatMarkdown = Ember.Handlebars.makeBoundHelper(function (markdown) {
|
||||
var escapedhtml = '';
|
||||
|
||||
// convert markdown to HTML
|
||||
escapedhtml = showdown.makeHtml(markdown || '');
|
||||
|
||||
// replace script and iFrame
|
||||
// jscs:disable
|
||||
escapedhtml = escapedhtml.replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi,
|
||||
'<pre class="js-embed-placeholder">Embedded JavaScript</pre>');
|
||||
escapedhtml = escapedhtml.replace(/<iframe\b[^<]*(?:(?!<\/iframe>)<[^<]*)*<\/iframe>/gi,
|
||||
'<pre class="iframe-embed-placeholder">Embedded iFrame</pre>');
|
||||
// jscs:enable
|
||||
|
||||
// sanitize html
|
||||
// jscs:disable requireCamelCaseOrUpperCaseIdentifiers
|
||||
escapedhtml = html_sanitize(escapedhtml, cajaSanitizers.url, cajaSanitizers.id);
|
||||
// jscs:enable requireCamelCaseOrUpperCaseIdentifiers
|
||||
|
||||
return new Handlebars.SafeString(escapedhtml);
|
||||
});
|
||||
|
||||
export default formatMarkdown;
|
||||
export default formatMarkdown;
|
||||
|
@ -6,4 +6,4 @@ var formatTimeago = Ember.Handlebars.makeBoundHelper(function (timeago) {
|
||||
// https://github.com/manuelmitasch/ghost-admin-ember-demo/commit/fba3ab0a59238290c85d4fa0d7c6ed1be2a8a82e#commitcomment-5396524
|
||||
});
|
||||
|
||||
export default formatTimeago;
|
||||
export default formatTimeago;
|
||||
|
@ -6,8 +6,7 @@
|
||||
// {{gh-path 'admin' '/assets/hi.png'}} for resolved url (/myblog/ghost/assets/hi.png)
|
||||
import ghostPaths from 'ghost/utils/ghost-paths';
|
||||
|
||||
export default function (path, url) {
|
||||
|
||||
function ghostPathsHelper(path, url) {
|
||||
var base;
|
||||
|
||||
switch (path.toString()) {
|
||||
@ -30,5 +29,6 @@ export default function (path, url) {
|
||||
}
|
||||
|
||||
return new Ember.Handlebars.SafeString(base);
|
||||
}
|
||||
|
||||
}
|
||||
export default ghostPathsHelper;
|
||||
|
@ -1,25 +1,30 @@
|
||||
import ghostPaths from 'ghost/utils/ghost-paths';
|
||||
|
||||
var Ghost = ghostPaths();
|
||||
var Ghost,
|
||||
AuthenticationInitializer;
|
||||
|
||||
var AuthenticationInitializer = {
|
||||
Ghost = ghostPaths();
|
||||
|
||||
AuthenticationInitializer = {
|
||||
name: 'authentication',
|
||||
before: 'simple-auth',
|
||||
after: 'registerTrailingLocationHistory',
|
||||
|
||||
initialize: function (container) {
|
||||
window.ENV = window.ENV || {};
|
||||
|
||||
window.ENV['simple-auth'] = {
|
||||
authenticationRoute: 'signin',
|
||||
routeAfterAuthentication: 'content',
|
||||
authorizer: 'simple-auth-authorizer:oauth2-bearer'
|
||||
};
|
||||
|
||||
SimpleAuth.Session.reopen({
|
||||
user: Ember.computed(function () {
|
||||
return container.lookup('store:main').find('user', 'me');
|
||||
})
|
||||
});
|
||||
|
||||
SimpleAuth.Authenticators.OAuth2.reopen({
|
||||
serverTokenEndpoint: Ghost.apiRoot + '/authentication/token',
|
||||
serverTokenRevocationEndpoint: Ghost.apiRoot + '/authentication/revoke',
|
||||
@ -29,6 +34,7 @@ var AuthenticationInitializer = {
|
||||
return this._super(url, data);
|
||||
}
|
||||
});
|
||||
|
||||
SimpleAuth.Stores.LocalStorage.reopen({
|
||||
key: 'ghost' + (Ghost.subdir.indexOf('/') === 0 ? '-' + Ghost.subdir.substr(1) : '') + ':session'
|
||||
});
|
||||
|
@ -20,4 +20,4 @@ var dropdownInitializer = {
|
||||
}
|
||||
};
|
||||
|
||||
export default dropdownInitializer;
|
||||
export default dropdownInitializer;
|
||||
|
@ -5,7 +5,7 @@ var ghostPathsInitializer = {
|
||||
after: 'store',
|
||||
|
||||
initialize: function (container, application) {
|
||||
application.register('ghost:paths', ghostPaths(), { instantiate: false });
|
||||
application.register('ghost:paths', ghostPaths(), {instantiate: false});
|
||||
|
||||
application.inject('route', 'ghostPaths', 'ghost:paths');
|
||||
application.inject('model', 'ghostPaths', 'ghost:paths');
|
||||
|
@ -1,7 +1,7 @@
|
||||
//Used to surgically insert the store into things that wouldn't normally have them.
|
||||
var StoreInjector = {
|
||||
name: 'store-injector',
|
||||
after: 'store',
|
||||
|
||||
initialize: function (container, application) {
|
||||
application.inject('component:gh-role-selector', 'store', 'store:main');
|
||||
}
|
||||
|
@ -1,12 +1,17 @@
|
||||
/*global Ember */
|
||||
|
||||
var trailingHistory = Ember.HistoryLocation.extend({
|
||||
var trailingHistory,
|
||||
registerTrailingLocationHistory;
|
||||
|
||||
trailingHistory = Ember.HistoryLocation.extend({
|
||||
formatURL: function () {
|
||||
// jscs: disable
|
||||
return this._super.apply(this, arguments).replace(/\/?$/, '/');
|
||||
// jscs: enable
|
||||
}
|
||||
});
|
||||
|
||||
var registerTrailingLocationHistory = {
|
||||
registerTrailingLocationHistory = {
|
||||
name: 'registerTrailingLocationHistory',
|
||||
|
||||
initialize: function (container, application) {
|
||||
@ -14,4 +19,4 @@ var registerTrailingLocationHistory = {
|
||||
}
|
||||
};
|
||||
|
||||
export default registerTrailingLocationHistory;
|
||||
export default registerTrailingLocationHistory;
|
||||
|
@ -1,38 +1,46 @@
|
||||
/*
|
||||
Code modified from Addepar/ember-widgets
|
||||
https://github.com/Addepar/ember-widgets/blob/master/src/mixins.coffee#L39
|
||||
*/
|
||||
|
||||
// Code modified from Addepar/ember-widgets
|
||||
// https://github.com/Addepar/ember-widgets/blob/master/src/mixins.coffee#L39
|
||||
|
||||
var BodyEventListener = Ember.Mixin.create({
|
||||
bodyElementSelector: 'html',
|
||||
bodyClick: Ember.K,
|
||||
|
||||
init: function () {
|
||||
this._super();
|
||||
|
||||
return Ember.run.next(this, this._setupDocumentHandlers);
|
||||
},
|
||||
|
||||
willDestroy: function () {
|
||||
this._super();
|
||||
|
||||
return this._removeDocumentHandlers();
|
||||
},
|
||||
|
||||
_setupDocumentHandlers: function () {
|
||||
if (this._clickHandler) {
|
||||
return;
|
||||
}
|
||||
|
||||
var self = this;
|
||||
|
||||
this._clickHandler = function () {
|
||||
return self.bodyClick();
|
||||
};
|
||||
|
||||
return $(this.get('bodyElementSelector')).on('click', this._clickHandler);
|
||||
},
|
||||
|
||||
_removeDocumentHandlers: function () {
|
||||
$(this.get('bodyElementSelector')).off('click', this._clickHandler);
|
||||
this._clickHandler = null;
|
||||
},
|
||||
/*
|
||||
http://stackoverflow.com/questions/152975/how-to-detect-a-click-outside-an-element
|
||||
*/
|
||||
|
||||
// http://stackoverflow.com/questions/152975/how-to-detect-a-click-outside-an-element
|
||||
click: function (event) {
|
||||
return event.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
export default BodyEventListener;
|
||||
export default BodyEventListener;
|
||||
|
@ -1,31 +1,31 @@
|
||||
var CurrentUserSettings = Ember.Mixin.create({
|
||||
currentUser: function () {
|
||||
return this.store.find('user', 'me');
|
||||
},
|
||||
currentUser: function () {
|
||||
return this.store.find('user', 'me');
|
||||
},
|
||||
|
||||
transitionAuthor: function () {
|
||||
var self = this;
|
||||
transitionAuthor: function () {
|
||||
var self = this;
|
||||
|
||||
return function (user) {
|
||||
if (user.get('isAuthor')) {
|
||||
return self.transitionTo('settings.users.user', user);
|
||||
}
|
||||
return function (user) {
|
||||
if (user.get('isAuthor')) {
|
||||
return self.transitionTo('settings.users.user', user);
|
||||
}
|
||||
|
||||
return user;
|
||||
};
|
||||
},
|
||||
return user;
|
||||
};
|
||||
},
|
||||
|
||||
transitionEditor: function () {
|
||||
var self = this;
|
||||
transitionEditor: function () {
|
||||
var self = this;
|
||||
|
||||
return function (user) {
|
||||
if (user.get('isEditor')) {
|
||||
return self.transitionTo('settings.users');
|
||||
}
|
||||
return function (user) {
|
||||
if (user.get('isEditor')) {
|
||||
return self.transitionTo('settings.users');
|
||||
}
|
||||
|
||||
return user;
|
||||
};
|
||||
}
|
||||
return user;
|
||||
};
|
||||
}
|
||||
});
|
||||
|
||||
export default CurrentUserSettings;
|
||||
export default CurrentUserSettings;
|
||||
|
@ -4,10 +4,12 @@
|
||||
var DropdownMixin = Ember.Mixin.create(Ember.Evented, {
|
||||
classNameBindings: ['isOpen:open:closed'],
|
||||
isOpen: false,
|
||||
|
||||
click: function (event) {
|
||||
this._super(event);
|
||||
|
||||
return event.stopPropagation();
|
||||
}
|
||||
});
|
||||
|
||||
export default DropdownMixin;
|
||||
export default DropdownMixin;
|
||||
|
@ -3,15 +3,18 @@ import MarkerManager from 'ghost/mixins/marker-manager';
|
||||
import PostModel from 'ghost/models/post';
|
||||
import boundOneWay from 'ghost/utils/bound-one-way';
|
||||
|
||||
var watchedProps,
|
||||
EditorControllerMixin;
|
||||
|
||||
// this array will hold properties we need to watch
|
||||
// to know if the model has been changed (`controller.isDirty`)
|
||||
var watchedProps = ['scratch', 'titleScratch', 'model.isDirty', 'tags.[]'];
|
||||
watchedProps = ['scratch', 'titleScratch', 'model.isDirty', 'tags.[]'];
|
||||
|
||||
PostModel.eachAttribute(function (name) {
|
||||
watchedProps.push('model.' + name);
|
||||
});
|
||||
|
||||
var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
needs: ['post-tags-input', 'post-settings-menu'],
|
||||
|
||||
init: function () {
|
||||
@ -23,6 +26,7 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
return self.get('isDirty') ? self.unloadDirtyMessage() : null;
|
||||
};
|
||||
},
|
||||
|
||||
/**
|
||||
* By default, a post will not change its publish state.
|
||||
* Only with a user-set value (via setSaveType action)
|
||||
@ -80,7 +84,6 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
// it's ok to set isDirty to false
|
||||
if (this.get('titleScratch') === model.get('title') &&
|
||||
this.get('scratch') === model.get('markdown')) {
|
||||
|
||||
this.set('isDirty', false);
|
||||
}
|
||||
},
|
||||
@ -141,8 +144,8 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
'==============================';
|
||||
},
|
||||
|
||||
//TODO: This has to be moved to the I18n localization file.
|
||||
//This structure is supposed to be close to the i18n-localization which will be used soon.
|
||||
// TODO: This has to be moved to the I18n localization file.
|
||||
// This structure is supposed to be close to the i18n-localization which will be used soon.
|
||||
messageMap: {
|
||||
errors: {
|
||||
post: {
|
||||
@ -175,7 +178,7 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
showSaveNotification: function (prevStatus, status, delay) {
|
||||
var message = this.messageMap.success.post[prevStatus][status];
|
||||
|
||||
this.notifications.showSuccess(message, { delayed: delay });
|
||||
this.notifications.showSuccess(message, {delayed: delay});
|
||||
},
|
||||
|
||||
showErrorNotification: function (prevStatus, status, errors, delay) {
|
||||
@ -183,7 +186,7 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
|
||||
message += '<br />' + errors[0].message;
|
||||
|
||||
this.notifications.showError(message, { delayed: delay });
|
||||
this.notifications.showError(message, {delayed: delay});
|
||||
},
|
||||
|
||||
shouldFocusTitle: Ember.computed.alias('model.isNew'),
|
||||
@ -201,7 +204,7 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
|
||||
options = options || {};
|
||||
|
||||
if(autoSaveId) {
|
||||
if (autoSaveId) {
|
||||
Ember.run.cancel(autoSaveId);
|
||||
this.set('autoSaveId', null);
|
||||
}
|
||||
@ -236,12 +239,14 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
if (!options.silent) {
|
||||
self.showSaveNotification(prevStatus, model.get('status'), isNew ? true : false);
|
||||
}
|
||||
|
||||
return model;
|
||||
});
|
||||
}).catch(function (errors) {
|
||||
if (!options.silent) {
|
||||
self.showErrorNotification(prevStatus, self.get('status'), errors);
|
||||
}
|
||||
|
||||
self.set('status', prevStatus);
|
||||
|
||||
return Ember.RSVP.reject(errors);
|
||||
@ -283,11 +288,13 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
|
||||
// Match the uploaded file to a line in the editor, and update that line with a path reference
|
||||
// ensuring that everything ends up in the correct place and format.
|
||||
handleImgUpload: function (e, result_src) {
|
||||
handleImgUpload: function (e, resultSrc) {
|
||||
var editor = this.get('codemirror'),
|
||||
line = this.findLine(Ember.$(e.currentTarget).attr('id')),
|
||||
lineNumber = editor.getLineNumber(line),
|
||||
// jscs:disable
|
||||
match = line.text.match(/\([^\n]*\)?/),
|
||||
// jscs:enable
|
||||
replacement = '(http://)';
|
||||
|
||||
if (match) {
|
||||
@ -297,7 +304,9 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
{line: lineNumber, ch: match.index + match[0].length - 1}
|
||||
);
|
||||
} else {
|
||||
// jscs:disable
|
||||
match = line.text.match(/\]/);
|
||||
// jscs:enable
|
||||
if (match) {
|
||||
editor.replaceRange(
|
||||
replacement,
|
||||
@ -306,11 +315,12 @@ var EditorControllerMixin = Ember.Mixin.create(MarkerManager, {
|
||||
);
|
||||
editor.setSelection(
|
||||
{line: lineNumber, ch: match.index + 2},
|
||||
{line: lineNumber, ch: match.index + replacement.length }
|
||||
{line: lineNumber, ch: match.index + replacement.length}
|
||||
);
|
||||
}
|
||||
}
|
||||
editor.replaceSelection(result_src);
|
||||
|
||||
editor.replaceSelection(resultSrc);
|
||||
},
|
||||
|
||||
togglePreview: function (preview) {
|
||||
|
@ -4,20 +4,23 @@ import loadingIndicator from 'ghost/mixins/loading-indicator';
|
||||
import editorShortcuts from 'ghost/utils/editor-shortcuts';
|
||||
|
||||
var EditorRouteBase = Ember.Mixin.create(styleBody, ShortcutsRoute, loadingIndicator, {
|
||||
|
||||
actions: {
|
||||
save: function () {
|
||||
this.get('controller').send('save');
|
||||
},
|
||||
|
||||
publish: function () {
|
||||
var controller = this.get('controller');
|
||||
|
||||
controller.send('setSaveType', 'publish');
|
||||
controller.send('save');
|
||||
},
|
||||
|
||||
toggleZenMode: function () {
|
||||
Ember.$('body').toggleClass('zen');
|
||||
},
|
||||
//The actual functionality is implemented in utils/codemirror-shortcuts
|
||||
|
||||
// The actual functionality is implemented in utils/codemirror-shortcuts
|
||||
codeMirrorShortcut: function (options) {
|
||||
this.get('controller.codemirror').shortcut(options.type);
|
||||
}
|
||||
|
@ -1,10 +1,14 @@
|
||||
// mixin used for routes to display a loading indicator when there is network activity
|
||||
var loaderOptions = {
|
||||
'showSpinner': false
|
||||
var loaderOptions,
|
||||
loadingIndicator;
|
||||
|
||||
loaderOptions = {
|
||||
showSpinner: false
|
||||
};
|
||||
|
||||
NProgress.configure(loaderOptions);
|
||||
|
||||
var loadingIndicator = Ember.Mixin.create({
|
||||
loadingIndicator = Ember.Mixin.create({
|
||||
actions: {
|
||||
|
||||
loading: function () {
|
||||
@ -12,14 +16,16 @@ var loadingIndicator = Ember.Mixin.create({
|
||||
this.router.one('didTransition', function () {
|
||||
NProgress.done();
|
||||
});
|
||||
|
||||
return true;
|
||||
},
|
||||
|
||||
error: function () {
|
||||
NProgress.done();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default loadingIndicator;
|
||||
export default loadingIndicator;
|
||||
|
@ -1,6 +1,8 @@
|
||||
var MarkerManager = Ember.Mixin.create({
|
||||
// jscs:disable
|
||||
imageMarkdownRegex: /^(?:\{<(.*?)>\})?!(?:\[([^\n\]]*)\])(?:\(([^\n\]]*)\))?$/gim,
|
||||
markerRegex: /\{<([\w\W]*?)>\}/,
|
||||
// jscs:enable
|
||||
|
||||
uploadId: 1,
|
||||
|
||||
@ -161,9 +163,12 @@ var MarkerManager = Ember.Mixin.create({
|
||||
stripMarkerFromLine: function (line) {
|
||||
var editor = this.get('codemirror'),
|
||||
ln = editor.getLineNumber(line),
|
||||
markerRegex = /\{<([\w\W]*?)>\}/,
|
||||
markerText = line.text.match(markerRegex);
|
||||
|
||||
// jscs:disable
|
||||
markerRegex = /\{<([\w\W]*?)>\}/,
|
||||
// jscs:enable
|
||||
|
||||
markerText = line.text.match(markerRegex);
|
||||
|
||||
if (markerText) {
|
||||
editor.replaceRange(
|
||||
@ -202,13 +207,13 @@ var MarkerManager = Ember.Mixin.create({
|
||||
},
|
||||
|
||||
// Find the line with the marker which matches
|
||||
findLine: function (result_id) {
|
||||
findLine: function (resultId) {
|
||||
var editor = this.get('codemirror'),
|
||||
markers = this.get('markers');
|
||||
|
||||
// try to find the right line to replace
|
||||
if (markers.hasOwnProperty(result_id) && markers[result_id].find()) {
|
||||
return editor.getLineHandle(markers[result_id].find().from.line);
|
||||
if (markers.hasOwnProperty(resultId) && markers[resultId].find()) {
|
||||
return editor.getLineHandle(markers[resultId].find().from.line);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -3,16 +3,19 @@ var NProgressSaveMixin = Ember.Mixin.create({
|
||||
if (options && options.disableNProgress) {
|
||||
return this._super(options);
|
||||
}
|
||||
|
||||
|
||||
NProgress.start();
|
||||
|
||||
return this._super(options).then(function (value) {
|
||||
NProgress.done();
|
||||
|
||||
return value;
|
||||
}).catch(function (error) {
|
||||
NProgress.done();
|
||||
|
||||
return Ember.RSVP.reject(error);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
export default NProgressSaveMixin;
|
||||
export default NProgressSaveMixin;
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { getRequestErrorMessage } from 'ghost/utils/ajax';
|
||||
|
||||
var PaginationControllerMixin = Ember.Mixin.create({
|
||||
|
||||
// set from PaginationRouteMixin
|
||||
paginationSettings: null,
|
||||
|
||||
@ -13,7 +12,7 @@ var PaginationControllerMixin = Ember.Mixin.create({
|
||||
|
||||
/**
|
||||
*
|
||||
* @param options: {
|
||||
* @param {object} options: {
|
||||
* modelType: <String> name of the model that will be paginated
|
||||
* }
|
||||
*/
|
||||
@ -21,10 +20,10 @@ var PaginationControllerMixin = Ember.Mixin.create({
|
||||
this._super();
|
||||
|
||||
var metadata = this.store.metadataFor(options.modelType);
|
||||
|
||||
this.set('nextPage', metadata.pagination.next);
|
||||
},
|
||||
|
||||
|
||||
/**
|
||||
* Takes an ajax response, concatenates any error messages, then generates an error notification.
|
||||
* @param {jqXHR} response The jQuery ajax reponse object.
|
||||
@ -49,7 +48,6 @@ var PaginationControllerMixin = Ember.Mixin.create({
|
||||
* @return
|
||||
*/
|
||||
loadNextPage: function () {
|
||||
|
||||
var self = this,
|
||||
store = this.get('store'),
|
||||
recordType = this.get('model').get('type'),
|
||||
@ -59,6 +57,7 @@ var PaginationControllerMixin = Ember.Mixin.create({
|
||||
if (nextPage) {
|
||||
this.set('isLoading', true);
|
||||
this.set('paginationSettings.page', nextPage);
|
||||
|
||||
store.find(recordType, paginationSettings).then(function () {
|
||||
var metadata = store.metadataFor(recordType);
|
||||
|
||||
@ -70,7 +69,6 @@ var PaginationControllerMixin = Ember.Mixin.create({
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
export default PaginationControllerMixin;
|
||||
|
@ -1,16 +1,17 @@
|
||||
var defaultPaginationSettings = {
|
||||
var defaultPaginationSettings,
|
||||
PaginationRoute;
|
||||
|
||||
defaultPaginationSettings = {
|
||||
page: 1,
|
||||
limit: 15
|
||||
};
|
||||
|
||||
var PaginationRoute = Ember.Mixin.create({
|
||||
|
||||
PaginationRoute = Ember.Mixin.create({
|
||||
/**
|
||||
* Sets up pagination details
|
||||
* @param {settings}: object that specifies additional pagination details
|
||||
* @param {object} settings specifies additional pagination details
|
||||
*/
|
||||
setupPagination: function (settings) {
|
||||
|
||||
settings = settings || {};
|
||||
for (var key in defaultPaginationSettings) {
|
||||
if (defaultPaginationSettings.hasOwnProperty(key)) {
|
||||
@ -23,7 +24,6 @@ var PaginationRoute = Ember.Mixin.create({
|
||||
this.set('paginationSettings', settings);
|
||||
this.controller.set('paginationSettings', settings);
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
export default PaginationRoute;
|
||||
|
@ -2,7 +2,7 @@ var PaginationViewInfiniteScrollMixin = Ember.Mixin.create({
|
||||
|
||||
/**
|
||||
* Determines if we are past a scroll point where we need to fetch the next page
|
||||
* @param event The scroll event
|
||||
* @param {object} event The scroll event
|
||||
*/
|
||||
checkScroll: function (event) {
|
||||
var element = event.target,
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* global key */
|
||||
|
||||
//Configure KeyMaster to respond to all shortcuts,
|
||||
//even inside of
|
||||
//input, textarea, and select.
|
||||
// Configure KeyMaster to respond to all shortcuts,
|
||||
// even inside of
|
||||
// input, textarea, and select.
|
||||
key.filter = function () {
|
||||
return true;
|
||||
};
|
||||
@ -57,12 +57,13 @@ var ShortcutsRoute = Ember.Mixin.create({
|
||||
}
|
||||
|
||||
key(shortcut, scope, function (event) {
|
||||
//stop things like ctrl+s from actually opening a save dialogue
|
||||
// stop things like ctrl+s from actually opening a save dialogue
|
||||
event.preventDefault();
|
||||
self.send(action, options);
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
removeShortcuts: function () {
|
||||
var shortcuts = this.get('shortcuts');
|
||||
|
||||
@ -70,13 +71,17 @@ var ShortcutsRoute = Ember.Mixin.create({
|
||||
key.unbind(shortcut);
|
||||
});
|
||||
},
|
||||
|
||||
activate: function () {
|
||||
this._super();
|
||||
|
||||
if (!this.shortcuts) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.registerShortcuts();
|
||||
},
|
||||
|
||||
deactivate: function () {
|
||||
this._super();
|
||||
this.removeShortcuts();
|
||||
|
@ -3,6 +3,7 @@
|
||||
var styleBody = Ember.Mixin.create({
|
||||
activate: function () {
|
||||
this._super();
|
||||
|
||||
var cssClasses = this.get('classNames');
|
||||
|
||||
if (cssClasses) {
|
||||
@ -16,6 +17,7 @@ var styleBody = Ember.Mixin.create({
|
||||
|
||||
deactivate: function () {
|
||||
this._super();
|
||||
|
||||
var cssClasses = this.get('classNames');
|
||||
|
||||
Ember.run.schedule('afterRender', null, function () {
|
||||
@ -26,4 +28,4 @@ var styleBody = Ember.Mixin.create({
|
||||
}
|
||||
});
|
||||
|
||||
export default styleBody;
|
||||
export default styleBody;
|
||||
|
@ -1,20 +1,23 @@
|
||||
var BlurField = Ember.Mixin.create({
|
||||
selectOnClick: false,
|
||||
stopEnterKeyDownPropagation: false,
|
||||
|
||||
click: function (event) {
|
||||
if (this.get('selectOnClick')) {
|
||||
event.currentTarget.select();
|
||||
}
|
||||
},
|
||||
|
||||
keyDown: function (event) {
|
||||
// stop event propagation when pressing "enter"
|
||||
// most useful in the case when undesired (global) keyboard shortcuts are getting triggered while interacting
|
||||
// with this particular input element.
|
||||
if (this.get('stopEnterKeyDownPropagation') && event.keyCode === 13) {
|
||||
event.stopPropagation();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
export default BlurField;
|
||||
export default BlurField;
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { getRequestErrorMessage } from 'ghost/utils/ajax';
|
||||
import {getRequestErrorMessage} from 'ghost/utils/ajax';
|
||||
|
||||
import ValidatorExtensions from 'ghost/utils/validator-extensions';
|
||||
import PostValidator from 'ghost/validators/post';
|
||||
@ -14,7 +14,7 @@ import UserValidator from 'ghost/validators/user';
|
||||
ValidatorExtensions.init();
|
||||
|
||||
// format errors to be used in `notifications.showErrors`.
|
||||
// result is [{ message: 'concatenated error messages' }]
|
||||
// result is [{message: 'concatenated error messages'}]
|
||||
function formatErrors(errors, opts) {
|
||||
var message = 'There was an error';
|
||||
|
||||
@ -46,12 +46,11 @@ function formatErrors(errors, opts) {
|
||||
}
|
||||
|
||||
// set format for notifications.showErrors
|
||||
message = [{ message: message }];
|
||||
message = [{message: message}];
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The class that gets this mixin will receive these properties and functions.
|
||||
* It will be able to validate any properties on itself (or the model it passes to validate())
|
||||
@ -143,9 +142,9 @@ var ValidationEngine = Ember.Mixin.create({
|
||||
return _super.call(self, options);
|
||||
}).catch(function (result) {
|
||||
// server save failed - validate() would have given back an array
|
||||
if (! Ember.isArray(result)) {
|
||||
if (!Ember.isArray(result)) {
|
||||
if (options.format !== false) {
|
||||
// concatenate all errors into an array with a single object: [{ message: 'concatted message' }]
|
||||
// concatenate all errors into an array with a single object: [{message: 'concatted message'}]
|
||||
result = formatErrors(result, options);
|
||||
} else {
|
||||
// return the array of errors from the server
|
||||
|
@ -16,13 +16,15 @@ var Post = DS.Model.extend(NProgressSaveMixin, ValidationEngine, {
|
||||
language: DS.attr('string', {defaultValue: 'en_US'}),
|
||||
meta_title: DS.attr('string'),
|
||||
meta_description: DS.attr('string'),
|
||||
author: DS.belongsTo('user', { async: true }),
|
||||
author: DS.belongsTo('user', {async: true}),
|
||||
author_id: DS.attr('number'),
|
||||
updated_at: DS.attr('moment-date'),
|
||||
published_at: DS.attr('moment-date'),
|
||||
published_by: DS.belongsTo('user', { async: true }),
|
||||
tags: DS.hasMany('tag', { embedded: 'always' }),
|
||||
//## Computed post properties
|
||||
published_by: DS.belongsTo('user', {async: true}),
|
||||
tags: DS.hasMany('tag', {embedded: 'always'}),
|
||||
|
||||
// Computed post properties
|
||||
|
||||
isPublished: Ember.computed.equal('status', 'published'),
|
||||
isDraft: Ember.computed.equal('status', 'draft'),
|
||||
|
||||
@ -31,7 +33,7 @@ var Post = DS.Model.extend(NProgressSaveMixin, ValidationEngine, {
|
||||
// when returned from the server with ids.
|
||||
updateTags: function () {
|
||||
var tags = this.get('tags'),
|
||||
oldTags = tags.filterBy('id', null);
|
||||
oldTags = tags.filterBy('id', null);
|
||||
|
||||
tags.removeObjects(oldTags);
|
||||
oldTags.invoke('deleteRecord');
|
||||
|
@ -5,7 +5,7 @@ var Tag = DS.Model.extend({
|
||||
description: DS.attr('string'),
|
||||
parent_id: DS.attr('number'),
|
||||
meta_title: DS.attr('string'),
|
||||
meta_description: DS.attr('string'),
|
||||
meta_description: DS.attr('string')
|
||||
});
|
||||
|
||||
export default Tag;
|
||||
export default Tag;
|
||||
|
@ -24,15 +24,17 @@ var User = DS.Model.extend(NProgressSaveMixin, SelectiveSaveMixin, ValidationEng
|
||||
created_by: DS.attr('number'),
|
||||
updated_at: DS.attr('moment-date'),
|
||||
updated_by: DS.attr('number'),
|
||||
roles: DS.hasMany('role', { embedded: 'always' }),
|
||||
roles: DS.hasMany('role', {embedded: 'always'}),
|
||||
|
||||
role: Ember.computed('roles', function (name, value) {
|
||||
if (arguments.length > 1) {
|
||||
//Only one role per user, so remove any old data.
|
||||
// Only one role per user, so remove any old data.
|
||||
this.get('roles').clear();
|
||||
this.get('roles').pushObject(value);
|
||||
|
||||
return value;
|
||||
}
|
||||
|
||||
return this.get('roles.firstObject');
|
||||
}),
|
||||
|
||||
@ -45,13 +47,14 @@ var User = DS.Model.extend(NProgressSaveMixin, SelectiveSaveMixin, ValidationEng
|
||||
|
||||
saveNewPassword: function () {
|
||||
var url = this.get('ghostPaths.url').api('users', 'password');
|
||||
|
||||
return ic.ajax.request(url, {
|
||||
type: 'PUT',
|
||||
data: {
|
||||
password: [{
|
||||
'oldPassword': this.get('password'),
|
||||
'newPassword': this.get('newPassword'),
|
||||
'ne2Password': this.get('ne2Password')
|
||||
oldPassword: this.get('password'),
|
||||
newPassword: this.get('newPassword'),
|
||||
ne2Password: this.get('ne2Password')
|
||||
}]
|
||||
}
|
||||
});
|
||||
@ -60,9 +63,9 @@ var User = DS.Model.extend(NProgressSaveMixin, SelectiveSaveMixin, ValidationEng
|
||||
resendInvite: function () {
|
||||
var fullUserData = this.toJSON(),
|
||||
userData = {
|
||||
email: fullUserData.email,
|
||||
roles: fullUserData.roles
|
||||
};
|
||||
email: fullUserData.email,
|
||||
roles: fullUserData.roles
|
||||
};
|
||||
|
||||
return ic.ajax.request(this.get('ghostPaths.url').api('users'), {
|
||||
type: 'POST',
|
||||
|
@ -18,29 +18,35 @@ Router.map(function () {
|
||||
this.route('setup');
|
||||
this.route('signin');
|
||||
this.route('signout');
|
||||
this.route('signup', { path: '/signup/:token' });
|
||||
this.route('signup', {path: '/signup/:token'});
|
||||
this.route('forgotten');
|
||||
this.route('reset', { path: '/reset/:token' });
|
||||
this.resource('posts', { path: '/' }, function () {
|
||||
this.route('post', { path: ':post_id' });
|
||||
this.route('reset', {path: '/reset/:token'});
|
||||
|
||||
this.resource('posts', {path: '/'}, function () {
|
||||
this.route('post', {path: ':post_id'});
|
||||
});
|
||||
|
||||
this.resource('editor', function () {
|
||||
this.route('new', { path: '' });
|
||||
this.route('edit', { path: ':post_id' });
|
||||
this.route('new', {path: ''});
|
||||
this.route('edit', {path: ':post_id'});
|
||||
});
|
||||
|
||||
this.resource('settings', function () {
|
||||
this.route('general');
|
||||
this.resource('settings.users', { path: '/users' }, function () {
|
||||
this.route('user', { path: '/:slug' });
|
||||
|
||||
this.resource('settings.users', {path: '/users'}, function () {
|
||||
this.route('user', {path: '/:slug'});
|
||||
});
|
||||
|
||||
this.route('about');
|
||||
});
|
||||
|
||||
this.route('debug');
|
||||
//Redirect legacy content to posts
|
||||
|
||||
// Redirect legacy content to posts
|
||||
this.route('content');
|
||||
|
||||
this.route('error404', { path: '/*path' });
|
||||
|
||||
this.route('error404', {path: '/*path'});
|
||||
});
|
||||
|
||||
export default Router;
|
||||
|
@ -10,8 +10,8 @@ var ApplicationRoute = Ember.Route.extend(SimpleAuth.ApplicationRouteMixin, Shor
|
||||
},
|
||||
|
||||
shortcuts: {
|
||||
'esc': {action: 'closePopups', scope: 'all'},
|
||||
'enter': {action: 'confirmModal', scope: 'modal'}
|
||||
esc: {action: 'closePopups', scope: 'all'},
|
||||
enter: {action: 'confirmModal', scope: 'modal'}
|
||||
},
|
||||
|
||||
actions: {
|
||||
@ -84,6 +84,7 @@ var ApplicationRoute = Ember.Route.extend(SimpleAuth.ApplicationRouteMixin, Shor
|
||||
key.setScope('modal');
|
||||
modalName = 'modals/' + modalName;
|
||||
this.set('modalName', modalName);
|
||||
|
||||
// We don't always require a modal to have a controller
|
||||
// so we're skipping asserting if one exists
|
||||
if (this.controllerFor(modalName, true)) {
|
||||
@ -101,9 +102,11 @@ var ApplicationRoute = Ember.Route.extend(SimpleAuth.ApplicationRouteMixin, Shor
|
||||
});
|
||||
},
|
||||
|
||||
confirmModal : function () {
|
||||
confirmModal: function () {
|
||||
var modalName = this.get('modalName');
|
||||
|
||||
this.send('closeModal');
|
||||
|
||||
if (this.controllerFor(modalName, true)) {
|
||||
this.controllerFor(modalName).send('confirmAccept');
|
||||
}
|
||||
@ -114,11 +117,13 @@ var ApplicationRoute = Ember.Route.extend(SimpleAuth.ApplicationRouteMixin, Shor
|
||||
outlet: 'modal',
|
||||
parentView: 'application'
|
||||
});
|
||||
|
||||
key.setScope('default');
|
||||
},
|
||||
|
||||
loadServerNotifications: function (isDelayed) {
|
||||
var self = this;
|
||||
|
||||
if (this.session.isAuthenticated) {
|
||||
this.store.findAll('notification').then(function (serverNotifications) {
|
||||
serverNotifications.forEach(function (notification) {
|
||||
@ -130,6 +135,7 @@ var ApplicationRoute = Ember.Route.extend(SimpleAuth.ApplicationRouteMixin, Shor
|
||||
|
||||
handleErrors: function (errors) {
|
||||
var self = this;
|
||||
|
||||
this.notifications.clear();
|
||||
errors.forEach(function (errorObj) {
|
||||
self.notifications.showError(errorObj.message || errorObj);
|
||||
|
@ -4,4 +4,4 @@ var ContentRoute = Ember.Route.extend({
|
||||
}
|
||||
});
|
||||
|
||||
export default ContentRoute;
|
||||
export default ContentRoute;
|
||||
|
@ -14,7 +14,7 @@ var DebugRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, styleBod
|
||||
},
|
||||
|
||||
model: function () {
|
||||
return this.store.find('setting', { type: 'blog,theme' }).then(function (records) {
|
||||
return this.store.find('setting', {type: 'blog,theme'}).then(function (records) {
|
||||
return records.get('firstObject');
|
||||
});
|
||||
}
|
||||
|
@ -9,4 +9,4 @@ var Error404Route = Ember.Route.extend({
|
||||
}
|
||||
});
|
||||
|
||||
export default Error404Route;
|
||||
export default Error404Route;
|
||||
|
@ -1,6 +1,6 @@
|
||||
import mobileQuery from 'ghost/utils/mobile';
|
||||
|
||||
//Routes that extend MobileIndexRoute need to implement
|
||||
// Routes that extend MobileIndexRoute need to implement
|
||||
// desktopTransition, a function which is called when
|
||||
// the user resizes to desktop levels.
|
||||
var MobileIndexRoute = Ember.Route.extend({
|
||||
|
@ -3,13 +3,16 @@ import ShortcutsRoute from 'ghost/mixins/shortcuts-route';
|
||||
import loadingIndicator from 'ghost/mixins/loading-indicator';
|
||||
import PaginationRouteMixin from 'ghost/mixins/pagination-route';
|
||||
|
||||
var paginationSettings = {
|
||||
var paginationSettings,
|
||||
PostsRoute;
|
||||
|
||||
paginationSettings = {
|
||||
status: 'all',
|
||||
staticPages: 'all',
|
||||
page: 1
|
||||
};
|
||||
|
||||
var PostsRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, ShortcutsRoute, styleBody, loadingIndicator, PaginationRouteMixin, {
|
||||
PostsRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, ShortcutsRoute, styleBody, loadingIndicator, PaginationRouteMixin, {
|
||||
classNames: ['manage'],
|
||||
|
||||
model: function () {
|
||||
@ -19,6 +22,7 @@ var PostsRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, Shortcut
|
||||
if (user.get('isAuthor')) {
|
||||
paginationSettings.author = user.get('slug');
|
||||
}
|
||||
|
||||
// using `.filter` allows the template to auto-update when new models are pulled in from the server.
|
||||
// we just need to 'return true' to allow all models by default.
|
||||
return self.store.filter('post', paginationSettings, function (post) {
|
||||
@ -52,21 +56,25 @@ var PostsRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, Shortcut
|
||||
} else if (newPosition < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.transitionTo('posts.post', posts.objectAt(newPosition));
|
||||
},
|
||||
|
||||
shortcuts: {
|
||||
'up, k': 'moveUp',
|
||||
'down, j': 'moveDown',
|
||||
'c': 'newPost'
|
||||
c: 'newPost'
|
||||
},
|
||||
|
||||
actions: {
|
||||
newPost: function () {
|
||||
this.transitionTo('editor.new');
|
||||
},
|
||||
|
||||
moveUp: function () {
|
||||
this.stepThroughPosts(-1);
|
||||
},
|
||||
|
||||
moveDown: function () {
|
||||
this.stepThroughPosts(1);
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import mobileQuery from 'ghost/utils/mobile';
|
||||
|
||||
var PostsIndexRoute = MobileIndexRoute.extend(SimpleAuth.AuthenticatedRouteMixin, loadingIndicator, {
|
||||
noPosts: false,
|
||||
|
||||
// Transition to a specific post if we're not on mobile
|
||||
beforeModel: function () {
|
||||
if (!mobileQuery.matches) {
|
||||
@ -21,22 +22,26 @@ var PostsIndexRoute = MobileIndexRoute.extend(SimpleAuth.AuthenticatedRouteMixin
|
||||
// the store has been populated by PostsRoute
|
||||
posts = this.store.all('post'),
|
||||
post;
|
||||
|
||||
return this.store.find('user', 'me').then(function (user) {
|
||||
post = posts.find(function (post) {
|
||||
// Authors can only see posts they've written
|
||||
if (user.get('isAuthor')) {
|
||||
return post.isAuthoredByUser(user);
|
||||
}
|
||||
|
||||
return true;
|
||||
});
|
||||
|
||||
if (post) {
|
||||
return self.transitionTo('posts.post', post);
|
||||
}
|
||||
|
||||
self.set('noPosts', true);
|
||||
});
|
||||
},
|
||||
|
||||
//Mobile posts route callback
|
||||
// Mobile posts route callback
|
||||
desktopTransition: function () {
|
||||
this.goToPost();
|
||||
}
|
||||
|
@ -12,8 +12,7 @@ var PostsPostRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, load
|
||||
|
||||
postId = Number(params.post_id);
|
||||
|
||||
if (!isNumber(postId) || !isFinite(postId) || postId % 1 !== 0 || postId <= 0)
|
||||
{
|
||||
if (!isNumber(postId) || !isFinite(postId) || postId % 1 !== 0 || postId <= 0) {
|
||||
return this.transitionTo('error404', params.post_id);
|
||||
}
|
||||
|
||||
@ -50,6 +49,7 @@ var PostsPostRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, load
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
setupController: function (controller, model) {
|
||||
this._super(controller, model);
|
||||
|
||||
@ -60,10 +60,12 @@ var PostsPostRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, load
|
||||
'enter, o': 'openEditor',
|
||||
'command+backspace, ctrl+backspace': 'deletePost'
|
||||
},
|
||||
|
||||
actions: {
|
||||
openEditor: function () {
|
||||
this.transitionTo('editor.edit', this.get('controller.model'));
|
||||
},
|
||||
|
||||
deletePost: function () {
|
||||
this.send('openModal', 'delete-post', this.get('controller.model'));
|
||||
}
|
||||
|
@ -3,15 +3,18 @@ import loadingIndicator from 'ghost/mixins/loading-indicator';
|
||||
|
||||
var ResetRoute = Ember.Route.extend(styleBody, loadingIndicator, {
|
||||
classNames: ['ghost-reset'],
|
||||
|
||||
beforeModel: function () {
|
||||
if (this.get('session').isAuthenticated) {
|
||||
this.notifications.showWarn('You can\'t reset your password while you\'re signed in.', { delayed: true });
|
||||
this.notifications.showWarn('You can\'t reset your password while you\'re signed in.', {delayed: true});
|
||||
this.transitionTo(SimpleAuth.Configuration.routeAfterAuthentication);
|
||||
}
|
||||
},
|
||||
|
||||
setupController: function (controller, params) {
|
||||
controller.token = params.token;
|
||||
},
|
||||
|
||||
// Clear out any sensitive information
|
||||
deactivate: function () {
|
||||
this._super();
|
||||
|
@ -5,4 +5,4 @@ var SettingsRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, style
|
||||
classNames: ['settings']
|
||||
});
|
||||
|
||||
export default SettingsRoute;
|
||||
export default SettingsRoute;
|
||||
|
@ -13,7 +13,7 @@ var AppsRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, styleBody
|
||||
.then(this.transitionAuthor())
|
||||
.then(this.transitionEditor());
|
||||
},
|
||||
|
||||
|
||||
model: function () {
|
||||
return this.store.find('app');
|
||||
}
|
||||
|
@ -12,7 +12,7 @@ var SettingsGeneralRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin
|
||||
},
|
||||
|
||||
model: function () {
|
||||
return this.store.find('setting', { type: 'blog,theme' }).then(function (records) {
|
||||
return this.store.find('setting', {type: 'blog,theme'}).then(function (records) {
|
||||
return records.get('firstObject');
|
||||
});
|
||||
}
|
||||
|
@ -1,13 +1,16 @@
|
||||
import PaginationRouteMixin from 'ghost/mixins/pagination-route';
|
||||
import styleBody from 'ghost/mixins/style-body';
|
||||
|
||||
var paginationSettings = {
|
||||
var paginationSettings,
|
||||
UsersIndexRoute;
|
||||
|
||||
paginationSettings = {
|
||||
page: 1,
|
||||
limit: 20,
|
||||
status: 'active'
|
||||
};
|
||||
|
||||
var UsersIndexRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, styleBody, PaginationRouteMixin, {
|
||||
UsersIndexRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, styleBody, PaginationRouteMixin, {
|
||||
classNames: ['settings-view-users'],
|
||||
|
||||
setupController: function (controller, model) {
|
||||
|
@ -15,7 +15,7 @@ var SigninRoute = Ember.Route.extend(styleBody, loadingIndicator, {
|
||||
|
||||
// clear the properties that hold the credentials from the controller
|
||||
// when we're no longer on the signin screen
|
||||
this.controllerFor('signin').setProperties({ identification: '', password: '' });
|
||||
this.controllerFor('signin').setProperties({identification: '', password: ''});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -12,7 +12,7 @@ var SignoutRoute = Ember.Route.extend(SimpleAuth.AuthenticatedRouteMixin, styleB
|
||||
} else {
|
||||
this.send('invalidateSession');
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
export default SignoutRoute;
|
||||
|
@ -5,7 +5,7 @@ var SignupRoute = Ember.Route.extend(styleBody, loadingIndicator, {
|
||||
classNames: ['ghost-signup'],
|
||||
beforeModel: function () {
|
||||
if (this.get('session').isAuthenticated) {
|
||||
this.notifications.showWarn('You need to sign out to register as a new user.', { delayed: true });
|
||||
this.notifications.showWarn('You need to sign out to register as a new user.', {delayed: true});
|
||||
this.transitionTo(SimpleAuth.Configuration.routeAfterAuthentication);
|
||||
}
|
||||
},
|
||||
@ -19,7 +19,7 @@ var SignupRoute = Ember.Route.extend(styleBody, loadingIndicator, {
|
||||
|
||||
return new Ember.RSVP.Promise(function (resolve) {
|
||||
if (!re.test(params.token)) {
|
||||
self.notifications.showError('Invalid token.', { delayed: true });
|
||||
self.notifications.showError('Invalid token.', {delayed: true});
|
||||
|
||||
return resolve(self.transitionTo('signin'));
|
||||
}
|
||||
@ -39,7 +39,7 @@ var SignupRoute = Ember.Route.extend(styleBody, loadingIndicator, {
|
||||
}
|
||||
}).then(function (response) {
|
||||
if (response && response.invitation && response.invitation[0].valid === false) {
|
||||
self.notifications.showError('The invitation does not exist or is no longer valid.', { delayed: true });
|
||||
self.notifications.showError('The invitation does not exist or is no longer valid.', {delayed: true});
|
||||
|
||||
return resolve(self.transitionTo('signin'));
|
||||
}
|
||||
@ -55,7 +55,7 @@ var SignupRoute = Ember.Route.extend(styleBody, loadingIndicator, {
|
||||
this._super();
|
||||
|
||||
// clear the properties that hold the sensitive data from the controller
|
||||
this.controllerFor('signup').setProperties({ email: '', password: '', token: '' });
|
||||
this.controllerFor('signup').setProperties({email: '', password: '', token: ''});
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -3,7 +3,7 @@ import ApplicationSerializer from 'ghost/serializers/application';
|
||||
var PostSerializer = ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
|
||||
// settings for the EmbeddedRecordsMixin.
|
||||
attrs: {
|
||||
tags: { embedded: 'always' }
|
||||
tags: {embedded: 'always'}
|
||||
},
|
||||
|
||||
normalize: function (type, hash) {
|
||||
|
@ -13,14 +13,14 @@ var SettingSerializer = ApplicationSerializer.extend({
|
||||
delete data.id;
|
||||
|
||||
Object.keys(data).forEach(function (k) {
|
||||
payload.push({ key: k, value: data[k] });
|
||||
payload.push({key: k, value: data[k]});
|
||||
});
|
||||
|
||||
hash[root] = payload;
|
||||
},
|
||||
|
||||
extractArray: function (store, type, _payload) {
|
||||
var payload = { id: '0' };
|
||||
var payload = {id: '0'};
|
||||
|
||||
_payload.settings.forEach(function (setting) {
|
||||
payload[setting.key] = setting.value;
|
||||
|
@ -2,7 +2,7 @@ import ApplicationSerializer from 'ghost/serializers/application';
|
||||
|
||||
var UserSerializer = ApplicationSerializer.extend(DS.EmbeddedRecordsMixin, {
|
||||
attrs: {
|
||||
roles: { embedded: 'always' }
|
||||
roles: {embedded: 'always'}
|
||||
},
|
||||
|
||||
extractSingle: function (store, primaryType, payload) {
|
||||
|
@ -6,7 +6,7 @@ var ajax = window.ajax = function () {
|
||||
|
||||
// Used in API request fail handlers to parse a standard api error
|
||||
// response json for the message to display
|
||||
var getRequestErrorMessage = function (request, performConcat) {
|
||||
function getRequestErrorMessage(request, performConcat) {
|
||||
var message,
|
||||
msgDetail;
|
||||
|
||||
@ -23,7 +23,6 @@ var getRequestErrorMessage = function (request, performConcat) {
|
||||
try {
|
||||
// Try to parse out the error, or default to 'Unknown'
|
||||
if (request.responseJSON.errors && Ember.isArray(request.responseJSON.errors)) {
|
||||
|
||||
message = request.responseJSON.errors.map(function (errorItem) {
|
||||
return errorItem.message;
|
||||
});
|
||||
@ -46,7 +45,7 @@ var getRequestErrorMessage = function (request, performConcat) {
|
||||
}
|
||||
|
||||
return message;
|
||||
};
|
||||
}
|
||||
|
||||
export { getRequestErrorMessage, ajax };
|
||||
export {getRequestErrorMessage, ajax};
|
||||
export default ajax;
|
||||
|
@ -5,13 +5,15 @@
|
||||
*
|
||||
* This is an ideal tool for working with values inside of {{input}}
|
||||
* elements.
|
||||
* @param transform: a function to transform the **upstream** value.
|
||||
* @param {*} upstream
|
||||
* @param {function} transform a function to transform the **upstream** value.
|
||||
*/
|
||||
var BoundOneWay = function (upstream, transform) {
|
||||
if (typeof transform !== 'function') {
|
||||
//default to the identity function
|
||||
// default to the identity function
|
||||
transform = function (value) { return value; };
|
||||
}
|
||||
|
||||
return Ember.computed(upstream, function (key, value) {
|
||||
return arguments.length > 1 ? value : transform(this.get(upstream));
|
||||
});
|
||||
|
@ -8,22 +8,24 @@ var url,
|
||||
* Check if URL is allowed
|
||||
* URLs are allowed if they start with http://, https://, or /.
|
||||
*/
|
||||
var url = function (url) {
|
||||
url = url.toString().replace(/['"]+/g, '');
|
||||
url = function (url) {
|
||||
// jscs:disable
|
||||
url = url.toString().replace(/['"]+/g, '');
|
||||
if (/^https?:\/\//.test(url) || /^\//.test(url)) {
|
||||
return url;
|
||||
}
|
||||
// jscs:enable
|
||||
};
|
||||
|
||||
/**
|
||||
* Check if ID is allowed
|
||||
* All ids are allowed at the moment.
|
||||
*/
|
||||
var id = function (id) {
|
||||
id = function (id) {
|
||||
return id;
|
||||
};
|
||||
|
||||
export default {
|
||||
url: url,
|
||||
id: id
|
||||
};
|
||||
};
|
||||
|
@ -19,20 +19,21 @@ setupMobileCodeMirror = function setupMobileCodeMirror() {
|
||||
return new TouchEditor(el, options);
|
||||
};
|
||||
|
||||
CodeMirror.keyMap = { basic: {} };
|
||||
CodeMirror.keyMap = {basic: {}};
|
||||
};
|
||||
|
||||
init = function init() {
|
||||
//Codemirror does not function on mobile devices,
|
||||
// nor on any iDevice.
|
||||
// Codemirror does not function on mobile devices, or on any iDevice
|
||||
if (device.mobile() || (device.tablet() && device.ios())) {
|
||||
$('body').addClass('touch-editor');
|
||||
|
||||
Ember.touchEditor = true;
|
||||
//initialize FastClick to remove touch delays
|
||||
|
||||
// initialize FastClick to remove touch delays
|
||||
Ember.run.scheduleOnce('afterRender', null, function () {
|
||||
FastClick.attach(document.body);
|
||||
});
|
||||
|
||||
TouchEditor = createTouchEditor();
|
||||
setupMobileCodeMirror();
|
||||
}
|
||||
|
@ -1,4 +1,6 @@
|
||||
/* global CodeMirror, moment, Showdown */
|
||||
// jscs:disable disallowSpacesInsideParentheses
|
||||
|
||||
/** Set up a shortcut function to be called via router actions.
|
||||
* See editor-route-base
|
||||
*/
|
||||
@ -9,8 +11,8 @@ function init() {
|
||||
// remove predefined `ctrl+h` shortcut
|
||||
delete CodeMirror.keyMap.emacsy['Ctrl-H'];
|
||||
|
||||
//Used for simple, noncomputational replace-and-go! shortcuts.
|
||||
// See default case in shortcut function below.
|
||||
// Used for simple, noncomputational replace-and-go! shortcuts.
|
||||
// See default case in shortcut function below.
|
||||
CodeMirror.prototype.simpleShortcutSyntax = {
|
||||
bold: '**$1**',
|
||||
italic: '*$1*',
|
||||
@ -20,6 +22,7 @@ function init() {
|
||||
image: '![$1](http://)',
|
||||
blockquote: '> $1'
|
||||
};
|
||||
|
||||
CodeMirror.prototype.shortcut = function (type) {
|
||||
var text = this.getSelection(),
|
||||
cursor = this.getCursor(),
|
||||
@ -40,14 +43,20 @@ function init() {
|
||||
currentHeaderLevel = match[0].length;
|
||||
}
|
||||
|
||||
if (currentHeaderLevel > 2) { currentHeaderLevel = 1; }
|
||||
if (currentHeaderLevel > 2) {
|
||||
currentHeaderLevel = 1;
|
||||
}
|
||||
|
||||
hashPrefix = new Array(currentHeaderLevel + 2).join('#');
|
||||
|
||||
// jscs:disable
|
||||
replacementLine = hashPrefix + ' ' + line.replace(/^#* /, '');
|
||||
// jscs:enable
|
||||
|
||||
this.replaceRange(replacementLine, fromLineStart, toLineEnd);
|
||||
this.setCursor(cursor.line, cursor.ch + replacementLine.length);
|
||||
break;
|
||||
|
||||
case 'link':
|
||||
md = this.simpleShortcutSyntax.link.replace('$1', text);
|
||||
this.replaceSelection(md, 'end');
|
||||
@ -65,6 +74,7 @@ function init() {
|
||||
});
|
||||
}
|
||||
return;
|
||||
|
||||
case 'image':
|
||||
md = this.simpleShortcutSyntax.image.replace('$1', text);
|
||||
if (line !== '') {
|
||||
@ -74,23 +84,31 @@ function init() {
|
||||
cursor = this.getCursor();
|
||||
this.setSelection({line: cursor.line, ch: cursor.ch - 8}, {line: cursor.line, ch: cursor.ch - 1});
|
||||
return;
|
||||
|
||||
case 'list':
|
||||
// jscs:disable
|
||||
md = text.replace(/^(\s*)(\w\W*)/gm, '$1* $2');
|
||||
// jscs:enable
|
||||
this.replaceSelection(md, 'end');
|
||||
return;
|
||||
|
||||
case 'currentDate':
|
||||
md = moment(new Date()).format('D MMMM YYYY');
|
||||
this.replaceSelection(md, 'end');
|
||||
return;
|
||||
|
||||
case 'uppercase':
|
||||
md = text.toLocaleUpperCase();
|
||||
break;
|
||||
|
||||
case 'lowercase':
|
||||
md = text.toLocaleLowerCase();
|
||||
break;
|
||||
|
||||
case 'titlecase':
|
||||
md = titleize(text);
|
||||
break;
|
||||
|
||||
case 'copyHTML':
|
||||
converter = new Showdown.converter();
|
||||
|
||||
@ -101,9 +119,10 @@ function init() {
|
||||
}
|
||||
|
||||
// Talk to Ember
|
||||
this.component.sendAction('openModal', 'copy-html', { generatedHTML: generatedHTML });
|
||||
this.component.sendAction('openModal', 'copy-html', {generatedHTML: generatedHTML});
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
if (this.simpleShortcutSyntax[type]) {
|
||||
md = this.simpleShortcutSyntax[type].replace('$1', text);
|
||||
|
@ -1,32 +1,39 @@
|
||||
/* global moment */
|
||||
var parseDateFormats = ['DD MMM YY @ HH:mm', 'DD MMM YY HH:mm',
|
||||
// jscs: disable disallowSpacesInsideParentheses
|
||||
|
||||
var parseDateFormats,
|
||||
displayDateFormat,
|
||||
verifyTimeStamp,
|
||||
parseDateString,
|
||||
formatDate;
|
||||
|
||||
parseDateFormats = ['DD MMM YY @ HH:mm', 'DD MMM YY HH:mm',
|
||||
'DD MMM YYYY @ HH:mm', 'DD MMM YYYY HH:mm',
|
||||
'DD/MM/YY @ HH:mm', 'DD/MM/YY HH:mm',
|
||||
'DD/MM/YYYY @ HH:mm', 'DD/MM/YYYY HH:mm',
|
||||
'DD-MM-YY @ HH:mm', 'DD-MM-YY HH:mm',
|
||||
'DD-MM-YYYY @ HH:mm', 'DD-MM-YYYY HH:mm',
|
||||
'YYYY-MM-DD @ HH:mm', 'YYYY-MM-DD HH:mm',
|
||||
'DD MMM @ HH:mm', 'DD MMM HH:mm'],
|
||||
displayDateFormat = 'DD MMM YY @ HH:mm';
|
||||
'DD MMM @ HH:mm', 'DD MMM HH:mm'];
|
||||
|
||||
/**
|
||||
* Add missing timestamps
|
||||
*/
|
||||
var verifyTimeStamp = function (dateString) {
|
||||
displayDateFormat = 'DD MMM YY @ HH:mm';
|
||||
|
||||
// Add missing timestamps
|
||||
verifyTimeStamp = function (dateString) {
|
||||
if (dateString && !dateString.slice(-5).match(/\d+:\d\d/)) {
|
||||
dateString += ' 12:00';
|
||||
}
|
||||
return dateString;
|
||||
};
|
||||
|
||||
//Parses a string to a Moment
|
||||
var parseDateString = function (value) {
|
||||
// Parses a string to a Moment
|
||||
parseDateString = function (value) {
|
||||
return value ? moment(verifyTimeStamp(value), parseDateFormats, true) : undefined;
|
||||
};
|
||||
|
||||
//Formats a Date or Moment
|
||||
var formatDate = function (value) {
|
||||
// Formats a Date or Moment
|
||||
formatDate = function (value) {
|
||||
return verifyTimeStamp(value ? moment(value).format(displayDateFormat) : '');
|
||||
};
|
||||
|
||||
export {parseDateString, formatDate};
|
||||
export {parseDateString, formatDate};
|
||||
|
@ -1,4 +1,4 @@
|
||||
// This is used by the dropdown initializer (and subsequently popovers) to manage closing & toggeling
|
||||
// This is used by the dropdown initializer (and subsequently popovers) to manage closing & toggling
|
||||
import BodyEventListener from 'ghost/mixins/body-event-listener';
|
||||
|
||||
var DropdownService = Ember.Object.extend(Ember.Evented, BodyEventListener, {
|
||||
@ -14,4 +14,4 @@ var DropdownService = Ember.Object.extend(Ember.Evented, BodyEventListener, {
|
||||
}
|
||||
});
|
||||
|
||||
export default DropdownService;
|
||||
export default DropdownService;
|
||||
|
@ -1,18 +1,14 @@
|
||||
var shortcuts = {},
|
||||
ctrlOrCmd = navigator.userAgent.indexOf('Mac') !== -1 ? 'command' : 'ctrl';
|
||||
//
|
||||
//General editor shortcuts
|
||||
//
|
||||
|
||||
// General editor shortcuts
|
||||
shortcuts[ctrlOrCmd + '+s'] = 'save';
|
||||
shortcuts[ctrlOrCmd + '+alt+p'] = 'publish';
|
||||
shortcuts['alt+shift+z'] = 'toggleZenMode';
|
||||
|
||||
//
|
||||
//CodeMirror Markdown Shortcuts
|
||||
//
|
||||
// CodeMirror Markdown Shortcuts
|
||||
|
||||
//Text
|
||||
// Text
|
||||
shortcuts['ctrl+alt+u'] = {action: 'codeMirrorShortcut', options: {type: 'strike'}};
|
||||
shortcuts[ctrlOrCmd + '+b'] = {action: 'codeMirrorShortcut', options: {type: 'bold'}};
|
||||
shortcuts[ctrlOrCmd + '+i'] = {action: 'codeMirrorShortcut', options: {type: 'italic'}};
|
||||
@ -23,11 +19,11 @@ shortcuts['ctrl+alt+shift+u'] = {action: 'codeMirrorShortcut', options: {type: '
|
||||
shortcuts[ctrlOrCmd + '+shift+c'] = {action: 'codeMirrorShortcut', options: {type: 'copyHTML'}};
|
||||
shortcuts[ctrlOrCmd + '+h'] = {action: 'codeMirrorShortcut', options: {type: 'cycleHeaderLevel'}};
|
||||
|
||||
//Formatting
|
||||
// Formatting
|
||||
shortcuts['ctrl+q'] = {action: 'codeMirrorShortcut', options: {type: 'blockquote'}};
|
||||
shortcuts['ctrl+l'] = {action: 'codeMirrorShortcut', options: {type: 'list'}};
|
||||
|
||||
//Insert content
|
||||
// Insert content
|
||||
shortcuts['ctrl+shift+1'] = {action: 'codeMirrorShortcut', options: {type: 'currentDate'}};
|
||||
shortcuts[ctrlOrCmd + '+k'] = {action: 'codeMirrorShortcut', options: {type: 'link'}};
|
||||
shortcuts[ctrlOrCmd + '+shift+i'] = {action: 'codeMirrorShortcut', options: {type: 'image'}};
|
||||
|
@ -9,7 +9,6 @@ var makeRoute = function (root, args) {
|
||||
return route;
|
||||
};
|
||||
|
||||
|
||||
function ghostPaths() {
|
||||
var path = window.location.pathname,
|
||||
subdir = path.substr(0, path.search('/ghost/')),
|
||||
|
@ -16,8 +16,7 @@ var Notifications = Ember.ArrayProxy.extend({
|
||||
if (object.get('location') === '') {
|
||||
object.set('location', 'bottom');
|
||||
}
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
if (!object.location) {
|
||||
object.location = 'bottom';
|
||||
}
|
||||
@ -56,7 +55,7 @@ var Notifications = Ember.ArrayProxy.extend({
|
||||
}
|
||||
|
||||
for (var i = 0; i < errors.length; i += 1) {
|
||||
this.showError(errors[i].message || errors[i], { doNotClosePassive: true });
|
||||
this.showError(errors[i].message || errors[i], {doNotClosePassive: true});
|
||||
}
|
||||
},
|
||||
showAPIError: function (resp, options) {
|
||||
@ -75,7 +74,7 @@ var Notifications = Ember.ArrayProxy.extend({
|
||||
} else if (resp && resp.jqXHR && resp.jqXHR.responseJSON && resp.jqXHR.responseJSON.message) {
|
||||
this.showError(resp.jqXHR.responseJSON.message, options);
|
||||
} else {
|
||||
this.showError(options.defaultErrorText, { doNotClosePassive: true });
|
||||
this.showError(options.defaultErrorText, {doNotClosePassive: true});
|
||||
}
|
||||
},
|
||||
showInfo: function (message, options) {
|
||||
@ -102,7 +101,6 @@ var Notifications = Ember.ArrayProxy.extend({
|
||||
message: message
|
||||
}, options.delayed);
|
||||
},
|
||||
// @Todo this function isn't referenced anywhere. Should it be removed?
|
||||
showWarn: function (message, options) {
|
||||
options = options || {};
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user