mirror of https://github.com/artf/grapesjs.git
committed by
GitHub
146 changed files with 5688 additions and 3054 deletions
@ -0,0 +1,10 @@ |
|||
root = true |
|||
|
|||
[*] |
|||
end_of_line = lf |
|||
insert_final_newline = true |
|||
|
|||
[*.js] |
|||
charset = utf-8 |
|||
indent_style = space |
|||
indent_size = 2 |
|||
@ -0,0 +1,3 @@ |
|||
test |
|||
index.html |
|||
webpack.config.js |
|||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1,26 +1,24 @@ |
|||
module.exports = { |
|||
|
|||
run(editor, sender) { |
|||
var config = editor.Config; |
|||
var pfx = config.stylePrefix; |
|||
var bm = editor.BlockManager; |
|||
var panelC; |
|||
if(!this.blocks){ |
|||
this.blocks = $('<div/>').get(0); |
|||
this.blocks.appendChild(bm.render()); |
|||
var panels = editor.Panels; |
|||
if(!panels.getPanel('views-container')) |
|||
panelC = panels.addPanel({id: 'views-container'}); |
|||
else |
|||
panelC = panels.getPanel('views-container'); |
|||
panelC.set('appendContent', this.blocks).trigger('change:appendContent'); |
|||
const bm = editor.BlockManager; |
|||
const pn = editor.Panels; |
|||
|
|||
if (!this.blocks) { |
|||
bm.render(); |
|||
const id = 'views-container'; |
|||
const blocks = document.createElement('div'); |
|||
const panels = pn.getPanel(id) || pn.addPanel({id}); |
|||
blocks.appendChild(bm.getContainer()); |
|||
panels.set('appendContent', blocks).trigger('change:appendContent'); |
|||
this.blocks = blocks; |
|||
} |
|||
|
|||
this.blocks.style.display = 'block'; |
|||
}, |
|||
|
|||
stop() { |
|||
if(this.blocks) |
|||
this.blocks.style.display = 'none'; |
|||
const blocks = this.blocks; |
|||
blocks && (blocks.style.display = 'none'); |
|||
} |
|||
}; |
|||
|
|||
@ -0,0 +1,9 @@ |
|||
module.exports = { |
|||
|
|||
run(editor) { |
|||
const comp = editor.getSelected(); |
|||
const coll = comp && comp.collection; |
|||
coll && coll.parent && editor.select(coll.parent); |
|||
} |
|||
|
|||
}; |
|||
@ -1,40 +1,11 @@ |
|||
module.exports = { |
|||
|
|||
stylePrefix : 'rte-', |
|||
toolbarId : 'toolbar', |
|||
|
|||
// If true, moves the toolbar below the element when the top canvas
|
|||
// edge is reached
|
|||
adjustToolbar: 1, |
|||
|
|||
// Default toolbar commands
|
|||
commands : [{ |
|||
command: 'bold', |
|||
title: 'Bold', |
|||
class: 'fa fa-bold', |
|||
},{ |
|||
command: 'italic', |
|||
title: 'Italic', |
|||
class: 'fa fa-italic', |
|||
},{ |
|||
command: 'underline', |
|||
title: 'Underline', |
|||
class: 'fa fa-underline', |
|||
},{ |
|||
command: 'strikethrough', |
|||
title: 'Strikethrough', |
|||
class: 'fa fa-strikethrough', |
|||
group: 'format' |
|||
},{ |
|||
command: 'insertHTML', |
|||
title: 'Link', |
|||
class: 'fa fa-link', |
|||
args: '<a class="link" href="">${content}</a>', |
|||
}/*,{ |
|||
command: 'fontSize', |
|||
options: [ |
|||
{name: 'Huge', value: '7'}, |
|||
{name: 'Normal', value: '5'}, |
|||
{value: '1'} |
|||
] |
|||
}*/], |
|||
// Default RTE actions
|
|||
actions: ['bold', 'italic', 'underline', 'strikethrough', 'link'], |
|||
}; |
|||
|
|||
@ -1,21 +0,0 @@ |
|||
var Backbone = require('backbone'); |
|||
|
|||
module.exports = Backbone.Model.extend({ |
|||
|
|||
idAttribute: 'command', |
|||
|
|||
defaults: { |
|||
command: '', |
|||
type: '', |
|||
title: '', |
|||
class: '', |
|||
options: [], |
|||
}, |
|||
|
|||
initialize() { |
|||
var opts = this.get('options'); |
|||
if(opts.length) |
|||
this.set('type', 'select'); |
|||
}, |
|||
|
|||
}); |
|||
@ -1,6 +0,0 @@ |
|||
var Backbone = require('backbone'); |
|||
var CommandButton = require('./CommandButton'); |
|||
|
|||
module.exports = Backbone.Collection.extend({ |
|||
model: CommandButton, |
|||
}); |
|||
@ -0,0 +1,245 @@ |
|||
// The initial version of this RTE was borrowed from https://github.com/jaredreich/pell
|
|||
// and adapted to the GrapesJS's need
|
|||
|
|||
import {on, off} from 'utils/mixins' |
|||
|
|||
const RTE_KEY = '_rte'; |
|||
|
|||
const defActions = { |
|||
bold: { |
|||
name: 'bold', |
|||
icon: '<b>B</b>', |
|||
attributes: {title: 'Bold'}, |
|||
result: (rte) => rte.exec('bold') |
|||
}, |
|||
italic: { |
|||
name: 'italic', |
|||
icon: '<i>I</i>', |
|||
attributes: {title: 'Italic'}, |
|||
result: (rte) => rte.exec('italic') |
|||
}, |
|||
underline: { |
|||
name: 'underline', |
|||
icon: '<u>U</u>', |
|||
attributes: {title: 'Underline'}, |
|||
result: (rte) => rte.exec('underline') |
|||
}, |
|||
strikethrough: { |
|||
name: 'strikethrough', |
|||
icon: '<strike>S</strike>', |
|||
attributes: {title: 'Strike-through'}, |
|||
result: (rte) => rte.exec('strikeThrough') |
|||
}, |
|||
link: { |
|||
icon: `<span style="transform:rotate(45deg)">⫘</span>`, |
|||
name: 'link', |
|||
attributes: { |
|||
style: 'font-size:1.4rem;padding:0 4px 2px;', |
|||
title: 'Link', |
|||
}, |
|||
result: (rte) => rte.insertHTML(`<a class="link" href="">${rte.selection()}</a>`) |
|||
} |
|||
} |
|||
|
|||
export default class RichTextEditor { |
|||
|
|||
constructor(settings = {}) { |
|||
const el = settings.el; |
|||
|
|||
if (el[RTE_KEY]) { |
|||
return el[RTE_KEY]; |
|||
} |
|||
|
|||
el[RTE_KEY] = this; |
|||
this.setEl(el); |
|||
this.updateActiveActions = this.updateActiveActions.bind(this); |
|||
|
|||
const settAct = settings.actions || []; |
|||
settAct.forEach((action, i) => { |
|||
if (typeof action === 'string') { |
|||
action = defActions[action]; |
|||
} else if (defActions[action.name]) { |
|||
action = {...defActions[action.name], ...action}; |
|||
} |
|||
settAct[i] = action; |
|||
}); |
|||
const actions = settAct.length ? settAct : |
|||
Object.keys(defActions).map(action => defActions[action]) |
|||
|
|||
settings.classes = { ...{ |
|||
actionbar: 'actionbar', |
|||
button: 'action', |
|||
active: 'active', |
|||
}, ...settings.classes}; |
|||
|
|||
const classes = settings.classes; |
|||
let actionbar = settings.actionbar; |
|||
this.actionbar = actionbar; |
|||
this.settings = settings; |
|||
this.classes = classes; |
|||
this.actions = actions; |
|||
|
|||
if (!actionbar) { |
|||
const actionbarCont = settings.actionbarContainer; |
|||
actionbar = document.createElement('div'); |
|||
actionbar.className = classes.actionbar; |
|||
actionbarCont.appendChild(actionbar); |
|||
this.actionbar = actionbar; |
|||
actions.forEach(action => this.addAction(action)) |
|||
} |
|||
|
|||
settings.styleWithCSS && this.exec('styleWithCSS'); |
|||
this.syncActions(); |
|||
|
|||
return this; |
|||
} |
|||
|
|||
setEl(el) { |
|||
this.el = el; |
|||
this.doc = el.ownerDocument; |
|||
} |
|||
|
|||
updateActiveActions() { |
|||
this.getActions().forEach(action => { |
|||
const btn = action.btn; |
|||
const update = action.update; |
|||
const active = this.classes.active; |
|||
const name = action.name; |
|||
const doc = this.doc; |
|||
btn.className = btn.className.replace(active, '').trim(); |
|||
|
|||
// doc.queryCommandValue(name) != 'false'
|
|||
if (doc.queryCommandState(name)) { |
|||
btn.className += ` ${active}`; |
|||
} |
|||
|
|||
update && update(this, action); |
|||
}) |
|||
} |
|||
|
|||
enable() { |
|||
if (this.enabled) { |
|||
return this; |
|||
} |
|||
|
|||
this.actionbarEl().style.display = ''; |
|||
this.el.contentEditable = true; |
|||
on(this.el, 'mouseup keyup', this.updateActiveActions) |
|||
this.syncActions(); |
|||
this.updateActiveActions(); |
|||
this.el.focus(); |
|||
this.enabled = 1; |
|||
return this; |
|||
} |
|||
|
|||
disable() { |
|||
this.actionbarEl().style.display = 'none'; |
|||
this.el.contentEditable = false; |
|||
off(this.el, 'mouseup keyup', this.updateActiveActions); |
|||
this.enabled = 0; |
|||
return this; |
|||
} |
|||
|
|||
/** |
|||
* Sync actions with the current RTE |
|||
*/ |
|||
syncActions() { |
|||
this.getActions().forEach(action => { |
|||
const event = action.event || 'click'; |
|||
action.btn[`on${event}`] = e => { |
|||
action.result(this, action); |
|||
this.updateActiveActions(); |
|||
}; |
|||
}) |
|||
} |
|||
|
|||
/** |
|||
* Add new action to the actionbar |
|||
* @param {Object} action |
|||
* @param {Object} [opts={}] |
|||
*/ |
|||
addAction(action, opts = {}) { |
|||
const sync = opts.sync; |
|||
const btn = document.createElement('span'); |
|||
const icon = action.icon; |
|||
const attr = action.attributes || {}; |
|||
btn.className = this.classes.button; |
|||
action.btn = btn; |
|||
|
|||
for (let key in attr) { |
|||
btn.setAttribute(key, attr[key]); |
|||
} |
|||
|
|||
if (typeof icon == 'string') { |
|||
btn.innerHTML = icon; |
|||
} else { |
|||
btn.appendChild(icon); |
|||
} |
|||
|
|||
this.actionbarEl().appendChild(btn); |
|||
|
|||
if (sync) { |
|||
this.actions.push(action); |
|||
this.syncActions(); |
|||
} |
|||
} |
|||
|
|||
/** |
|||
* Get the array of current actions |
|||
* @return {Array} |
|||
*/ |
|||
getActions() { |
|||
return this.actions; |
|||
} |
|||
|
|||
/** |
|||
* Returns the Selection instance |
|||
* @return {Selection} |
|||
*/ |
|||
selection() { |
|||
return this.doc.getSelection() |
|||
} |
|||
|
|||
/** |
|||
* Execute the command |
|||
* @param {string} command Command name |
|||
* @param {any} [value=null Command's arguments |
|||
*/ |
|||
exec(command, value = null) { |
|||
this.doc.execCommand(command, false, value); |
|||
} |
|||
|
|||
/** |
|||
* Get the actionbar element |
|||
* @return {HTMLElement} |
|||
*/ |
|||
actionbarEl() { |
|||
return this.actionbar; |
|||
} |
|||
|
|||
/** |
|||
* Set custom HTML to the selection, useful as the default 'insertHTML' command |
|||
* doesn't work in the same way on all browsers |
|||
* @param {string} value HTML string |
|||
*/ |
|||
insertHTML(value) { |
|||
let lastNode; |
|||
const doc = this.doc; |
|||
const sel = doc.getSelection(); |
|||
|
|||
if (sel && sel.rangeCount) { |
|||
const node = doc.createElement('div'); |
|||
const range = sel.getRangeAt(0); |
|||
range.deleteContents(); |
|||
node.innerHTML = value; |
|||
Array.prototype.slice.call(node.childNodes).forEach(nd => { |
|||
range.insertNode(nd); |
|||
lastNode = nd; |
|||
}) |
|||
|
|||
sel.removeAllRanges(); |
|||
sel.addRange(range); |
|||
this.el.focus(); |
|||
} |
|||
} |
|||
} |
|||
@ -1,42 +0,0 @@ |
|||
var Backbone = require('backbone'); |
|||
var CommandButtonView = require('./CommandButtonView'); |
|||
|
|||
module.exports = CommandButtonView.extend({ |
|||
|
|||
initialize(o, config) { |
|||
CommandButtonView.prototype.initialize.apply(this, arguments); |
|||
}, |
|||
|
|||
getInput() { |
|||
var m = this.model; |
|||
if(!this.input){ |
|||
var cmd = m.get('command'); |
|||
var input = '<select data-edit="' + cmd +'">'; |
|||
var opts = m.get('options'); |
|||
var label = m.get('title') || m.get('command'); |
|||
input += '<option>' + label + '</option>'; |
|||
for(var i = 0, len = opts.length; i < len; i++){ |
|||
var opt = opts[i]; |
|||
var value = opt.value; |
|||
var name = opt.name || value; |
|||
input += '<option value="' + value + '">' + name + '</option>'; |
|||
} |
|||
input += '</select>'; |
|||
this.input = $(input); |
|||
} |
|||
return this.input; |
|||
}, |
|||
|
|||
getInputCont() { |
|||
var input = this.getInput(); |
|||
var pfx = this.ppfx; |
|||
var cont = $('<div class="'+pfx+'field '+pfx+'select"><div class="'+pfx+'sel-arrow"><div class="'+pfx+'d-s-arrow"></div></div></div>'); |
|||
return cont.append(input); |
|||
}, |
|||
|
|||
render(...args) { |
|||
CommandButtonView.prototype.render.apply(this, args); |
|||
this.$el.html(this.getInputCont()); |
|||
return this; |
|||
} |
|||
}); |
|||
@ -1,16 +0,0 @@ |
|||
var Backbone = require('backbone'); |
|||
|
|||
module.exports = Backbone.View.extend({ |
|||
tagName: 'a', |
|||
|
|||
initialize(o, config) { |
|||
this.config = config || {}; |
|||
this.ppfx = this.config.pStylePrefix || ''; |
|||
this.className = this.config.stylePrefix + 'btn ' + this.model.get('class'); |
|||
}, |
|||
|
|||
render() { |
|||
this.$el.addClass(this.className); |
|||
return this; |
|||
} |
|||
}); |
|||
@ -1,76 +0,0 @@ |
|||
var Backbone = require('backbone'); |
|||
var CommandButtonView = require('./CommandButtonView'); |
|||
var CommandButtonSelectView = require('./CommandButtonSelectView'); |
|||
|
|||
module.exports = Backbone.View.extend({ |
|||
|
|||
attributes : { |
|||
'data-role': 'editor-toolbar', |
|||
}, |
|||
|
|||
initialize(o) { |
|||
this.config = o.config || {}; |
|||
var pfx = this.config.stylePrefix || ''; |
|||
this.id = pfx + this.config.toolbarId; |
|||
this.listenTo(this.collection, 'add', this.addTo); |
|||
this.$el.data('helper', 1); |
|||
}, |
|||
|
|||
/** |
|||
* Add new model to the collection |
|||
* @param {Model} model |
|||
* @private |
|||
* */ |
|||
addTo(model) { |
|||
this.add(model); |
|||
}, |
|||
|
|||
/** |
|||
* Render new model inside the view |
|||
* @param {Model} model |
|||
* @param {Object} fragment Fragment collection |
|||
* @private |
|||
* */ |
|||
add(model, fragment) { |
|||
var frag = fragment || null; |
|||
var viewObj = CommandButtonView; |
|||
|
|||
switch (model.get('type')) { |
|||
case 'select': |
|||
viewObj = CommandButtonSelectView; |
|||
break; |
|||
} |
|||
var args = model.get('args'); |
|||
var attrs = { |
|||
'title': model.get('title'), |
|||
'data-edit': model.get('command'), |
|||
}; |
|||
if(args) |
|||
attrs['data-args'] = args; |
|||
var view = new viewObj({ |
|||
model, |
|||
attributes: attrs, |
|||
}, this.config); |
|||
|
|||
var rendered = view.render().el; |
|||
|
|||
if(frag) |
|||
frag.appendChild(rendered); |
|||
else |
|||
this.$el.append(rendered); |
|||
}, |
|||
|
|||
render() { |
|||
var frag = document.createDocumentFragment(); |
|||
this.$el.empty(); |
|||
|
|||
this.collection.each(function(model){ |
|||
this.add(model, frag); |
|||
}, this); |
|||
|
|||
this.$el.append(frag); |
|||
this.$el.attr('id', this.id ); |
|||
return this; |
|||
} |
|||
|
|||
}); |
|||
@ -1,231 +0,0 @@ |
|||
var readFileIntoDataUrl = fileInfo => { |
|||
var loader = $.Deferred(), |
|||
fReader = new FileReader(); |
|||
fReader.onload = e => { |
|||
loader.resolve(e.target.result); |
|||
}; |
|||
fReader.onerror = loader.reject; |
|||
fReader.onprogress = loader.notify; |
|||
fReader.readAsDataURL(fileInfo); |
|||
return loader.promise(); |
|||
}; |
|||
$.fn.cleanHtml = function () { |
|||
var html = $(this).html(); |
|||
return html && html.replace(/(<br>|\s|<div><br><\/div>| )*$/, ''); |
|||
}; |
|||
$.fn.wysiwyg = function (userOptions) { |
|||
var editor = this, |
|||
selectedRange, |
|||
options, |
|||
toolbarBtnSelector, |
|||
updateToolbar = () => { |
|||
var actCls = options.activeToolbarClass; |
|||
if (actCls) { |
|||
$(options.toolbarSelector).find(toolbarBtnSelector).each(function () { |
|||
var el = $(this); |
|||
var command = el.data(options.commandRole); |
|||
var doc = editor.get(0).ownerDocument; |
|||
if (doc.queryCommandState(command)) { |
|||
el.addClass(actCls); |
|||
} else { |
|||
el.removeClass(actCls); |
|||
} |
|||
}); |
|||
} |
|||
}, |
|||
execCommand = (commandWithArgs, valueArg) => { |
|||
var commandArr = commandWithArgs.split(' '), |
|||
command = commandArr.shift(), |
|||
args = commandArr.join(' ') + (valueArg || ''); |
|||
//document.execCommand("insertHTML", false, "<span class='own-class'>"+ document.getSelection()+"</span>");
|
|||
editor.get(0).ownerDocument.execCommand("styleWithCSS", false, true); |
|||
editor.get(0).ownerDocument.execCommand(command, 0, args); |
|||
updateToolbar(); |
|||
editor.trigger('change'); |
|||
}, |
|||
/* |
|||
bindHotkeys = function (hotKeys) { |
|||
$.each(hotKeys, function (hotkey, command) { |
|||
editor.keydown(hotkey, function (e) { |
|||
if (editor.attr('contenteditable') && editor.is(':visible')) { |
|||
e.preventDefault(); |
|||
e.stopPropagation(); |
|||
execCommand(command); |
|||
} |
|||
}).keyup(hotkey, function (e) { |
|||
if (editor.attr('contenteditable') && editor.is(':visible')) { |
|||
e.preventDefault(); |
|||
e.stopPropagation(); |
|||
} |
|||
}); |
|||
}); |
|||
}, |
|||
*/ |
|||
getCurrentRange = () => { |
|||
var sel = window.getSelection(); |
|||
if (sel.getRangeAt && sel.rangeCount) { |
|||
return sel.getRangeAt(0); |
|||
} |
|||
}, |
|||
saveSelection = () => { |
|||
selectedRange = getCurrentRange(); |
|||
}, |
|||
restoreSelection = () => { |
|||
var selection = window.getSelection(); |
|||
if (selectedRange) { |
|||
try { |
|||
selection.removeAllRanges(); |
|||
} catch (ex) { |
|||
document.body.createTextRange().select(); |
|||
document.selection.empty(); |
|||
} |
|||
|
|||
selection.addRange(selectedRange); |
|||
} |
|||
}, |
|||
insertFiles = files => { |
|||
editor.focus(); |
|||
$.each(files, (idx, fileInfo) => { |
|||
if (/^image\//.test(fileInfo.type)) { |
|||
$.when(readFileIntoDataUrl(fileInfo)).done(dataUrl => { |
|||
execCommand('insertimage', dataUrl); |
|||
}).fail(e => { |
|||
options.fileUploadError("file-reader", e); |
|||
}); |
|||
} else { |
|||
options.fileUploadError("unsupported-file-type", fileInfo.type); |
|||
} |
|||
}); |
|||
}, |
|||
markSelection = (input, color) => { |
|||
restoreSelection(); |
|||
if (document.queryCommandSupported('hiliteColor')) { |
|||
document.execCommand('hiliteColor', 0, color || 'transparent'); |
|||
} |
|||
saveSelection(); |
|||
input.data(options.selectionMarker, color); |
|||
}, |
|||
bindToolbar = (toolbar, options) => { |
|||
toolbar.find(toolbarBtnSelector).unbind().click(function () { |
|||
restoreSelection(); |
|||
//editor.focus(); // cause defocus on selects
|
|||
var doc = editor.get(0).ownerDocument; |
|||
var el = $(this); |
|||
var comm = el.data(options.commandRole); |
|||
var args = el.data('args'); |
|||
if(args){ |
|||
args = args.replace('${content}', doc.getSelection()); |
|||
execCommand(comm, args); |
|||
}else{ |
|||
doc.execCommand(comm); |
|||
} |
|||
saveSelection(); |
|||
}); |
|||
toolbar.find('[data-toggle=dropdown]').click(restoreSelection); |
|||
var dName = '[data-' + options.commandRole + ']'; |
|||
toolbar.find('select'+dName).on('webkitspeechchange change', function(){ |
|||
var newValue = this.value; |
|||
restoreSelection(); |
|||
if (newValue) { |
|||
editor.focus(); |
|||
execCommand($(this).data(options.commandRole), newValue); |
|||
} |
|||
saveSelection(); |
|||
}); |
|||
toolbar.find('input[type=text]'+dName,', select'+dName).on('webkitspeechchange change', function () { |
|||
var newValue = this.value; /* ugly but prevents fake double-calls due to selection restoration */ |
|||
this.value = ''; |
|||
restoreSelection(); |
|||
if (newValue) { |
|||
editor.focus(); |
|||
execCommand($(this).data(options.commandRole), newValue); |
|||
} |
|||
saveSelection(); |
|||
}).on('focus', function () { |
|||
var input = $(this); |
|||
if (!input.data(options.selectionMarker)) { |
|||
markSelection(input, options.selectionColor); |
|||
input.focus(); |
|||
} |
|||
}).on('blur', function () { |
|||
var input = $(this); |
|||
if (input.data(options.selectionMarker)) { |
|||
markSelection(input, false); |
|||
} |
|||
}); |
|||
toolbar.find('input[type=file][data-' + options.commandRole + ']').change(function () { |
|||
restoreSelection(); |
|||
if (this.type === 'file' && this.files && this.files.length > 0) { |
|||
insertFiles(this.files); |
|||
} |
|||
saveSelection(); |
|||
this.value = ''; |
|||
}); |
|||
}, |
|||
initFileDrops = () => { |
|||
editor.on('dragenter dragover', false) |
|||
.on('drop', e => { |
|||
var dataTransfer = e.originalEvent.dataTransfer; |
|||
e.stopPropagation(); |
|||
e.preventDefault(); |
|||
if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) { |
|||
insertFiles(dataTransfer.files); |
|||
} |
|||
}); |
|||
}; |
|||
/** Disable the editor |
|||
* @date 2015-03-19 */ |
|||
if(typeof userOptions=='string' && userOptions=='destroy'){ |
|||
editor.attr('contenteditable', false).unbind('mouseup keyup mouseout dragenter dragover'); |
|||
$(window).unbind('touchend'); |
|||
return this; |
|||
} |
|||
options = $.extend({}, $.fn.wysiwyg.defaults, userOptions); |
|||
var dName = '[data-' + options.commandRole + ']'; |
|||
toolbarBtnSelector = 'a'+dName+',button'+dName+',input[type=button]'+dName+', select'+dName; |
|||
//bindHotkeys(options.hotKeys);
|
|||
if (options.dragAndDropImages) { |
|||
initFileDrops(); |
|||
} |
|||
bindToolbar($(options.toolbarSelector), options); |
|||
editor.attr('contenteditable', true).on('mouseup keyup mouseout', () => { |
|||
saveSelection(); |
|||
updateToolbar(); |
|||
}); |
|||
$(window).bind('touchend', e => { |
|||
var isInside = (editor.is(e.target) || editor.has(e.target).length > 0), |
|||
currentRange = getCurrentRange(), |
|||
clear = currentRange && (currentRange.startContainer === currentRange.endContainer && currentRange.startOffset === currentRange.endOffset); |
|||
if (!clear || isInside) { |
|||
saveSelection(); |
|||
updateToolbar(); |
|||
} |
|||
}); |
|||
return this; |
|||
}; |
|||
$.fn.wysiwyg.defaults = { |
|||
/* |
|||
hotKeys: { |
|||
'ctrl+b meta+b': 'bold', |
|||
'ctrl+i meta+i': 'italic', |
|||
'ctrl+u meta+u': 'underline', |
|||
'ctrl+z meta+z': 'undo', |
|||
'ctrl+y meta+y meta+shift+z': 'redo', |
|||
'ctrl+l meta+l': 'justifyleft', |
|||
'ctrl+r meta+r': 'justifyright', |
|||
'ctrl+e meta+e': 'justifycenter', |
|||
'ctrl+j meta+j': 'justifyfull', |
|||
'shift+tab': 'outdent', |
|||
'tab': 'indent' |
|||
}, |
|||
*/ |
|||
toolbarSelector: '[data-role=editor-toolbar]', |
|||
commandRole: 'edit', |
|||
activeToolbarClass: 'btn-info', |
|||
selectionMarker: 'edit-focus-marker', |
|||
selectionColor: 'darkgrey', |
|||
dragAndDropImages: true, |
|||
fileUploadError(reason, detail) { console.log("File upload error", reason, detail); } |
|||
}; |
|||
|
|||
module.exports = $; |
|||
@ -0,0 +1,9 @@ |
|||
const Property = require('./PropertyInteger'); |
|||
|
|||
module.exports = Property.extend({ |
|||
|
|||
defaults: Object.assign({}, Property.prototype.defaults, { |
|||
showInput: 1, |
|||
}), |
|||
|
|||
}); |
|||
@ -1,6 +1,5 @@ |
|||
var Backbone = require('backbone'); |
|||
var Sector = require('./Sector'); |
|||
const Sector = require('./Sector'); |
|||
|
|||
module.exports = Backbone.Collection.extend({ |
|||
module.exports = require('backbone').Collection.extend({ |
|||
model: Sector, |
|||
}); |
|||
|
|||
@ -1,31 +1,27 @@ |
|||
var Backbone = require('backbone'); |
|||
var PropertyView = require('./PropertyView'); |
|||
var InputColor = require('domain_abstract/ui/InputColor'); |
|||
const InputColor = require('domain_abstract/ui/InputColor'); |
|||
|
|||
module.exports = PropertyView.extend({ |
|||
module.exports = require('./PropertyIntegerView').extend({ |
|||
|
|||
initialize(options) { |
|||
PropertyView.prototype.initialize.apply(this, arguments); |
|||
this.className += ` ${this.pfx}file`; |
|||
setValue(value, opts = {}) { |
|||
opts = Object.assign({}, opts, {silent: 1}); |
|||
this.inputInst.setValue(value, opts); |
|||
}, |
|||
|
|||
renderInput() { |
|||
onRender() { |
|||
if (!this.input) { |
|||
var inputColor = new InputColor({ |
|||
const ppfx = this.ppfx; |
|||
const inputColor = new InputColor({ |
|||
target: this.target, |
|||
model: this.model, |
|||
ppfx: this.ppfx |
|||
ppfx |
|||
}); |
|||
this.input = inputColor.render(); |
|||
this.$el.append(this.input.$el); |
|||
this.$input = this.input.inputEl; |
|||
this.$color = this.input.colorEl; |
|||
const input = inputColor.render(); |
|||
this.el.querySelector(`.${ppfx}fields`).appendChild(input.el); |
|||
this.$input = input.inputEl; |
|||
this.$color = input.colorEl; |
|||
this.input = this.$input.get(0); |
|||
this.inputInst = input; |
|||
} |
|||
this.setValue(this.componentValue); |
|||
}, |
|||
|
|||
setValue(value) { |
|||
this.input.setValue(value, {silent: 1}); |
|||
}, |
|||
|
|||
}); |
|||
|
|||
@ -1,30 +1,39 @@ |
|||
var PropertyView = require('./PropertyView'); |
|||
var InputNumber = require('domain_abstract/ui/InputNumber'); |
|||
const InputNumber = require('domain_abstract/ui/InputNumber'); |
|||
const $ = Backbone.$; |
|||
|
|||
module.exports = PropertyView.extend({ |
|||
module.exports = require('./PropertyView').extend({ |
|||
|
|||
initialize(options) { |
|||
PropertyView.prototype.initialize.apply(this, arguments); |
|||
this.listenTo(this.model, 'change:unit', this.valueChanged); |
|||
this.listenTo(this.model, 'el:change', this.elementUpdated); |
|||
templateInput() { |
|||
return ''; |
|||
}, |
|||
|
|||
renderInput() { |
|||
init() { |
|||
const model = this.model; |
|||
this.listenTo(model, 'change:unit', this.modelValueChanged); |
|||
this.listenTo(model, 'el:change', this.elementUpdated); |
|||
}, |
|||
|
|||
setValue(value) { |
|||
this.inputInst.setValue(value, {silent: 1}); |
|||
}, |
|||
|
|||
onRender() { |
|||
const ppfx = this.ppfx; |
|||
|
|||
if (!this.input) { |
|||
var inputNumber = new InputNumber({ |
|||
const inputNumber = new InputNumber({ |
|||
model: this.model, |
|||
ppfx: this.ppfx |
|||
}); |
|||
this.input = inputNumber.render(); |
|||
this.$el.append(this.input.$el); |
|||
this.$input = this.input.inputEl; |
|||
this.$unit = this.input.unitEl; |
|||
const input = inputNumber.render(); |
|||
const fields = this.el.querySelector(`.${ppfx}fields`); |
|||
fields.appendChild(input.el); |
|||
this.$input = input.inputEl; |
|||
this.unit = input.unitEl; |
|||
this.$unit = $(this.unit); |
|||
this.input = this.$input.get(0); |
|||
this.inputInst = input; |
|||
} |
|||
this.setValue(this.componentValue); |
|||
}, |
|||
|
|||
setValue(value) { |
|||
this.input.setValue(value, {silent: 1}); |
|||
}, |
|||
|
|||
}); |
|||
|
|||
@ -1,74 +1,69 @@ |
|||
var Backbone = require('backbone'); |
|||
var PropertyView = require('./PropertyView'); |
|||
module.exports = require('./PropertyView').extend({ |
|||
|
|||
module.exports = PropertyView.extend({ |
|||
|
|||
templateField() { |
|||
templateInput() { |
|||
const pfx = this.pfx; |
|||
const ppfx = this.ppfx; |
|||
return ` |
|||
<div class="${ppfx}field ${ppfx}field-radio"> |
|||
<span id="${pfx}input-holder"></span> |
|||
</div> |
|||
<div style="clear:both"></div> |
|||
`;
|
|||
}, |
|||
|
|||
initialize(options) { |
|||
PropertyView.prototype.initialize.apply(this, arguments); |
|||
onRender() { |
|||
const pfx = this.pfx; |
|||
const ppfx = this.ppfx; |
|||
const itemCls = `${ppfx}radio-item-label`; |
|||
const model = this.model; |
|||
this.list = model.get('list') || model.get('options') || []; |
|||
this.className = this.className + ' '+ this.pfx +'list'; |
|||
}, |
|||
const prop = model.get('property'); |
|||
const options = model.get('list') || model.get('options') || []; |
|||
|
|||
/** @inheritdoc */ |
|||
renderInput() { |
|||
var pfx = this.pfx; |
|||
var ppfx = this.ppfx; |
|||
var itemCls = ppfx + 'radio-item-label'; |
|||
var prop = this.property; |
|||
if (!this.input) { |
|||
if(options && options.length) { |
|||
let inputStr = ''; |
|||
|
|||
if(!this.$input) { |
|||
if(this.list && this.list.length) { |
|||
var input = ''; |
|||
_.each(this.list, el => { |
|||
var cl = el.className ? el.className + ' ' + pfx + 'icon ' + itemCls : '', |
|||
id = prop + '-' + el.value, |
|||
labelTxt = el.name ? el.name : el.value; |
|||
var titleAttr = el.title ? 'title="' + el.title + '"': ''; |
|||
input += '<div class="' + ppfx + 'radio-item">'+ |
|||
'<input class="'+pfx+'radio" type="radio" id="'+ id +'" name="'+prop+'" value="'+el.value+'" />'+ |
|||
'<label class="'+(cl ? cl : itemCls)+'" ' + titleAttr + ' for="'+ id +'">' + (cl ? '' : labelTxt) + '</label></div>'; |
|||
options.forEach(el => { |
|||
let cl = el.className ? `${el.className} ${pfx}icon ${itemCls}` : ''; |
|||
let id = `${prop}-${el.value}`; |
|||
let labelTxt = el.name || el.value; |
|||
let titleAttr = el.title ? `title="${el.title}"` : ''; |
|||
inputStr += ` |
|||
<div class="${ppfx}radio-item"> |
|||
<input type="radio" class="${pfx}radio" id="${id}" name="${prop}" value="${el.value}"/> |
|||
<label class="${cl || itemCls}" ${titleAttr} for="${id}">${cl ? '' : labelTxt}</label> |
|||
</div> |
|||
`;
|
|||
}); |
|||
this.input = input; |
|||
this.$inputEl = $(this.input); |
|||
this.$el.find('#'+ pfx +'input-holder').html(this.$inputEl); |
|||
this.$input = this.$inputEl.find('input[name="'+this.property+'"]'); |
|||
|
|||
const inputHld = this.el.querySelector(`#${pfx}input-holder`); |
|||
inputHld.innerHTML = `<div>${inputStr}</div>`; |
|||
this.input = inputHld.firstChild; |
|||
} |
|||
} |
|||
|
|||
this.setValue(this.componentValue); |
|||
}, |
|||
|
|||
/** |
|||
* Returns value from input |
|||
* @return {string} |
|||
*/ |
|||
getInputValue() { |
|||
return this.$input ? this.$el.find('input:checked').val() : ''; |
|||
const inputChk = this.getCheckedEl(); |
|||
return inputChk ? inputChk.value : ''; |
|||
}, |
|||
|
|||
/** @inheritdoc */ |
|||
setValue(value) { |
|||
var v = this.model.get('value') || this.model.getDefaultValue(); |
|||
|
|||
if(value) |
|||
v = value; |
|||
getCheckedEl() { |
|||
const input = this.getInputEl(); |
|||
return input ? input.querySelector('input:checked') : ''; |
|||
}, |
|||
|
|||
if(this.$input) |
|||
this.$input.filter('[value="'+v+'"]').prop('checked', true); |
|||
setValue(value) { |
|||
const model = this.model; |
|||
let val = value || model.get('value') || model.getDefaultValue(); |
|||
const input = this.getInputEl(); |
|||
const inputIn = input ? input.querySelector(`[value="${val}"]`) : ''; |
|||
|
|||
this.model.set({value: v},{silent: true}); |
|||
if (inputIn) { |
|||
inputIn.checked = true; |
|||
} else { |
|||
const inputChk = this.getCheckedEl(); |
|||
inputChk && (inputChk.checked = false); |
|||
} |
|||
}, |
|||
|
|||
}); |
|||
|
|||
@ -0,0 +1,59 @@ |
|||
const InputNumber = require('domain_abstract/ui/InputNumber'); |
|||
const Property = require('./PropertyIntegerView'); |
|||
|
|||
module.exports = Property.extend({ |
|||
|
|||
events: { |
|||
'change': 'inputValueChanged', |
|||
'input': 'inputValueChangedSoft', |
|||
}, |
|||
|
|||
templateInput(model) { |
|||
const ppfx = this.ppfx; |
|||
return ` |
|||
<div class="${ppfx}field ${ppfx}field-range"> |
|||
<input type="range" |
|||
min="${model.get('min')}" |
|||
max="${model.get('max')}" |
|||
step="${model.get('step')}"/> |
|||
</div> |
|||
`;
|
|||
}, |
|||
|
|||
getSliderEl() { |
|||
if (!this.slider) { |
|||
this.slider = this.el.querySelector('input[type=range]'); |
|||
} |
|||
|
|||
return this.slider; |
|||
}, |
|||
|
|||
inputValueChanged() { |
|||
const model = this.model; |
|||
const step = model.get('step'); |
|||
this.getInputEl().value = this.getSliderEl().value; |
|||
const value = this.getInputValue() - step; |
|||
model.set('value', value, {avoidStore: 1}).set('value', value + step); |
|||
this.elementUpdated(); |
|||
}, |
|||
|
|||
inputValueChangedSoft() { |
|||
this.getInputEl().value = this.getSliderEl().value; |
|||
this.model.set('value', this.getInputValue(), {avoidStore: 1}); |
|||
this.elementUpdated(); |
|||
}, |
|||
|
|||
setValue(value) { |
|||
this.getSliderEl().value = value; |
|||
this.inputInst.setValue(value, {silent: 1}); |
|||
}, |
|||
|
|||
onRender() { |
|||
Property.prototype.onRender.apply(this, arguments); |
|||
const model = this.model; |
|||
|
|||
if (!model.get('showInput')) { |
|||
this.inputInst.el.style.display = 'none'; |
|||
} |
|||
} |
|||
}); |
|||
@ -0,0 +1,41 @@ |
|||
.#{$rte-prefix} { |
|||
&toolbar { |
|||
@extend .#{$app-prefix}bg-main; |
|||
@extend .#{$app-prefix}no-user-select; |
|||
|
|||
border: 1px solid $mainDkColor; |
|||
position: absolute; |
|||
border-radius: 3px; |
|||
z-index: 10; |
|||
} |
|||
|
|||
&actionbar { |
|||
display: flex; |
|||
} |
|||
|
|||
&action { |
|||
@extend .#{$app-prefix}color-main; |
|||
|
|||
display: flex; |
|||
align-items: center; |
|||
justify-content: center; |
|||
padding: 5px; |
|||
min-width: 25px; |
|||
border-right: 1px solid $mainDkColor; |
|||
text-align: center; |
|||
cursor: pointer; |
|||
outline: none; |
|||
|
|||
&:last-child { |
|||
border-right: none; |
|||
} |
|||
|
|||
&:hover { |
|||
background-color: $mainLhColor; |
|||
} |
|||
} |
|||
|
|||
&active { |
|||
background-color: $mainDkColor; |
|||
} |
|||
} |
|||
@ -1,78 +1,76 @@ |
|||
|
|||
|
|||
/* Class names prefixes */ |
|||
|
|||
$app-prefix: 'gjs-' !default; |
|||
$nv-prefix: $app-prefix + 'nv-' !default; |
|||
$rte-prefix: $app-prefix + 'rte-' !default; |
|||
$comp-prefix: $app-prefix + 'comp-' !default; |
|||
$mdl-prefix: $app-prefix + 'mdl-' !default; |
|||
$am-prefix: $app-prefix + 'am-' !default; |
|||
$cm-prefix: $app-prefix + 'cm-' !default; |
|||
$pn-prefix: $app-prefix + 'pn-' !default; |
|||
$com-prefix: $app-prefix + 'com-' !default; |
|||
$sm-prefix: $app-prefix + 'sm-' !default; |
|||
$cv-prefix: $app-prefix + 'cv-' !default; |
|||
$clm-prefix: $app-prefix + 'clm-' !default; |
|||
$trt-prefix: $app-prefix + 'trt-' !default; |
|||
$app-prefix: 'gjs-' !default; |
|||
$nv-prefix: $app-prefix + 'nv-' !default; |
|||
$rte-prefix: $app-prefix + 'rte-' !default; |
|||
$comp-prefix: $app-prefix + 'comp-' !default; |
|||
$mdl-prefix: $app-prefix + 'mdl-' !default; |
|||
$am-prefix: $app-prefix + 'am-' !default; |
|||
$cm-prefix: $app-prefix + 'cm-' !default; |
|||
$pn-prefix: $app-prefix + 'pn-' !default; |
|||
$com-prefix: $app-prefix + 'com-' !default; |
|||
$sm-prefix: $app-prefix + 'sm-' !default; |
|||
$cv-prefix: $app-prefix + 'cv-' !default; |
|||
$clm-prefix: $app-prefix + 'clm-' !default; |
|||
$trt-prefix: $app-prefix + 'trt-' !default; |
|||
|
|||
|
|||
/* Colors / Theme */ |
|||
|
|||
|
|||
/* Dark theme */ |
|||
$mainColor: #444 !default; /* Light: #573454 Dark: #3b2639 -moz-linear-gradient(top, #fca99b 0%, #6e2842 100%) */ |
|||
$fontColor: #ddd !default; /* l: #d8d7db */ |
|||
$fontColorActive: #f8f8f8 !default; |
|||
$mainColor: #444 !default; /* Light: #573454 Dark: #3b2639 -moz-linear-gradient(top, #fca99b 0%, #6e2842 100%) */ |
|||
$fontColor: #ddd !default; /* l: #d8d7db */ |
|||
$fontColorActive: #f8f8f8 !default; |
|||
|
|||
/* Light theme |
|||
$mainColor: #fff; |
|||
$fontColor: #9299a3; |
|||
$fontColorActive: #4f8ef7; |
|||
$mainColor: #fff; |
|||
$fontColor: #9299a3; |
|||
$fontColorActive: #4f8ef7; |
|||
*/ |
|||
|
|||
$mainDkColor: rgba(0, 0, 0, 0.3) !default;/* darken($mainColor, 4%) - #383838 */ |
|||
$mainDklColor: rgba(0, 0, 0, 0.1) !default; |
|||
$mainLhColor: rgba(255, 255, 255, 0.1) !default; /* #515151 */ |
|||
$mainLhlColor: rgba(255, 255, 255, 0.7) !default; |
|||
$fontColorDk: #777 !default; |
|||
$mainFont: Helvetica, sans-serif !default; |
|||
$colorBlue: #3b97e3 !default; |
|||
$colorRed: #dd3636 !default; |
|||
$colorYell: #ffca6f !default; |
|||
$colorGreen: #62c462 !default; |
|||
$tagBg: #804f7b !default; |
|||
$secColor: $tagBg !default; |
|||
$imageCompDim: 50px !default; |
|||
$leftWidth: 15% !default; |
|||
$mainDkColor: rgba(0, 0, 0, 0.2) !default;/* darken($mainColor, 4%) - #383838 */ |
|||
$mainDklColor: rgba(0, 0, 0, 0.1) !default; |
|||
$mainLhColor: rgba(255, 255, 255, 0.1) !default; /* #515151 */ |
|||
$mainLhlColor: rgba(255, 255, 255, 0.7) !default; |
|||
$fontColorDk: #777 !default; |
|||
$mainFont: Helvetica, sans-serif !default; |
|||
$colorBlue: #3b97e3 !default; |
|||
$colorRed: #dd3636 !default; |
|||
$colorYell: #ffca6f !default; |
|||
$colorGreen: #62c462 !default; |
|||
$tagBg: #804f7b !default; |
|||
$secColor: $tagBg !default; |
|||
$imageCompDim: 50px !default; |
|||
$leftWidth: 15% !default; |
|||
|
|||
/* Color Helpers */ |
|||
$colorHighlight: #71b7f1 !default; |
|||
$colorWarn: #ffca6f !default; |
|||
$colorHighlight: #71b7f1 !default; |
|||
$colorWarn: #ffca6f !default; |
|||
|
|||
/* Canvas */ |
|||
$hndlMargin: -5px !default; |
|||
$hndlMargin: -5px !default; |
|||
|
|||
/* Components / Inputs */ |
|||
$lightBorder: rgba(255, 255, 255, 0.05) !default; |
|||
$inputFontColor: $mainLhlColor !default; /* #d5d5d5 */ |
|||
$arrowColor: $mainLhlColor !default; /* b1b1b1 */ |
|||
$darkTextShadow: $mainDkColor !default; /* #252525 */ |
|||
$darkBorder: rgba(0, 0, 0, 0.15) !default; /* 303030 */ |
|||
$colorpSize: 22px !default; |
|||
$inputPadding: 5px !default; // Has to be a single value |
|||
$lightBorder: rgba(255, 255, 255, 0.05) !default; |
|||
$inputFontColor: $mainLhlColor !default; /* #d5d5d5 */ |
|||
$arrowColor: $mainLhlColor !default; /* b1b1b1 */ |
|||
$darkTextShadow: $mainDkColor !default; /* #252525 */ |
|||
$darkBorder: rgba(0, 0, 0, 0.15) !default; /* 303030 */ |
|||
$colorpSize: 22px !default; |
|||
$inputPadding: 5px !default; // Has to be a single value |
|||
|
|||
/* Class manager */ |
|||
$addBtnBg: lighten($mainDkColor, 10%) !default; |
|||
$paddElClm: 5px 6px !default; |
|||
$addBtnBg: lighten($mainDkColor, 10%) !default; |
|||
$paddElClm: 5px 6px !default; |
|||
|
|||
/* File uploader */ |
|||
$uploadPadding: 150px 10px !default; |
|||
$uploadPadding: 150px 10px !default; |
|||
|
|||
/* Commands */ |
|||
$animSpeed: 0.2s !default; |
|||
$animSpeed: 0.2s !default; |
|||
|
|||
/* Fonts */ |
|||
$fontPath: '../fonts' !default; |
|||
$fontName: 'main-fonts' !default; |
|||
$fontV: 20 !default;//random(1000) |
|||
$fontPath: '../fonts' !default; |
|||
$fontName: 'main-fonts' !default; |
|||
$fontV: 20 !default;//random(1000) |
|||
|
|||
File diff suppressed because it is too large
@ -0,0 +1,309 @@ |
|||
module.exports = ({$, Backbone}) => { |
|||
if (Backbone) { |
|||
const ViewProt = Backbone.View.prototype; |
|||
const eventNsMap = {}; |
|||
ViewProt.eventNsMap = eventNsMap; |
|||
|
|||
ViewProt.delegate = function(eventName, selector, listener) { |
|||
const vid = '.delegateEvents' + this.cid; |
|||
this.$el.on(eventName, selector, listener); |
|||
//return this;
|
|||
let eventMap = eventNsMap[vid]; |
|||
|
|||
if (!eventMap) { |
|||
eventMap = []; |
|||
eventNsMap[vid] = eventMap; |
|||
} |
|||
|
|||
eventMap.push({eventName, selector, listener}); |
|||
return this; |
|||
}; |
|||
|
|||
ViewProt.undelegateEvents = function() { |
|||
const vid = '.delegateEvents' + this.cid; |
|||
if (this.$el) { |
|||
//this.$el.off(); return this;
|
|||
let eventMap = eventNsMap[vid]; |
|||
|
|||
if (eventMap) { |
|||
eventMap.forEach(({eventName, selector, listener}) => { |
|||
this.$el.off(eventName); |
|||
}); |
|||
} |
|||
} |
|||
return this; |
|||
}; |
|||
|
|||
ViewProt.undelegate = function(ev, sel, list) { |
|||
const vid = '.delegateEvents' + this.cid; |
|||
//this.$el.off(ev, sel, list); return this;
|
|||
let eventMap = eventNsMap[vid]; |
|||
|
|||
if (eventMap) { |
|||
eventMap.forEach(({eventName, selector, listener}) => { |
|||
if (eventName == ev && selector == sel) { |
|||
this.$el.off(eventName); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
return this; |
|||
}; |
|||
} |
|||
|
|||
if ($) { |
|||
const fn = $.fn; |
|||
|
|||
const splitNamespace = function(name) { |
|||
const namespaceArray = name.split('.') |
|||
return ( name.indexOf('.') !== 0 ? [namespaceArray[0], namespaceArray.slice(1)] : [null, namespaceArray] ); |
|||
} |
|||
/* |
|||
const CashEvent = function(node, eventName, namespaces, delegate, originalCallback, runOnce) { |
|||
|
|||
const eventCache = getData(node,'_cashEvents') || setData(node, '_cashEvents', {}); |
|||
const remove = function(c, namespace){ |
|||
if ( c && originalCallback !== c ) { return; } |
|||
if ( namespace && this.namespaces.indexOf(namespace) < 0 ) { return; } |
|||
node.removeEventListener(eventName, callback); |
|||
}; |
|||
const callback = function(e) { |
|||
var t = this; |
|||
if (delegate) { |
|||
t = e.target; |
|||
|
|||
while (t && !matches(t, delegate)) { |
|||
if (t === this) { |
|||
return (t = false); |
|||
} |
|||
t = t.parentNode; |
|||
} |
|||
} |
|||
|
|||
if (t) { |
|||
originalCallback.call(t, e, e.data); |
|||
if ( runOnce ) { remove(); } |
|||
} |
|||
|
|||
}; |
|||
|
|||
this.remove = remove; |
|||
this.namespaces = namespaces; |
|||
|
|||
node.addEventListener(eventName, callback); |
|||
|
|||
eventCache[eventName] = eventCache[eventName] || []; |
|||
eventCache[eventName].push(this); |
|||
|
|||
return this; |
|||
} |
|||
*/ |
|||
|
|||
const on = $.prototype.on; |
|||
const off = $.prototype.off; |
|||
const trigger = $.prototype.trigger; |
|||
const offset = $.prototype.offset; |
|||
const getEvents = (eventName) => eventName.split(/[,\s]+/g); |
|||
const getNamespaces = (eventName) => eventName.split('.'); |
|||
|
|||
fn.on = function(eventName, delegate, callback, runOnce) { |
|||
|
|||
if (typeof eventName == 'string') { |
|||
const events = getEvents(eventName); |
|||
|
|||
if (events.length == 1) { |
|||
eventName = events[0]; |
|||
let namespaces = getNamespaces(eventName); |
|||
|
|||
if (eventName.indexOf('.') !== 0) { |
|||
eventName = namespaces[0]; |
|||
} |
|||
|
|||
namespaces = namespaces.slice(1); |
|||
|
|||
if (namespaces.length) { |
|||
//console.log('Found event with namespaces', namespaces, eventName, delegate, this);
|
|||
const cashNs = this.data('_cashNs') || []; |
|||
// cashNs[namespace]
|
|||
this.data('_cashNs', namespaces); // for each ns need to store '.store' => eventName, delegate, callback
|
|||
} |
|||
|
|||
return on.call(this, eventName, delegate, callback, runOnce); |
|||
} else { |
|||
events.forEach((eventName) => |
|||
this.on(eventName, delegate, callback, runOnce)); |
|||
return this; |
|||
} |
|||
} else { |
|||
return on.call(this, eventName, delegate, callback, runOnce) |
|||
} |
|||
} |
|||
|
|||
fn.off = function(eventName, callback) { |
|||
if (typeof eventName == 'string') { |
|||
const events = getEvents(eventName); |
|||
|
|||
if (events.length == 1) { |
|||
eventName = events[0]; |
|||
let namespaces = getNamespaces(eventName); |
|||
|
|||
if (eventName.indexOf('.') !== 0) { |
|||
eventName = namespaces[0]; |
|||
} |
|||
|
|||
namespaces = namespaces.slice(1); |
|||
|
|||
if (namespaces.length) { |
|||
// Have to off only with the same namespace
|
|||
} |
|||
|
|||
return off.call(this, eventName, callback); |
|||
} else { |
|||
events.forEach((eventName) => this.off(eventName, callback)); |
|||
return this; |
|||
} |
|||
} else { |
|||
return off.call(this, eventName, callback); |
|||
} |
|||
} |
|||
|
|||
fn.trigger = function(eventName, data) { |
|||
if (eventName instanceof $.Event) { |
|||
return this.trigger(eventName.type, data); |
|||
} |
|||
|
|||
if (typeof eventName == 'string') { |
|||
const events = getEvents(eventName); |
|||
|
|||
if (events.length == 1) { |
|||
eventName = events[0]; |
|||
let namespaces = getNamespaces(eventName); |
|||
|
|||
if (eventName.indexOf('.') !== 0) { |
|||
eventName = namespaces[0]; |
|||
} |
|||
|
|||
namespaces = namespaces.slice(1); |
|||
|
|||
if (namespaces.length) { |
|||
// have to trigger with same namespaces and eventName
|
|||
} |
|||
|
|||
return trigger.call(this, eventName, data); |
|||
} else { |
|||
events.forEach((eventName) => this.trigger(eventName, data)); |
|||
return this; |
|||
} |
|||
} else { |
|||
return trigger.call(this, eventName, data); |
|||
} |
|||
} |
|||
|
|||
fn.hide = function() { |
|||
return this.css('display', 'none'); |
|||
} |
|||
|
|||
fn.show = function() { |
|||
return this.css('display', 'block'); |
|||
} |
|||
|
|||
fn.focus = function() { |
|||
const el = this.get(0); |
|||
el && el.focus(); |
|||
return this; |
|||
} |
|||
|
|||
fn.remove = function () { |
|||
return this.each(node => { |
|||
return node.parentNode && node.parentNode.removeChild(node); |
|||
}); |
|||
}, |
|||
|
|||
// For spectrum compatibility
|
|||
fn.bind = function(ev, h) { |
|||
return this.on(ev, h); |
|||
} |
|||
|
|||
fn.unbind = function(ev, h) { |
|||
return this.off(ev, h); |
|||
} |
|||
|
|||
fn.click = function(h) { |
|||
return h ? this.on('click', h) : this.trigger('click'); |
|||
} |
|||
|
|||
fn.change = function(h) { |
|||
return h ? this.on('change', h) : this.trigger('change'); |
|||
} |
|||
|
|||
fn.keydown = function(h) { |
|||
return h ? this.on('keydown', h) : this.trigger('keydown'); |
|||
} |
|||
|
|||
fn.delegate = function(selector, events, data, handler) { |
|||
if (!handler) { |
|||
handler = data; |
|||
} |
|||
|
|||
return this.on(events, selector, function(e) { |
|||
e.data = data; |
|||
handler(e); |
|||
}); |
|||
} |
|||
|
|||
fn.scrollLeft = function() { |
|||
let el = this.get(0); |
|||
el = el.nodeType == 9 ? el.defaultView : el; |
|||
let win = el instanceof Window ? el : null; |
|||
return win ? win.pageXOffset : el.scrollLeft || 0; |
|||
} |
|||
|
|||
fn.scrollTop = function() { |
|||
let el = this.get(0); |
|||
el = el.nodeType == 9 ? el.defaultView : el; |
|||
let win = el instanceof Window ? el : null; |
|||
return win ? win.pageYOffset : el.scrollTop || 0; |
|||
} |
|||
|
|||
fn.offset = function(coords) { |
|||
let top, left; |
|||
|
|||
if (coords) { |
|||
top = coords.top; |
|||
left = coords.left; |
|||
} |
|||
|
|||
if (typeof top != 'undefined') { |
|||
this.css('top', `${top}px`); |
|||
} |
|||
if (typeof left != 'undefined') { |
|||
this.css('left', `${left}px`); |
|||
} |
|||
|
|||
return offset.call(this); |
|||
}; |
|||
|
|||
$.map = function(items, clb) { |
|||
const ar = []; |
|||
|
|||
for (var i = 0; i < items.length; i++) { |
|||
ar.push(clb(items[i], i)); |
|||
} |
|||
|
|||
return ar; |
|||
} |
|||
|
|||
$.inArray = function(val, arr) { |
|||
return arr.indexOf(val); |
|||
} |
|||
|
|||
$.Event = function(src, props) { |
|||
if (!(this instanceof $.Event) ) { |
|||
return new $.Event(src, props); |
|||
} |
|||
|
|||
this.type = src; |
|||
this.isDefaultPrevented = () => false; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,19 @@ |
|||
const on = (el, ev, fn) => { |
|||
ev = ev.split(/\s+/); |
|||
el = el instanceof Array ? el : [el]; |
|||
|
|||
for (let i = 0; i < ev.length; ++i) { |
|||
el.forEach(elem => elem.addEventListener(ev[i], fn)); |
|||
} |
|||
} |
|||
|
|||
const off = (el, ev, fn) => { |
|||
ev = ev.split(/\s+/); |
|||
el = el instanceof Array ? el : [el]; |
|||
|
|||
for (let i = 0; i < ev.length; ++i) { |
|||
el.forEach(elem => elem.removeEventListener(ev[i], fn)); |
|||
} |
|||
} |
|||
|
|||
export {on, off} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue