mirror of https://github.com/artf/grapesjs.git
28 changed files with 846 additions and 541 deletions
@ -0,0 +1,40 @@ |
|||
{ |
|||
"name": "grapes", |
|||
"description": "Open source web template editor", |
|||
"version": "0.0.5", |
|||
"author": "Artur Arseniev", |
|||
"main": [ |
|||
"dist/grapes.min.js" |
|||
], |
|||
"keywords": [ |
|||
"grapes", |
|||
"wte", |
|||
"web template editor", |
|||
"site builder", |
|||
"newsletter builder", |
|||
"wysiwyg", |
|||
"template", |
|||
"editor" |
|||
], |
|||
"license": "BSD-3-Clause", |
|||
"ignore": [ |
|||
"**/.*", |
|||
"node_modules", |
|||
"bower_components", |
|||
"test", |
|||
"tests" |
|||
], |
|||
"dependencies": { |
|||
"backbone": "~1.2.3", |
|||
"Backbone.Undo": "~0.2.5", |
|||
"jquery": "~2.2.0", |
|||
"jquery.ui": "~1.11.4", |
|||
"keymaster": "~1.6.3", |
|||
"requirejs": "~2.1.22", |
|||
"requirejs-text": "~2.0.14", |
|||
"spectrum": "~1.8.0", |
|||
"underscore": "~1.8.3", |
|||
"codemirror": "~5.10.0", |
|||
"codemirror-formatting": "*" |
|||
} |
|||
} |
|||
@ -0,0 +1,209 @@ |
|||
/*jslint browser:true*/ |
|||
define(['jquery'], |
|||
function ($) { |
|||
|
|||
var readFileIntoDataUrl = function (fileInfo) { |
|||
var loader = $.Deferred(), |
|||
fReader = new FileReader(); |
|||
fReader.onload = function (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 = function () { |
|||
if (options.activeToolbarClass) { |
|||
$(options.toolbarSelector).find(toolbarBtnSelector).each(function () { |
|||
var command = $(this).data(options.commandRole); |
|||
if (document.queryCommandState(command)) { |
|||
$(this).addClass(options.activeToolbarClass); |
|||
} else { |
|||
$(this).removeClass(options.activeToolbarClass); |
|||
} |
|||
}); |
|||
} |
|||
}, |
|||
execCommand = function (commandWithArgs, valueArg) { |
|||
var commandArr = commandWithArgs.split(' '), |
|||
command = commandArr.shift(), |
|||
args = commandArr.join(' ') + (valueArg || ''); |
|||
document.execCommand(command, 0, args); |
|||
updateToolbar(); |
|||
}, |
|||
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 = function () { |
|||
var sel = window.getSelection(); |
|||
if (sel.getRangeAt && sel.rangeCount) { |
|||
return sel.getRangeAt(0); |
|||
} |
|||
}, |
|||
saveSelection = function () { |
|||
selectedRange = getCurrentRange(); |
|||
}, |
|||
restoreSelection = function () { |
|||
var selection = window.getSelection(); |
|||
if (selectedRange) { |
|||
try { |
|||
selection.removeAllRanges(); |
|||
} catch (ex) { |
|||
document.body.createTextRange().select(); |
|||
document.selection.empty(); |
|||
} |
|||
|
|||
selection.addRange(selectedRange); |
|||
} |
|||
}, |
|||
insertFiles = function (files) { |
|||
editor.focus(); |
|||
$.each(files, function (idx, fileInfo) { |
|||
if (/^image\//.test(fileInfo.type)) { |
|||
$.when(readFileIntoDataUrl(fileInfo)).done(function (dataUrl) { |
|||
execCommand('insertimage', dataUrl); |
|||
}).fail(function (e) { |
|||
options.fileUploadError("file-reader", e); |
|||
}); |
|||
} else { |
|||
options.fileUploadError("unsupported-file-type", fileInfo.type); |
|||
} |
|||
}); |
|||
}, |
|||
markSelection = function (input, color) { |
|||
restoreSelection(); |
|||
if (document.queryCommandSupported('hiliteColor')) { |
|||
document.execCommand('hiliteColor', 0, color || 'transparent'); |
|||
} |
|||
saveSelection(); |
|||
input.data(options.selectionMarker, color); |
|||
}, |
|||
bindToolbar = function (toolbar, options) { |
|||
toolbar.find(toolbarBtnSelector).click(function () { |
|||
restoreSelection(); |
|||
editor.focus(); |
|||
execCommand($(this).data(options.commandRole)); |
|||
saveSelection(); |
|||
}); |
|||
toolbar.find('[data-toggle=dropdown]').click(restoreSelection); |
|||
|
|||
toolbar.find('input[type=text][data-' + options.commandRole + ']').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 = function () { |
|||
editor.on('dragenter dragover', false) |
|||
.on('drop', function (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); |
|||
toolbarBtnSelector = 'a[data-' + options.commandRole + '],button[data-' + options.commandRole + '],input[type=button][data-' + options.commandRole + ']'; |
|||
bindHotkeys(options.hotKeys); |
|||
if (options.dragAndDropImages) { |
|||
initFileDrops(); |
|||
} |
|||
bindToolbar($(options.toolbarSelector), options); |
|||
editor.attr('contenteditable', true) |
|||
.on('mouseup keyup mouseout', function () { |
|||
saveSelection(); |
|||
updateToolbar(); |
|||
}); |
|||
$(window).bind('touchend', function (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: function (reason, detail) { console.log("File upload error", reason, detail); } |
|||
}; |
|||
|
|||
return $; |
|||
}); |
|||
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in new issue