mirror of https://github.com/artf/grapesjs.git
7 changed files with 10 additions and 402 deletions
@ -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, |
|
||||
}); |
|
||||
@ -1,42 +0,0 @@ |
|||||
const CommandButtonView = require('./CommandButtonView'); |
|
||||
const $ = Backbone.$; |
|
||||
|
|
||||
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,234 +0,0 @@ |
|||||
const Backbone = require('backbone'); |
|
||||
const $ = Backbone.$; |
|
||||
|
|
||||
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).off('click').on('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]').on('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 + ']').on('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).off('mouseup keyup mouseout dragenter dragover'); |
|
||||
$(window).off('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).on('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 = $; |
|
||||
Loading…
Reference in new issue