2017-02-27 07:44:15 +03:00
|
|
|
import Ember from 'ember';
|
2017-03-01 21:50:08 +03:00
|
|
|
import layout from '../templates/components/gh-koenig';
|
2017-02-27 07:44:15 +03:00
|
|
|
import Mobiledoc from 'mobiledoc-kit';
|
|
|
|
import {MOBILEDOC_VERSION} from 'mobiledoc-kit/renderers/mobiledoc';
|
|
|
|
import createCardFactory from '../libs/card-factory';
|
|
|
|
import defaultCommands from '../options/default-commands';
|
|
|
|
import editorCards from '../cards/index';
|
|
|
|
//import { VALID_MARKUP_SECTION_TAGNAMES } from 'mobiledoc-kit/models/markup-section'; //the block elements supported by mobile-doc
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
export const BLANK_DOC = {
|
|
|
|
version: MOBILEDOC_VERSION,
|
|
|
|
atoms: [],
|
|
|
|
markups: [],
|
|
|
|
cards: [],
|
|
|
|
sections: []
|
|
|
|
};
|
|
|
|
|
|
|
|
export default Ember.Component.extend({
|
|
|
|
layout,
|
|
|
|
classNames: ['editor-holder'],
|
|
|
|
emberCards: Ember.A([]),
|
|
|
|
init() {
|
|
|
|
this._super(...arguments);
|
|
|
|
this.container = document.querySelector(".gh-editor-container")[0];
|
|
|
|
|
|
|
|
let mobiledoc = this.get('value') || BLANK_DOC;
|
|
|
|
let userCards = this.get('cards') || [];
|
|
|
|
|
|
|
|
if (typeof mobiledoc === "string") {
|
|
|
|
mobiledoc = JSON.parse(mobiledoc);
|
|
|
|
}
|
|
|
|
|
|
|
|
//if the doc is cached then the editor is loaded and we don't need to continue.
|
|
|
|
if (this._cached_doc && this._cached_doc === mobiledoc) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
let createCard = createCardFactory.apply(this, {}); //need to pass the toolbar
|
|
|
|
|
|
|
|
const options = {
|
|
|
|
mobiledoc: mobiledoc,
|
|
|
|
//temp
|
|
|
|
cards: createCard(editorCards.concat(userCards)),
|
|
|
|
atoms: [{
|
|
|
|
name: 'soft-return',
|
|
|
|
type: 'dom',
|
|
|
|
render() {
|
|
|
|
return document.createElement('br');
|
|
|
|
}
|
|
|
|
}],
|
|
|
|
spellcheck: true,
|
|
|
|
autofocus: this.get('shouldFocusEditor'),
|
|
|
|
placeholder: 'Click here to start ...'
|
|
|
|
};
|
|
|
|
this.editor = new Mobiledoc.Editor(options);
|
|
|
|
},
|
|
|
|
willRender() {
|
|
|
|
if(this._rendered) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let editor =this.editor;
|
|
|
|
|
|
|
|
|
|
|
|
editor.willRender(() => {
|
|
|
|
//console.log(Ember.run.currentRunLoop);
|
|
|
|
//if (!Ember.run.currentRunLoop) {
|
|
|
|
// this._startedRunLoop = true;
|
|
|
|
// Ember.run.begin();
|
|
|
|
//}
|
|
|
|
});
|
|
|
|
|
|
|
|
editor.didRender(() => {
|
|
|
|
|
|
|
|
this.sendAction('loaded', editor);
|
|
|
|
//Ember.run.end();
|
|
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
editor.postDidChange(()=> {
|
|
|
|
Ember.run.join(() => {
|
|
|
|
//store a cache of the local doc so that we don't need to reinitialise it.
|
|
|
|
this._cached_doc = editor.serialize(MOBILEDOC_VERSION);
|
|
|
|
this.sendAction('onChange', this._cached_doc);
|
|
|
|
if (this._cached_doc !== BLANK_DOC && !this._firstChange) {
|
|
|
|
this._firstChange = true;
|
|
|
|
this.sendAction('onFirstChange', this._cached_doc);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
},
|
|
|
|
didRender() {
|
|
|
|
|
|
|
|
if(this._rendered) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
let editorDom = this.$('.surface')[0];
|
|
|
|
this.domContainer = editorDom.parentNode.parentNode.parentNode.parentNode; // nasty nasty nasty.
|
|
|
|
this.editor.render(editorDom);
|
|
|
|
this._rendered = true;
|
|
|
|
|
|
|
|
window.editor = this.editor;
|
|
|
|
defaultCommands(this.editor); // initialise the custom text handlers for MD, etc.
|
|
|
|
// shouldFocusEditor is only true when transitioning from new to edit, otherwise it's false or undefined.
|
|
|
|
// therefore, if it's true it's after the first lot of content is entered and we expect the caret to be at the
|
|
|
|
// end of the document.
|
|
|
|
if (this.get('shouldFocusEditor')) {
|
|
|
|
var range = document.createRange();
|
|
|
|
range.selectNodeContents(this.editor.element);
|
|
|
|
range.collapse(false);
|
|
|
|
var sel = window.getSelection();
|
|
|
|
sel.removeAllRanges();
|
|
|
|
sel.addRange(range);
|
|
|
|
this.editor._ensureFocus();
|
|
|
|
}
|
|
|
|
|
|
|
|
this.editor.cursorDidChange(() => this.cursorMoved());
|
|
|
|
|
|
|
|
},
|
|
|
|
// drag and drop images onto the editor
|
|
|
|
drop(event) {
|
|
|
|
if(event.dataTransfer.files.length) {
|
|
|
|
event.preventDefault();
|
|
|
|
for (let i = 0; i < event.dataTransfer.files.length; i++) {
|
|
|
|
let file = [event.dataTransfer.files[i]];
|
|
|
|
this.editor.insertCard('image-card', {pos: 'top', file});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
// makes sure the cursor is on screen.
|
|
|
|
cursorMoved() {
|
|
|
|
const scrollBuffer = 33; // the extra buffer to scroll.
|
|
|
|
const range = window.getSelection().getRangeAt(0); // get the actual range within the DOM.
|
|
|
|
const position = range.getBoundingClientRect();
|
|
|
|
const windowHeight = window.innerHeight;
|
|
|
|
|
|
|
|
if(position.bottom > windowHeight ) {
|
|
|
|
this.domContainer.scrollTop += position.bottom - windowHeight + scrollBuffer;
|
|
|
|
} else if(position.top < 0) {
|
|
|
|
this.domContainer.scrollTop += position.top - scrollBuffer;
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|
|
|
|
willDestroy() {
|
|
|
|
this.editor.destroy();
|
|
|
|
}
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|