[ Mini Kiebo ]
Server: Windows NT DESKTOP-5B8S0D4 6.2 build 9200 (Windows 8 Professional Edition) i586
Path:
D:
/
xampp182
/
htdocs
/
simkeu
/
keuangan
/
vendors
/
bower_components
/
summernote
/
src
/
js
/
base
/
module
/
[
Home
]
File: Editor.js
define([ 'summernote/base/core/agent', 'summernote/base/core/key', 'summernote/base/core/func', 'summernote/base/core/list', 'summernote/base/core/dom', 'summernote/base/core/range', 'summernote/base/core/async', 'summernote/base/editing/History', 'summernote/base/editing/Style', 'summernote/base/editing/Typing', 'summernote/base/editing/Table', 'summernote/base/editing/Bullet' ], function ( agent, key, func, list, dom, range, async, History, Style, Typing, Table, Bullet ) { var KEY_BOGUS = 'bogus'; /** * @class Editor */ var Editor = function (context) { var self = this; var $note = context.layoutInfo.note; var $editor = context.layoutInfo.editor; var $editable = context.layoutInfo.editable; var options = context.options; var lang = options.langInfo; var editable = $editable[0]; var lastRange = null; var style = new Style(); var table = new Table(); var typing = new Typing(); var bullet = new Bullet(); var history = new History($editable); this.initialize = function () { // bind custom events $editable.on('keydown', function (event) { if (event.keyCode === key.code.ENTER) { context.triggerEvent('enter', event); } context.triggerEvent('keydown', event); if (options.shortcuts && !event.isDefaultPrevented()) { self.handleKeyMap(event); } }).on('keyup', function (event) { context.triggerEvent('keyup', event); }).on('focus', function (event) { context.triggerEvent('focus', event); }).on('blur', function (event) { context.triggerEvent('blur', event); }).on('mousedown', function (event) { context.triggerEvent('mousedown', event); }).on('mouseup', function (event) { context.triggerEvent('mouseup', event); }).on('scroll', function (event) { context.triggerEvent('scroll', event); }).on('paste', function (event) { context.triggerEvent('paste', event); }); // init content before set event $editable.html(dom.html($note) || dom.emptyPara); // [workaround] IE doesn't have input events for contentEditable // - see: https://goo.gl/4bfIvA var changeEventName = agent.isMSIE ? 'DOMCharacterDataModified DOMSubtreeModified DOMNodeInserted' : 'input'; $editable.on(changeEventName, function () { context.triggerEvent('change', $editable.html()); }); $editor.on('focusin', function (event) { context.triggerEvent('focusin', event); }).on('focusout', function (event) { context.triggerEvent('focusout', event); }); if (!options.airMode && options.height) { this.setHeight(options.height); } if (!options.airMode && options.maxHeight) { $editable.css('max-height', options.maxHeight); } if (!options.airMode && options.minHeight) { $editable.css('min-height', options.minHeight); } history.recordUndo(); }; this.destroy = function () { $editable.off(); }; this.handleKeyMap = function (event) { var keyMap = options.keyMap[agent.isMac ? 'mac' : 'pc']; var keys = []; if (event.metaKey) { keys.push('CMD'); } if (event.ctrlKey && !event.altKey) { keys.push('CTRL'); } if (event.shiftKey) { keys.push('SHIFT'); } var keyName = key.nameFromCode[event.keyCode]; if (keyName) { keys.push(keyName); } var eventName = keyMap[keys.join('+')]; if (eventName) { event.preventDefault(); context.invoke(eventName); } else if (key.isEdit(event.keyCode)) { this.afterCommand(); } }; /** * create range * @return {WrappedRange} */ this.createRange = function () { this.focus(); return range.create(editable); }; /** * saveRange * * save current range * * @param {Boolean} [thenCollapse=false] */ this.saveRange = function (thenCollapse) { lastRange = this.createRange(); if (thenCollapse) { lastRange.collapse().select(); } }; /** * restoreRange * * restore lately range */ this.restoreRange = function () { if (lastRange) { lastRange.select(); this.focus(); } }; this.saveTarget = function (node) { $editable.data('target', node); }; this.clearTarget = function () { $editable.removeData('target'); }; this.restoreTarget = function () { return $editable.data('target'); }; /** * currentStyle * * current style * @return {Object|Boolean} unfocus */ this.currentStyle = function () { var rng = range.create(); if (rng) { rng = rng.normalize(); } return rng ? style.current(rng) : style.fromNode($editable); }; /** * style from node * * @param {jQuery} $node * @return {Object} */ this.styleFromNode = function ($node) { return style.fromNode($node); }; /** * undo */ this.undo = function () { context.triggerEvent('before.command', $editable.html()); history.undo(); context.triggerEvent('change', $editable.html()); }; context.memo('help.undo', lang.help.undo); /** * redo */ this.redo = function () { context.triggerEvent('before.command', $editable.html()); history.redo(); context.triggerEvent('change', $editable.html()); }; context.memo('help.redo', lang.help.redo); /** * before command */ var beforeCommand = this.beforeCommand = function () { context.triggerEvent('before.command', $editable.html()); // keep focus on editable before command execution self.focus(); }; /** * after command * @param {Boolean} isPreventTrigger */ var afterCommand = this.afterCommand = function (isPreventTrigger) { history.recordUndo(); if (!isPreventTrigger) { context.triggerEvent('change', $editable.html()); } }; /* jshint ignore:start */ // native commands(with execCommand), generate function for execCommand var commands = ['bold', 'italic', 'underline', 'strikethrough', 'superscript', 'subscript', 'justifyLeft', 'justifyCenter', 'justifyRight', 'justifyFull', 'formatBlock', 'removeFormat', 'backColor', 'foreColor', 'fontName']; for (var idx = 0, len = commands.length; idx < len; idx ++) { this[commands[idx]] = (function (sCmd) { return function (value) { beforeCommand(); document.execCommand(sCmd, false, value); afterCommand(true); }; })(commands[idx]); context.memo('help.' + commands[idx], lang.help[commands[idx]]); } /* jshint ignore:end */ /** * handle tab key */ this.tab = function () { var rng = this.createRange(); if (rng.isCollapsed() && rng.isOnCell()) { table.tab(rng); } else { beforeCommand(); typing.insertTab(rng, options.tabSize); afterCommand(); } }; context.memo('help.tab', lang.help.tab); /** * handle shift+tab key */ this.untab = function () { var rng = this.createRange(); if (rng.isCollapsed() && rng.isOnCell()) { table.tab(rng, true); } }; context.memo('help.untab', lang.help.untab); /** * run given function between beforeCommand and afterCommand */ this.wrapCommand = function (fn) { return function () { beforeCommand(); fn.apply(self, arguments); afterCommand(); }; }; /** * insert paragraph */ this.insertParagraph = this.wrapCommand(function () { typing.insertParagraph(editable); }); context.memo('help.insertParagraph', lang.help.insertParagraph); this.insertOrderedList = this.wrapCommand(function () { bullet.insertOrderedList(editable); }); context.memo('help.insertOrderedList', lang.help.insertOrderedList); this.insertUnorderedList = this.wrapCommand(function () { bullet.insertUnorderedList(editable); }); context.memo('help.insertUnorderedList', lang.help.insertUnorderedList); this.indent = this.wrapCommand(function () { bullet.indent(editable); }); context.memo('help.indent', lang.help.indent); this.outdent = this.wrapCommand(function () { bullet.outdent(editable); }); context.memo('help.outdent', lang.help.outdent); /** * insert image * * @param {String} src * @param {String|Function} param * @return {Promise} */ this.insertImage = function (src, param) { return async.createImage(src, param).then(function ($image) { beforeCommand(); if (typeof param === 'function') { param($image); } else { if (typeof param === 'string') { $image.attr('data-filename', param); } $image.css('width', Math.min($editable.width(), $image.width())); } $image.show(); range.create(editable).insertNode($image[0]); range.createFromNodeAfter($image[0]).select(); afterCommand(); }).fail(function (e) { context.triggerEvent('image.upload.error', e); }); }; /** * insertImages * @param {File[]} files */ this.insertImages = function (files) { $.each(files, function (idx, file) { var filename = file.name; if (options.maximumImageFileSize && options.maximumImageFileSize < file.size) { context.triggerEvent('image.upload.error', lang.image.maximumFileSizeError); } else { async.readFileAsDataURL(file).then(function (dataURL) { return self.insertImage(dataURL, filename); }).fail(function () { context.triggerEvent('image.upload.error'); }); } }); }; /** * insertImagesOrCallback * @param {File[]} files */ this.insertImagesOrCallback = function (files) { var callbacks = options.callbacks; // If onImageUpload options setted if (callbacks.onImageUpload) { context.triggerEvent('image.upload', files); // else insert Image as dataURL } else { this.insertImages(files); } }; /** * insertNode * insert node * @param {Node} node */ this.insertNode = this.wrapCommand(function (node) { var rng = this.createRange(); rng.insertNode(node); range.createFromNodeAfter(node).select(); }); /** * insert text * @param {String} text */ this.insertText = this.wrapCommand(function (text) { var rng = this.createRange(); var textNode = rng.insertNode(dom.createText(text)); range.create(textNode, dom.nodeLength(textNode)).select(); }); /** * return selected plain text * @return {String} text */ this.getSelectedText = function () { var rng = this.createRange(); // if range on anchor, expand range with anchor if (rng.isOnAnchor()) { rng = range.createFromNode(dom.ancestor(rng.sc, dom.isAnchor)); } return rng.toString(); }; /** * paste HTML * @param {String} markup */ this.pasteHTML = this.wrapCommand(function (markup) { var contents = this.createRange().pasteHTML(markup); range.createFromNodeAfter(list.last(contents)).select(); }); /** * formatBlock * * @param {String} tagName */ this.formatBlock = this.wrapCommand(function (tagName) { // [workaround] for MSIE, IE need `<` tagName = agent.isMSIE ? '<' + tagName + '>' : tagName; document.execCommand('FormatBlock', false, tagName); }); this.formatPara = function () { this.formatBlock('P'); }; context.memo('help.formatPara', lang.help.formatPara); /* jshint ignore:start */ for (var idx = 1; idx <= 6; idx ++) { this['formatH' + idx] = function (idx) { return function () { this.formatBlock('H' + idx); }; }(idx); context.memo('help.formatH'+idx, lang.help['formatH' + idx]); }; /* jshint ignore:end */ /** * fontSize * * @param {String} value - px */ this.fontSize = function (value) { var rng = this.createRange(); if (rng && rng.isCollapsed()) { var spans = style.styleNodes(rng); var firstSpan = list.head(spans); $(spans).css({ 'font-size': value + 'px' }); // [workaround] added styled bogus span for style // - also bogus character needed for cursor position if (firstSpan && !dom.nodeLength(firstSpan)) { firstSpan.innerHTML = dom.ZERO_WIDTH_NBSP_CHAR; range.createFromNodeAfter(firstSpan.firstChild).select(); $editable.data(KEY_BOGUS, firstSpan); } } else { beforeCommand(); $(style.styleNodes(rng)).css({ 'font-size': value + 'px' }); afterCommand(); } }; /** * insert horizontal rule */ this.insertHorizontalRule = this.wrapCommand(function () { var hrNode = this.createRange().insertNode(dom.create('HR')); if (hrNode.nextSibling) { range.create(hrNode.nextSibling, 0).normalize().select(); } }); context.memo('help.insertHorizontalRule', lang.help.insertHorizontalRule); /** * remove bogus node and character */ this.removeBogus = function () { var bogusNode = $editable.data(KEY_BOGUS); if (!bogusNode) { return; } var textNode = list.find(list.from(bogusNode.childNodes), dom.isText); var bogusCharIdx = textNode.nodeValue.indexOf(dom.ZERO_WIDTH_NBSP_CHAR); if (bogusCharIdx !== -1) { textNode.deleteData(bogusCharIdx, 1); } if (dom.isEmpty(bogusNode)) { dom.remove(bogusNode); } $editable.removeData(KEY_BOGUS); }; /** * lineHeight * @param {String} value */ this.lineHeight = this.wrapCommand(function (value) { style.stylePara(this.createRange(), { lineHeight: value }); }); /** * unlink * * @type command */ this.unlink = function () { var rng = this.createRange(); if (rng.isOnAnchor()) { var anchor = dom.ancestor(rng.sc, dom.isAnchor); rng = range.createFromNode(anchor); rng.select(); beforeCommand(); document.execCommand('unlink'); afterCommand(); } }; /** * create link (command) * * @param {Object} linkInfo */ this.createLink = this.wrapCommand(function (linkInfo) { var linkUrl = linkInfo.url; var linkText = linkInfo.text; var isNewWindow = linkInfo.isNewWindow; var rng = linkInfo.range || this.createRange(); var isTextChanged = rng.toString() !== linkText; if (options.onCreateLink) { linkUrl = options.onCreateLink(linkUrl); } var anchors = []; if (isTextChanged) { rng = rng.deleteContents(); var anchor = rng.insertNode($('<A>' + linkText + '</A>')[0]); anchors.push(anchor); } else { anchors = style.styleNodes(rng, { nodeName: 'A', expandClosestSibling: true, onlyPartialContains: true }); } $.each(anchors, function (idx, anchor) { $(anchor).attr('href', linkUrl); if (isNewWindow) { $(anchor).attr('target', '_blank'); } else { $(anchor).removeAttr('target'); } }); var startRange = range.createFromNodeBefore(list.head(anchors)); var startPoint = startRange.getStartPoint(); var endRange = range.createFromNodeAfter(list.last(anchors)); var endPoint = endRange.getEndPoint(); range.create( startPoint.node, startPoint.offset, endPoint.node, endPoint.offset ).select(); }); /** * returns link info * * @return {Object} * @return {WrappedRange} return.range * @return {String} return.text * @return {Boolean} [return.isNewWindow=true] * @return {String} [return.url=""] */ this.getLinkInfo = function () { var rng = this.createRange().expand(dom.isAnchor); // Get the first anchor on range(for edit). var $anchor = $(list.head(rng.nodes(dom.isAnchor))); return { range: rng, text: rng.toString(), isNewWindow: $anchor.length ? $anchor.attr('target') === '_blank' : false, url: $anchor.length ? $anchor.attr('href') : '' }; }; /** * setting color * * @param {Object} sObjColor color code * @param {String} sObjColor.foreColor foreground color * @param {String} sObjColor.backColor background color */ this.color = this.wrapCommand(function (colorInfo) { var foreColor = colorInfo.foreColor; var backColor = colorInfo.backColor; if (foreColor) { document.execCommand('foreColor', false, foreColor); } if (backColor) { document.execCommand('backColor', false, backColor); } }); /** * insert Table * * @param {String} dimension of table (ex : "5x5") */ this.insertTable = this.wrapCommand(function (dim) { var dimension = dim.split('x'); var rng = this.createRange().deleteContents(); rng.insertNode(table.createTable(dimension[0], dimension[1], options)); }); /** * float me * * @param {String} value */ this.floatMe = this.wrapCommand(function (value) { var $target = $(this.restoreTarget()); $target.css('float', value); }); /** * resize overlay element * @param {String} value */ this.resize = this.wrapCommand(function (value) { var $target = $(this.restoreTarget()); $target.css({ width: value * 100 + '%', height: '' }); }); /** * @param {Position} pos * @param {jQuery} $target - target element * @param {Boolean} [bKeepRatio] - keep ratio */ this.resizeTo = function (pos, $target, bKeepRatio) { var imageSize; if (bKeepRatio) { var newRatio = pos.y / pos.x; var ratio = $target.data('ratio'); imageSize = { width: ratio > newRatio ? pos.x : pos.y / ratio, height: ratio > newRatio ? pos.x * ratio : pos.y }; } else { imageSize = { width: pos.x, height: pos.y }; } $target.css(imageSize); }; /** * remove media object */ this.removeMedia = this.wrapCommand(function () { var $target = $(this.restoreTarget()).detach(); context.triggerEvent('media.delete', $target, $editable); }); /** * returns whether editable area has focus or not. */ this.hasFocus = function () { return $editable.is(':focus'); }; /** * set focus */ this.focus = function () { // [workaround] Screen will move when page is scolled in IE. // - do focus when not focused if (!this.hasFocus()) { $editable.focus(); } }; /** * returns whether contents is empty or not. * @return {Boolean} */ this.isEmpty = function () { return dom.isEmpty($editable[0]) || dom.emptyPara === $editable.html(); }; /** * Removes all contents and restores the editable instance to an _emptyPara_. */ this.empty = function () { context.invoke('code', dom.emptyPara); }; /** * set height for editable */ this.setHeight = function (height) { $editable.outerHeight(height); }; }; return Editor; });