Skip to content

Instantly share code, notes, and snippets.

@knownasilya
Forked from bantic/components.template-tag.js
Last active April 12, 2017 18:33
Show Gist options
  • Save knownasilya/50d39b99c95fa44bc1fd3b8284e94183 to your computer and use it in GitHub Desktop.
Save knownasilya/50d39b99c95fa44bc1fd3b8284e94183 to your computer and use it in GitHub Desktop.
mobiledoc template fill in
import Ember from 'ember';
export default Ember.Component.extend({
tagName: 'span',
classNames: ['template-tag'],
click() {
let tag = this.get('tag');
let promise = this.get('onClick')(tag);
promise.then((tagVal) => {
tag.setProperties({
tag: tagVal,
value: tagVal
});
});
}
});
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['template-tags-input'],
didInsertElement() {
let uniqueId = this.get('uniqueId');
let closeAllDropdowns = this.closeAllDropdowns.bind(this);
let tags = this.get('tags');
let template = this.get('template');
let createMarkerables = this.createMarkerables.bind(this);
// Parse pasted/initial templates and convert to tag atoms
// see https://github.com/bustlelabs/mobiledoc-kit#dom-parsing-hooks
let pastedTextPlugin = function(node, builder, { addMarkerable, nodeFinished }) {
if (node.nodeType === Node.TEXT_NODE) {
let text = node.textContent;
let markerables = createMarkerables(text, builder);
markerables.forEach((markerable) => {
addMarkerable(markerable);
});
nodeFinished();
}
};
let editor = new Mobiledoc.Editor({
html: template,
autofocus: false,
parserPlugins: [pastedTextPlugin],
atoms: [
// tag atom implementation for the editor
{
name: 'tag',
type: 'dom',
render: ({ value, env, payload }) => {
// Remove select when tag erased
// TODO: Only remove select if open for current tag, might not be able to get into this state any way
env.onTeardown(() => {
closeAllDropdowns(true);
});
let container = document.createElement('span');
let inner = document.createElement('span');
let open = document.createTextNode('{');
let close = document.createTextNode('}');
inner.textContent = value;
inner.classList.add('template-tag-value');
// Allows creating tags from input to position the select correctly
closeAllDropdowns();
inner.setAttribute('data-ebd-id', `${uniqueId}-trigger`);
if (!tags.includes(value)) {
inner.classList.add('template-tag-value-invalid');
}
container.classList.add('template-tag');
container.appendChild(open);
container.appendChild(inner);
container.appendChild(close);
inner.onclick = () => {
closeAllDropdowns();
// make sure the trigger id is set on this atom, so the menu positions properly.
inner.setAttribute('data-ebd-id', `${uniqueId}-trigger`);
this.get('onShowTags')().then((tag) => {
if (tag !== null) {
env.save(tag, payload);
}
});
};
return container;
}
}
]
});
// Handle the creation of tags when typing '{'
editor.onTextInput({
name: 'create-tag',
text: '{',
run: (editor) => {
let { range } = editor;
let position = editor.post.tailPosition();
let temporaryAtom = editor.insertAtom('tag', '...');
// delete the user's '{'
editor.deleteAtPosition(range.head, -1, {});
// Move the cursor to the end of temp atom
editor.selectRange(range);
// Wait for user's tag selection
this.get('onShowTags')().then((tag) => {
// Delete the temporary atom
editor.deleteAtPosition(range.tail, -1, {});
// Create actual atom
editor.insertAtom('tag', tag);
});
}
});
editor.render(this.element);
},
closeAllDropdowns(override) {
let dropdownOpen = this.get('dropdownOpen');
if ((override || !dropdownOpen) && this.$()) {
let items = this.$('[data-ebd-id]');
items.attr('data-ebd-id', '');
this.get('closeDropdown')();
}
},
createMarkerables(text, builder) {
let regInner = /\{(.+?)\}/g;
let regOuter = /(\{.+?\})/g;
let markerables = [];
if (text.search(regInner) !== -1) {
let split = text.split(regOuter);
markerables = split.map((item) => {
let match = regInner.exec(item);
if (match) {
let tag = match[1];
return builder.createAtom('tag', tag);
}
return builder.createMarker(item);
});
}
return markerables;
}
});
import Ember from 'ember';
export default Ember.Component.extend({
classNames: ['template-tags'],
actions: {
openAndSelect(open, close, reposition) {
open();
reposition();
let defer = Ember.RSVP.defer();
this.set('defer', defer);
return defer.promise.then((tag) => {
close();
return tag;
});
},
setTag(tag) {
let defer = this.get('defer');
defer.resolve(tag);
}
}
});
import Ember from 'ember';
export default Ember.Controller.extend({
appName: 'Ember Twiddle',
tags: ['name', 'address', 'email'],
template: `Hi, I'm {name} and I live at {address}`
});
import Ember from 'ember';
export function eq([val1, val2]/*, hash*/) {
return val1 === val2;
}
export default Ember.Helper.helper(eq);
body {
margin: 12px 16px;
font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 12pt;
}
/* required to keep event to working for outside click for dropdown */
#root {
min-height: 100vh;
}
.template-tags-input {
background-color: #efefef;
line-height: 1.5;
}
.template-tag-value-invalid {
text-decoration: line-through;
}
.template-tag {
color: tomato;
cursor: pointer;
}
.template-tag:hover {
color: indianred;
}
.tag-select,
.ember-basic-dropdown-content {
background-color: transparent;
}
.ember-basic-dropdown-content {
margin-top: 12px;
margin-left: -6px;
}
.tag-select li {
list-style-type: none;
padding: 0.2em 0.4em;
margin-bottom: 0.25em;
background-color: #eee;
border-radius: 10px;
cursor: pointer;
}
.tag-select li:hover {
background-color: #ddd;
}
.tag-select ul {
background-color: transparent;
padding: 0;
margin: 0;
}
<h1>template-tags</h1>
<p>
<ul>
<li>Use `{` character to start adding a template value.</li>
<li>Click on one of the tags to open the tag select to change it's value.</li>
<li>To delete, just put your cursor in front of a tag, and hit the backspace key.</li>
<li>You can also copy & paste. Try copying and pasting this text: {name} lives at {address} and works at {job}.</li>
<li>Invalid pasted tags will have a strike through.</li>
</ul>
</p>
<br>
{{template-tags template=template tags=tags onChange=(action (mut template))}}
<div id="ember-basic-dropdown-wormhole"></div>
{{yield}}
{{#basic-dropdown as |dropdown|}}
{{template-tags-input
tags=tags
template=template
uniqueId=dropdown.uniqueId
dropdownOpen=dropdown.isOpen
closeDropdown=dropdown.actions.close
onShowTags=(action 'openAndSelect' dropdown.actions.open dropdown.actions.close dropdown.actions.reposition)
onTagClick=(action 'openAndSelect' dropdown.actions.open dropdown.actions.close dropdown.actions.reposition)}}
{{#dropdown.content}}
<div class='tag-select'>
<ul>
{{#each tags as |tag|}}
<li class='template-tag' onclick={{action 'setTag' tag}}>
{{tag}}
</li>
{{/each}}
</ul>
</div>
{{/dropdown.content}}
{{/basic-dropdown}}
{
"version": "0.12.1",
"EmberENV": {
"FEATURES": {}
},
"options": {
"use_pods": false,
"enable-testing": false
},
"dependencies": {
"jquery": "https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.3/jquery.js",
"ember": "2.12.0",
"ember-template-compiler": "2.12.0",
"ember-testing": "2.12.0",
"mobiledoc-kit": "https://unpkg.com/[email protected]/dist/global/mobiledoc-kit.js"
},
"addons": {
"ember-data": "2.12.1",
"ember-basic-dropdown": "0.31.0"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment