芝麻web文件管理V1.00
编辑当前文件:/home/pulsehostuk9/public_html/cloud.pulsehost.co.uk/modules/MailWebclient/js/CCrea.js
'use strict' const _ = require('underscore'), $ = require('jquery') const App = require('%PathToCoreWebclientModule%/js/App.js'), Browser = require('%PathToCoreWebclientModule%/js/Browser.js'), ContenteditableUtils = require('%PathToCoreWebclientModule%/js/utils/Contenteditable.js'), Types = require('%PathToCoreWebclientModule%/js/utils/Types.js') const CreaUtils = require('modules/%ModuleName%/js/utils/Crea.js') /** * @constructor * * @param {Object} oOptions */ function CCrea(oOptions) { this.oOptions = _.extend( { creaId: 'creaId', fontNameArray: ['Tahoma'], defaultFontName: 'Tahoma', defaultFontSize: 3, alwaysTryUseImageWhilePasting: true, dropableArea: null, isRtl: false, onChange: function () {}, onCursorMove: function () {}, onFocus: function () {}, onBlur: function () {}, onUrlIn: function () {}, onUrlOut: function () {}, onImageSelect: function () {}, onImageBlur: function () {}, onItemOver: null, onItemOut: null, openInsertLinkDialog: function () {}, onUrlClicked: false, }, typeof oOptions === 'undefined' ? {} : oOptions ) } /** * @type {Object} */ CCrea.prototype.oOptions = {} /** * @type {Object} */ CCrea.prototype.$container = null /** * @type {Object} */ CCrea.prototype.$editableArea = null CCrea.prototype.aEditableAreaHtml = [] CCrea.prototype.iUndoRedoPosition = 0 CCrea.prototype.bEditable = false CCrea.prototype.bFocused = false /** * @type {Array} */ CCrea.prototype.aSizes = [ { inNumber: 1, inPixels: 10 }, { inNumber: 2, inPixels: 13 }, { inNumber: 3, inPixels: 16 }, { inNumber: 4, inPixels: 18 }, { inNumber: 5, inPixels: 24 }, { inNumber: 6, inPixels: 32 }, { inNumber: 7, inPixels: 48 }, ] CCrea.prototype.bInUrl = false CCrea.prototype.oCurrLink = null CCrea.prototype.oCurrImage = null CCrea.prototype.bInImage = false CCrea.prototype.sBasicFontName = '' CCrea.prototype.sBasicFontSize = '' CCrea.prototype.sBasicDirection = '' /** * Creates editable area. * * @param {boolean} bEditable */ CCrea.prototype.start = function (bEditable) { function isValidURL(sUrl) { var oRegExp = /^(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?$/ return oRegExp.test(sUrl) } function isCorrectEmail(sValue) { return !!sValue.match(/^[A-Z0-9\"!#\$%\^\{\}`~&'\+\-=_\.]+@[A-Z0-9\.\-]+$/i) } this.aRanges = null // if this.aRanges is not null first focus doesn't work properly, then insert image doesn't work this.$container = $('#' + this.oOptions.creaId) this.$editableArea = $('
') .addClass('crea-content-editable') .prop('contentEditable', 'true') .appendTo(this.$container) var self = this this.$editableArea.on('focus', function () { self.bFocused = true }) this.$editableArea.on('blur', function () { self.bFocused = false //self.editableSave(); //Undo/Redo fix }) this.$editableArea.on('click', 'img', function (ev) { var oImage = $(this) self.bInImage = true self.oCurrImage = oImage self.oOptions.onImageSelect(oImage, ev) ev.stopPropagation() }) this.$editableArea.on('click', function (ev) { self.bInImage = false self.oCurrImage = null self.oOptions.onImageBlur() }) if (self.oOptions.onItemOver !== null) { this.$editableArea.on('mouseover', function (ev) { self.oOptions.onItemOver(ev) }) } if (self.oOptions.onItemOver !== null) { this.$editableArea.on('mouseout', function (ev) { self.oOptions.onItemOut(ev) }) } this.$editableArea.on('cut paste', function () { self.editableSave() _.defer(function () { self.editableSave() }) }) this.$editableArea.on('paste', function (oEvent) { oEvent = oEvent.originalEvent || oEvent if (oEvent.clipboardData) { var sText = oEvent.clipboardData.getData('text/plain'), sHtml = oEvent.clipboardData.getData('text/html') if (self.oOptions.alwaysTryUseImageWhilePasting && self.pasteImage(oEvent)) { oEvent.preventDefault() } else { if (isValidURL(sText)) { oEvent.preventDefault() self.execCom('insertHTML', '
' + sText.replaceAll('&', '&') + '
') } else if (isCorrectEmail(sText)) { oEvent.preventDefault() self.execCom('insertHTML', '
' + sText.replaceAll('&', '&') + '
') } else if (sHtml !== '') { const preparedHtml = CreaUtils.preparePastedHtml(sHtml) if (preparedHtml) { oEvent.preventDefault() self.execCom('insertHTML', preparedHtml) } } } } }) this.$editableArea.on('keydown', function (oEvent) { var iKey = oEvent.keyCode || oEvent.which || oEvent.charCode || 0, bCtrlKey = oEvent.ctrlKey || oEvent.metaKey, bAltKey = oEvent.altKey, bShiftKey = oEvent.shiftKey, sLink = '' if ((bShiftKey && bCtrlKey && iKey === Enums.Key.z) || (bCtrlKey && iKey === Enums.Key.y)) { oEvent.preventDefault() self.editableRedo() } else if (bCtrlKey && !bAltKey && iKey === Enums.Key.z) { oEvent.preventDefault() self.editableUndo() } else if ( bCtrlKey && (iKey === Enums.Key.k || iKey === Enums.Key.b || iKey === Enums.Key.i || iKey === Enums.Key.u) ) { oEvent.preventDefault() switch (iKey) { case Enums.Key.k: sLink = self.getSelectedText() if (isValidURL(sLink)) { self.insertLink(sLink) } else if (isCorrectEmail(sLink)) { self.insertLink('mailto:' + sLink) } else { self.oOptions.openInsertLinkDialog() } break case Enums.Key.b: self.bold() break case Enums.Key.i: self.italic() break case Enums.Key.u: self.underline() break } } else if (!bAltKey && !bShiftKey && !bCtrlKey) { if (iKey === Enums.Key.Del || iKey === Enums.Key.Backspace) { self.editableSave() } } }) this.$editableArea.on('keyup', function (oEvent) { var iKey = oEvent.keyCode || oEvent.which || oEvent.charCode || 0, bCtrlKey = oEvent.ctrlKey || oEvent.metaKey, bAltKey = oEvent.altKey, bShiftKey = oEvent.shiftKey if (!bAltKey && !bShiftKey && !bCtrlKey) { if ( iKey === Enums.Key.Space || iKey === Enums.Key.Enter || iKey === Enums.Key.Del || iKey === Enums.Key.Backspace ) { self.editableSave() } else { self.oOptions.onChange() } } }) this.initContentEditable() this.setEditable(bEditable) App.broadcastEvent('%ModuleName%::StartCrea::after', { EditableArea: this.$editableArea, InsertHtmlHandler: this.insertHtml.bind(this), }) } CCrea.prototype.clearUndoRedo = function () { this.aEditableAreaHtml = [] this.iUndoRedoPosition = 0 } CCrea.prototype.isUndoAvailable = function () { return this.iUndoRedoPosition > 0 } CCrea.prototype.clearRedo = function () { this.aEditableAreaHtml = this.aEditableAreaHtml.slice(0, this.iUndoRedoPosition + 1) } CCrea.prototype.editableSave = function () { var sEditableHtml = this.$editableArea.html(), oLastSaved = _.last(this.aEditableAreaHtml), sLastSaved = oLastSaved ? oLastSaved[0] : '' if (sEditableHtml !== sLastSaved) { this.clearRedo() this.aEditableAreaHtml.push([sEditableHtml, this.getCaretPos(this.$editableArea[0])]) this.iUndoRedoPosition = this.aEditableAreaHtml.length - 1 this.oOptions.onChange() } } CCrea.prototype.editableUndo = function () { var sEditableHtml = this.$editableArea.html(), oCurrSaved = this.aEditableAreaHtml[this.iUndoRedoPosition], sCurrSaved = oCurrSaved ? oCurrSaved[0] : '' if (sEditableHtml !== sCurrSaved) { this.editableSave() } if (this.iUndoRedoPosition > 0) { this.iUndoRedoPosition-- this.$editableArea.html(this.aEditableAreaHtml[this.iUndoRedoPosition]) this.setCaretPos(this.$editableArea[0], this.aEditableAreaHtml[this.iUndoRedoPosition][1]) } } CCrea.prototype.editableRedo = function () { if (this.iUndoRedoPosition < this.aEditableAreaHtml.length - 1) { this.iUndoRedoPosition++ this.$editableArea.html(this.aEditableAreaHtml[this.iUndoRedoPosition]) this.setCaretPos( this.$editableArea[0], this.aEditableAreaHtml[this.iUndoRedoPosition] ? this.aEditableAreaHtml[this.iUndoRedoPosition][1] : {} ) } } CCrea.prototype.getCaretPos = function (oContainerEl) { var oSel = null, oRange = {}, oPreSelectionRange = {}, iStart = 0, oCaretPos = {} if (window.getSelection && document.createRange) { oSel = window.getSelection() if (oSel.rangeCount > 0) { oRange = oSel.getRangeAt(0) oPreSelectionRange = oRange.cloneRange() oPreSelectionRange.selectNodeContents(oContainerEl) oPreSelectionRange.setEnd(oRange.startContainer, oRange.startOffset) iStart = oPreSelectionRange.toString().length oCaretPos = { start: iStart, end: iStart + oRange.toString().length, } } } else if (document.selection && document.body.createTextRange) { oRange = document.selection.createRange() oPreSelectionRange = document.body.createTextRange() oPreSelectionRange.moveToElementText(oContainerEl) if (typeof oPreSelectionRange.setEndPoint === 'function') { oPreSelectionRange.setEndPoint('EndToStart', oRange) } iStart = oPreSelectionRange.text.length oCaretPos = { start: iStart, end: iStart + oRange.text.length, } } return oCaretPos } CCrea.prototype.setCaretPos = function (oContainerEl, oSavedSel) { if (window.getSelection && document.createRange) { var oNodeStack = [oContainerEl], oNode = {}, oSel = {}, bFoundStart = false, bStop = false, iCharIndex = 0, iNextCharIndex = 0, iChildNodes = 0, oRange = document.createRange() oRange.setStart(oContainerEl, 0) oRange.collapse(true) oNode = oNodeStack.pop() while (!bStop && oNode) { if (oNode.nodeType === 3) { iNextCharIndex = iCharIndex + oNode.length if (!bFoundStart && oSavedSel.start >= iCharIndex && oSavedSel.start <= iNextCharIndex) { oRange.setStart(oNode, oSavedSel.start - iCharIndex) bFoundStart = true } if (bFoundStart && oSavedSel.end >= iCharIndex && oSavedSel.end <= iNextCharIndex) { oRange.setEnd(oNode, oSavedSel.end - iCharIndex) bStop = true } iCharIndex = iNextCharIndex } else { iChildNodes = oNode.childNodes.length while (iChildNodes--) { oNodeStack.push(oNode.childNodes[iChildNodes]) } } oNode = oNodeStack.pop() } oSel = window.getSelection() oSel.removeAllRanges() oSel.addRange(oRange) } else if (document.selection && document.body.createTextRange) { var oTextRange = document.body.createTextRange() oTextRange.moveToElementText(oContainerEl) oTextRange.collapse(true) oTextRange.moveEnd('character', oSavedSel.end) oTextRange.moveStart('character', oSavedSel.start) oTextRange.select() } } /** * Sets tab index. * * @param {string} sTabIndex */ CCrea.prototype.setTabIndex = function (sTabIndex) { if (sTabIndex) { this.$editableArea.attr('tabindex', sTabIndex) } } /** * Initializes properties. */ CCrea.prototype.initContentEditable = function () { this.$editableArea.bind({ mousemove: _.bind(this.storeSelectionPosition, this), mouseup: _.bind(this.onCursorMove, this), keydown: _.bind(this.onButtonPressed, this), keyup: _.bind(this.onCursorMove, this), click: _.bind(this.onClickWith, this), focus: this.oOptions.onFocus, blur: this.oOptions.onBlur, }) if (window.File && window.FileReader && window.FileList) { if (this.oOptions.enableDrop) { this.$editableArea.bind({ dragover: _.bind(this.onDragOver, this), dragleave: _.bind(this.onDragLeave, this), drop: _.bind(this.onFileSelect, this), }) } } var self = this, lazyScroll = _.debounce(function () { self.oCurrLink = null self.bInUrl = false self.oOptions.onUrlOut() }, 300) $('html, body').on('scroll', lazyScroll) } /** * Starts cursor move handlers. * @param {Object} ev */ CCrea.prototype.onCursorMove = function (ev) { var iKey = -1 if (window.event) { iKey = window.event.keyCode } else if (ev) { iKey = ev.which } if (iKey === 13) { // Enter this.breakQuotes(ev) } if (iKey === 17) { // Cntr this.$editableArea.find('a').css('cursor', 'inherit') } if (iKey === 8) { // BackSpace this.uniteWithNextQuote(ev) } if (iKey === 46 && Browser.chrome) { // Delete this.uniteWithPrevQuote(ev) } this.storeSelectionPosition() this.oOptions.onCursorMove() } /** * Starts when clicked. * @param {Object} oEvent */ CCrea.prototype.onClickWith = function (oEvent) { if (oEvent.ctrlKey) { if (oEvent.target.nodeName === 'A') { window.open(oEvent.target.href, '_blank') } } this.checkAnchorNode() } /** * Starts when key pressed. * @param {Object} oEvent */ CCrea.prototype.onButtonPressed = function (oEvent) { var iKey = -1 if (window.event) { iKey = window.event.keyCode } else if (oEvent) { iKey = oEvent.which } if (iKey === 17) { // Cntr this.$editableArea.find('a').css('cursor', 'pointer') } } /** * Starts cursor move handlers. * @param {Object} oEvent */ CCrea.prototype.onFileSelect = function (oEvent) { oEvent = (oEvent && oEvent.originalEvent ? oEvent.originalEvent : oEvent) || window.event if (oEvent) { oEvent.stopPropagation() oEvent.preventDefault() var oReader = null, oFile = null, aFiles = oEvent.files || (oEvent.dataTransfer ? oEvent.dataTransfer.files : null), self = this if (aFiles && 1 === aFiles.length && this.checkIsImage(aFiles[0])) { oFile = aFiles[0] oReader = new window.FileReader() oReader.onload = (function () { return function (oEvent) { self.insertImage(oEvent.target.result) } })() oReader.readAsDataURL(oFile) } } } CCrea.prototype.onDragLeave = function () { this.$editableArea.removeClass('editorDragOver') } /** * @param {Object} oEvent */ CCrea.prototype.onDragOver = function (oEvent) { oEvent.stopPropagation() oEvent.preventDefault() this.$editableArea.addClass('editorDragOver') } /** * @param {Object} oEvent * @returns {Boolean} */ CCrea.prototype.pasteImage = function (oEvent) { var oClipboardItems = oEvent.clipboardData && oEvent.clipboardData.items, self = this, bImagePasted = false if (window.File && window.FileReader && window.FileList && oClipboardItems) { _.each(oClipboardItems, function (oItem) { if (self.checkIsImage(oItem) && oItem['getAsFile']) { var oReader = null, oFile = oItem['getAsFile']() if (oFile) { oReader = new window.FileReader() oReader.onload = (function () { return function (oEvent) { self.insertImage(oEvent.target.result) } })() oReader.readAsDataURL(oFile) bImagePasted = true } } }) } return bImagePasted } /** * @param {Object} oItem * @return {boolean} */ CCrea.prototype.checkIsImage = function (oItem) { return oItem && oItem.type && 0 === oItem.type.indexOf('image/') } /** * Sets plain text to rich editor. * * @param {string} sText */ CCrea.prototype.setPlainText = function (sText) { if (typeof sText !== 'string') { sText = '' } if (this.$editableArea) { this.editableSave() this.$editableArea.empty().text(sText).css('white-space', 'pre') this.editableSave() } } /** * Sets text to rich editor. * * @param {string} sText */ CCrea.prototype.setText = function (sText) { if (typeof sText !== 'string') { sText = '' } if (this.$editableArea) { if (sText.length === 0) { sText = '
' } const preparedHtml = this.prepareHtmlWithoutWrappers(sText) this.$editableArea.empty().append(preparedHtml).css('white-space', 'normal') this.clearUndoRedo() this.editableSave() } } CCrea.prototype.prepareHtmlWithoutWrappers = function (html) { let outerNode = $(html) let isOuterElemChanged = false while ( outerNode.length === 1 && (outerNode.data('x-div-type') === 'html' || outerNode.data('x-div-type') === 'body') ) { outerNode = outerNode.children() isOuterElemChanged = true } if (outerNode.length === 1 && outerNode.data('crea') === 'font-wrapper') { this.setBasicStyles(outerNode.css('font-family'), outerNode.css('font-size'), outerNode.css('direction')) return outerNode.html() } this.setBasicStyles( this.oOptions.defaultFontName, this.convertFontSizeToPixels(this.oOptions.defaultFontSize), this.oOptions.isRtl ? 'rtl' : 'ltr' ) if (!isOuterElemChanged) { return html } else { let res = '' outerNode.each((index, elem) => { res += elem.outerHTML }) return res } } /** * @param {string} sFontName * @param {string} sFontSize * @param {string} sDirection */ CCrea.prototype.setBasicStyles = function (sFontName, sFontSize, sDirection) { this.sBasicFontName = sFontName this.sBasicFontSize = sFontSize this.sBasicDirection = sDirection this.$editableArea.css({ 'font-family': this.getFontNameWithFamily(this.sBasicFontName), 'font-size': this.sBasicFontSize, direction: this.sBasicDirection, }) } /** * Gets plain text from rich editor. * * @return {string} */ CCrea.prototype.getPlainText = function () { var sVal = '' if (this.$editableArea) { sVal = this.$editableArea .html() .replace(/([^>]{1})
/gi, '$1\n') .replace(/