Skip to content

Commit

Permalink
Initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
mixonic committed Sep 24, 2015
1 parent 6cc2331 commit cd789cb
Show file tree
Hide file tree
Showing 31 changed files with 796 additions and 9 deletions.
3 changes: 2 additions & 1 deletion .ember-cli
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@

Setting `disableAnalytics` to true will prevent any data from being sent.
*/
"disableAnalytics": false
"disableAnalytics": false,
"usePods": true
}
70 changes: 70 additions & 0 deletions addon/components/content-kit-component-card/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import Ember from 'ember';
import layout from './template';

export default Ember.Component.extend({
layout,
classNames: ['content-kit-component-card'],
classNameBindings: ['isEditing', 'cardTypeClass'],

/* Actions */

actions: {
moveCard(direction) {
let editor = this.get('editor');
let section = this.get('cardSection');
let method = direction === 'up' ? 'moveSectionUp' : 'moveSectionDown';
editor.run(postEditor => postEditor[method](section));
},

edit() {
this.saveOriginalData();
this.set('isEditing', true);
},

save(data) {
this.saveCard({ data });
this.setProperties({
isEditing: false,
data
});
},

cancel() {
this.restoreOriginalData();
this.set('isEditing', false);
},

remove() {
this.removeCard();
}

},

/* Properties */

isEditing: true,
editor: null,
cardSection: null,

/* Computed properties */

cardTypeClass: Ember.computed('cardName', function() {
return `is-${this.get('cardName')}`;
}),

/* private methods */

// Keep a copy of the data before starting editing
saveOriginalData() {
this.set('originalData', Ember.copy(this.get('data')));
},

// Restore pre-edit data, if any
restoreOriginalData() {
let data = this.get('originalData');
if (data) {
this.saveCard({ data });
this.set('data', data);
}
}
});
20 changes: 20 additions & 0 deletions addon/components/content-kit-component-card/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<div class="content-kit-component-card__actions">
{{#if this.isEditing}}
<button {{action 'save' data}} class="content-kit-component-card__action content-kit-component-card__save">Save</button>
<button {{action 'cancel'}} class="content-kit-component-card__action content-kit-component-card__cancel">Cancel</button>
{{else}}
<button {{action 'edit'}} class="content-kit-component-card__action content-kit-component-card__edit">Edit</button>
<button {{action 'moveCard' 'up'}} title="Move Up" class="content-kit-component-card__action content-kit-component-card__move-up">
Up
</button>
<button {{action 'moveCard' 'down'}} title="Move Down" class="content-kit-component-card__action content-kit-component-card__move-down">
Down
</button>
{{/if}}
<button {{action 'remove'}} class="content-kit-component-card__action content-kit-component-card__remove">Remove</button>
</div>
{{#if this.isEditing}}
{{component (concat cardName '-editor') data=data editorData=editorData saveAction=(action 'save') cancelAction=(action 'cancel')}}
{{else}}
{{component cardName data=(unbound data) editAction=(action 'edit')}}
{{/if}}
188 changes: 188 additions & 0 deletions addon/components/content-kit-editor/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
import Ember from 'ember';
import layout from './template';

export default Ember.Component.extend({
layout,
tagName: 'article',
classNames: ['content-kit-editor'],

activeMarkupTagNames: [],
activeSectionTagNames: [],

init() {
this._super(...arguments);
let mobiledoc = this.get('mobiledoc');
if (!mobiledoc) {
mobiledoc = {
version: '0.2.0',
sections: [[], []]
};
this.set('mobiledoc', mobiledoc);
}
this.set('componentCards', Ember.A([]));
this.set('linkOffsets', null);
this._ignoreCursorDidChange = false;
},

actions: {
toggleMarkup(markupTagName) {
let editor = this.get('editor');
editor.run(postEditor => postEditor.toggleMarkup(markupTagName));
},

toggleSectionTagName(newTagName) {
const editor = this.get('editor');
const sections = editor.activeSections;
let hasSectionsOfTagName = false;

editor.run(postEditor => {
hasSectionsOfTagName = Ember.A(sections).any(
s => s.tagName === newTagName);

if (hasSectionsOfTagName) {
sections.forEach(s => postEditor.resetSectionTagName(s));
} else {
sections.forEach(s => postEditor.changeSectionTagName(s, newTagName));
}
postEditor.scheduleAfterRender(() => {
editor.selectSections(sections);
});
});
},

createListSection(tagName) {
const editor = this.get('editor');
const section = editor.activeSections[0];
if (!section) { return; }

// can only convert a section *into* an li, do nothing to
// sections that are already li sections
if (section.tagName === 'li') { return; }

const listItem = editor.run(postEditor => {
const { builder } = postEditor;
const listItem = builder.createListItem();
const listSection = builder.createListSection(tagName, [listItem]);
section.markers.forEach(m => listItem.markers.append(m.clone()));
postEditor.replaceSection(section, listSection);
return listItem;
});

editor.selectSections([listItem]);
},

addCard(cardName, data) {
let editor = this.get('editor');
let card = editor.builder.createCardSection(cardName, { data });
editor.run(postEditor => postEditor.insertSectionAtEnd(card));
},

toggleLink() {
let editor = this.get('editor');
let offsets = editor.cursor.offsets;
let hasMarkup = editor.detectMarkupInRange(offsets, 'a');
if (hasMarkup) {
editor.run(postEditor => {
postEditor.removeMarkupFromRange(offsets, hasMarkup);
});
} else {
this._ignoreCursorDidChange = true;
this.set('linkOffsets', offsets);
}
},

completeLink(href) {
let offsets = this.get('linkOffsets');
this.set('linkOffsets', null);
let editor = this.get('editor');
editor.run(postEditor => {
let markup = postEditor.builder.createMarkup('a', {
href: href
});
postEditor.addMarkupToRange(offsets, markup);
});
},

cancelLink() {
this.set('linkOffsets', null);
}

},

editingContexts: Ember.computed(function() {
return Ember.A([]);
}),

editor: Ember.computed('mobiledoc', 'isEditingDisabled', function() {
let mobiledoc = this.get('mobiledoc');
let editor = new window.ContentKit.Editor({
mobiledoc,
cards: this.get('cards') || [],
cardOptions: {
onAddComponentCard: (element, cardName, env, payload) => {
let cardId = Ember.uuid();
let destinationElementId = `content-kit-editor-card-${cardId}`;
element.id = destinationElementId;

// The data must be copied to avoid sharing the reference
// to the `defaultListicleItem` between new listicle items.
let data = Ember.copy(payload.data, true);

let card = Ember.Object.create({
destinationElementId,
cardName,
data,
callbacks: env,
editor,
section: env.section
});
return this.get('componentCards').pushObject(card);
},
onRemoveComponentCard: (card) => {
this.get('componentCards').removeObject(card);
}
}
});
editor.on('update', () => {
let updatedMobileDoc = editor.serialize();
this.sendAction('on-change', updatedMobileDoc);
});
editor.cursorDidChange(() => {
if (this.isDestroyed) { return; }

const markupTags = Ember.A(editor.markupsInSelection).mapBy('tagName');
const sectionTags = Ember.A(editor.activeSections).mapBy('tagName');

Ember.run(() => {
this.set('activeMarkupTagNames', markupTags);
this.set('activeSectionTagNames', sectionTags);
});

let isCursorOffEditor = !this.get('editor').cursor.offsets.head.section;
if (!isCursorOffEditor && !this._ignoreCursorDidChange) {
this.set('linkOffsets', null);
} else {
this._ignoreCursorDidChange = false;
}
});
if (this.get('isEditingDisabled')) {
editor.disableEditing();
}
return editor;
}),

didRender() {
let editor = this.get('editor');
let editorElement = this.$('.content-kit-editor__editor')[0];
if (this._renderedEditor !== editor) {
this._renderedEditor = editor;
editor.render(editorElement);
}
},

willDestroyElement() {
let editor = this.get('editor');
editor.destroy();
}

});
35 changes: 35 additions & 0 deletions addon/components/content-kit-editor/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
{{yield editor (hash
toggleMarkup=(action 'toggleMarkup')
toggleLink=(action 'toggleLink')
addCard=(action 'addCard')
toggleSectionTagName=(action 'toggleSectionTagName')
createListSection=(action 'createListSection')
)
this
}}

<div class="content-kit-editor__editor-wrapper">
<div class="content-kit-editor__editor"></div>
</div>

{{#if linkOffsets}}
{{#tether-to-selection}}
{{content-kit-link-prompt
on-submit=(action "completeLink")
on-cancel=(action "cancelLink")}}
{{/tether-to-selection}}
{{/if}}

{{#each componentCards as |card|}}
{{#ember-wormhole to=card.destinationElementId}}
{{content-kit-component-card
editor=editor
cardSection=card.section
cardName=card.cardName
data=card.data
editCard=(action card.callbacks.edit)
saveCard=(action card.callbacks.save)
cancelCard=(action card.callbacks.cancel)
removeCard=(action card.callbacks.remove)}}
{{/ember-wormhole}}
{{/each}}
6 changes: 6 additions & 0 deletions addon/components/content-kit-link-prompt/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import Ember from 'ember';
import layout from './template';

export default Ember.Component.extend({
layout
});
5 changes: 5 additions & 0 deletions addon/components/content-kit-link-prompt/template.hbs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<form {{action attrs.on-submit href on="submit"}}>
{{input value=href}}
<button type="submit">Link</button>
<button {{action attrs.on-cancel}}>Cancel</button>
</form>
8 changes: 8 additions & 0 deletions addon/components/content-kit-toolbar/component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import Ember from 'ember';
import layout from './template';

export default Ember.Component.extend({
layout,
tagName: 'ul',
classNames: ['content-kit-toolbar'],
});
Loading

0 comments on commit cd789cb

Please sign in to comment.