mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-03 00:15:11 +03:00
e422f0bcba
Integrated Ghost-Editor as an in-repo addon. Moved CSS to /app/styles/addons/ghost-editor/ Still a WIP.
181 lines
5.7 KiB
JavaScript
181 lines
5.7 KiB
JavaScript
import Ember from 'ember';
|
|
import Tools from '../options/default-tools';
|
|
import layout from '../templates/components/slash-menu';
|
|
|
|
export default Ember.Component.extend({
|
|
layout,
|
|
classNames: ['slash-menu'],
|
|
classNameBindings: ['isVisible'],
|
|
range: null,
|
|
menuSelectedItem: 0,
|
|
toolsLength:0,
|
|
selectedTool:null,
|
|
isVisible:false,
|
|
toolbar: Ember.computed(function () {
|
|
let tools = [ ];
|
|
let match = (this.query || "").trim().toLowerCase();
|
|
let i = 0;
|
|
// todo cache active tools so we don't need to loop through them on selection change.
|
|
this.tools.forEach((tool) => {
|
|
|
|
if ((tool.type === 'block' || tool.type === 'card') && (tool.label.toLowerCase().startsWith(match) || tool.name.toLowerCase().startsWith(match))) {
|
|
|
|
let t = {
|
|
label : tool.label,
|
|
name: tool.name,
|
|
icon: tool.icon,
|
|
selected: i===this.menuSelectedItem,
|
|
onClick: tool.onClick
|
|
};
|
|
if(i === this.menuSelectedItem) {
|
|
this.set('selectedTool', t);
|
|
}
|
|
|
|
tools.push(t);
|
|
i++;
|
|
}
|
|
});
|
|
this.set('toolsLength', i);
|
|
if(this.menuSelectedItem > this.toolsLength) {
|
|
this.set('menuSelectedItem', this.toolsLength-1);
|
|
// this.propertyDidChange('toolbar');
|
|
}
|
|
|
|
if(tools.length < 1) {
|
|
this.isActive = false;
|
|
this.set('isVisible', false);
|
|
}
|
|
return tools;
|
|
}),
|
|
|
|
init() {
|
|
this._super(...arguments);
|
|
this.tools =new Tools(this.get('editor'), this);
|
|
this.iconURL = this.get('assetPath') + '/tools/';
|
|
|
|
this.editor.cursorDidChange(this.cursorChange.bind(this));
|
|
let self = this;
|
|
this.editor.onTextInput(
|
|
{
|
|
name: 'slash_menu',
|
|
text: '/',
|
|
run(editor) {
|
|
self.open(editor);
|
|
}
|
|
});
|
|
|
|
|
|
},
|
|
willDestroy() {
|
|
this.editor.destroy();
|
|
},
|
|
cursorChange() {
|
|
if(this.isActive) {
|
|
if(!this.editor.range.isCollapsed || this.editor.range.head.section !== this._node || this.editor.range.head.offset < 1 || !this.editor.range.head.section) {
|
|
this.close();
|
|
}
|
|
this.query = this.editor.range.head.section.text.substring(this._offset, this.editor.range.head.offset);
|
|
this.set('range', {
|
|
section: this._node,
|
|
startOffset: this._offset,
|
|
endOffset: this.editor.range.head.offset
|
|
});
|
|
this.propertyDidChange('toolbar');
|
|
}
|
|
|
|
|
|
},
|
|
open(editor) {
|
|
let self = this;
|
|
let $this = this.$();
|
|
let $editor = Ember.$('.gh-editor-container');
|
|
|
|
this._node = editor.range.head.section;
|
|
this._offset = editor.range.head.offset;
|
|
this.isActive = true;
|
|
this.cursorChange();
|
|
let range = window.getSelection().getRangeAt(0); // get the actual range within the DOM.
|
|
|
|
let position = range.getBoundingClientRect();
|
|
let edOffset = $editor.offset();
|
|
|
|
this.set('isVisible', true);
|
|
|
|
Ember.run.schedule('afterRender', this,
|
|
() => {
|
|
$this.css('top', position.top + $editor.scrollTop() - edOffset.top + 20); //- edOffset.top+10
|
|
$this.css('left', position.left + (position.width / 2) + $editor.scrollLeft() - edOffset.left );
|
|
}
|
|
);
|
|
|
|
this.query="";
|
|
this.propertyDidChange('toolbar');
|
|
|
|
|
|
const downKeyCommand = {
|
|
str: 'DOWN',
|
|
_ghostName: 'slashdown',
|
|
run() {
|
|
let item = self.get('menuSelectedItem');
|
|
if(item < self.get('toolsLength')-1) {
|
|
self.set('menuSelectedItem', item + 1);
|
|
self.propertyDidChange('toolbar');
|
|
}
|
|
}
|
|
};
|
|
editor.registerKeyCommand(downKeyCommand);
|
|
|
|
const upKeyCommand = {
|
|
str: 'UP',
|
|
_ghostName: 'slashup',
|
|
run() {
|
|
let item = self.get('menuSelectedItem');
|
|
if(item > 0) {
|
|
self.set('menuSelectedItem', item - 1);
|
|
self.propertyDidChange('toolbar');
|
|
}
|
|
}
|
|
};
|
|
editor.registerKeyCommand(upKeyCommand);
|
|
|
|
const enterKeyCommand = {
|
|
str: 'ENTER',
|
|
_ghostName: 'slashdown',
|
|
run(postEditor) {
|
|
|
|
let range = postEditor.range;
|
|
|
|
range.head.offset = self._offset - 1;
|
|
postEditor.deleteRange(range);
|
|
self.get('selectedTool').onClick(self.get('editor'));
|
|
self.close();
|
|
}
|
|
};
|
|
editor.registerKeyCommand(enterKeyCommand);
|
|
|
|
const escapeKeyCommand = {
|
|
str: 'ESC',
|
|
_ghostName: 'slashesc',
|
|
run() {
|
|
self.close();
|
|
}
|
|
};
|
|
editor.registerKeyCommand(escapeKeyCommand);
|
|
},
|
|
close() {
|
|
this.isActive = false;
|
|
|
|
this.set('isVisible', false);
|
|
// note: below is using a mobiledoc Private API.
|
|
// there is no way to unregister a keycommand when it's registered so we have to remove it ourselves.
|
|
for( let i = this.editor._keyCommands.length-1; i > -1; i--) {
|
|
let keyCommand = this.editor._keyCommands[i];
|
|
|
|
if(keyCommand._ghostName === 'slashdown' || keyCommand._ghostName === 'slashup' || keyCommand._ghostName === 'slashenter'|| keyCommand._ghostName === 'slashesc') {
|
|
this.editor._keyCommands.splice(i,1);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
});
|