芝麻web文件管理V1.00
编辑当前文件:/home/pulsehostuk9/www/cloud.pulsehost.co.uk/modules/MailWebclient/js/views/CHtmlEditorView.js
'use strict' const _ = require('underscore'), $ = require('jquery'), ko = require('knockout') const AddressUtils = require('%PathToCoreWebclientModule%/js/utils/Address.js'), TextUtils = require('%PathToCoreWebclientModule%/js/utils/Text.js'), Types = require('%PathToCoreWebclientModule%/js/utils/Types.js') const App = require('%PathToCoreWebclientModule%/js/App.js'), Browser = require('%PathToCoreWebclientModule%/js/Browser.js'), CJua = require('%PathToCoreWebclientModule%/js/CJua.js'), UserSettings = require('%PathToCoreWebclientModule%/js/Settings.js') const Popups = require('%PathToCoreWebclientModule%/js/Popups.js'), AlertPopup = require('%PathToCoreWebclientModule%/js/popups/AlertPopup.js'), ConfirmPopup = require('%PathToCoreWebclientModule%/js/popups/ConfirmPopup.js') const CAttachmentModel = require('modules/%ModuleName%/js/models/CAttachmentModel.js'), CColorPickerView = require('modules/%ModuleName%/js/views/CColorPickerView.js'), CCrea = require('modules/%ModuleName%/js/CCrea.js'), MailCache = require('modules/%ModuleName%/js/Cache.js'), Settings = require('modules/%ModuleName%/js/Settings.js'), TemplatesUtils = require('modules/%ModuleName%/js/utils/Templates.js'), sourceEditor = require('modules/%ModuleName%/js/views/html-editor/SourceEditor.js') /** * @constructor * @param {boolean} bInsertImageAsBase64 * @param {boolean} bAllowComposePlainText * @param {Object=} oParent */ function CHtmlEditorView(bInsertImageAsBase64, bAllowComposePlainText, oParent) { this.oParent = oParent this.creaId = 'creaId' + Math.random().toString().replace('.', '') this.textFocused = ko.observable(false) this.workareaDom = ko.observable() this.plaintextDom = ko.observable() this.uploaderAreaDom = ko.observable() this.editorUploaderBodyDragOver = ko.observable(false) this.htmlEditorDom = ko.observable() this.toolbarDom = ko.observable() this.colorPickerDropdownDom = ko.observable() this.insertLinkDropdownDom = ko.observable() this.insertImageDropdownDom = ko.observable() this.isFWBold = ko.observable(false) this.isFSItalic = ko.observable(false) this.isTDUnderline = ko.observable(false) this.isTDStrikeThrough = ko.observable(false) this.isEnumeration = ko.observable(false) this.isBullets = ko.observable(false) this.isEnable = ko.observable(true) this.isEnable.subscribe(function () { if (this.oCrea) { this.oCrea.setEditable(this.isEnable()) } }, this) this.bInsertImageAsBase64 = bInsertImageAsBase64 this.bAllowFileUpload = !(bInsertImageAsBase64 && window.File === undefined) this.bAllowInsertImage = Settings.AllowInsertImage this.bAllowHorizontalLineButton = Settings.AllowHorizontalLineButton this.bAllowComposePlainText = bAllowComposePlainText this.plainTextMode = ko.observable(false) this.changeTextModeTitle = ko.computed(function () { return this.plainTextMode() ? TextUtils.i18n('%MODULENAME%/LINK_TURNOFF_PLAINTEXT') : TextUtils.i18n('%MODULENAME%/LINK_TURNON_PLAINTEXT') }, this) this.bAllowEditHtmlSource = Settings.AllowEditHtmlSource this.editSourceMode = ko.observable(false) this.htmlSourceDom = ko.observable() this.htmlSourceDom.subscribe(() => { sourceEditor.setHtmlSourceDom(this.htmlSourceDom()) }) this.sourceCodeButtonText = ko.computed(() => { return this.editSourceMode() ? TextUtils.i18n('%MODULENAME%/ACTION_EDIT_HTML_PREVIEW') : TextUtils.i18n('%MODULENAME%/ACTION_EDIT_HTML_SOURCE_CODE') }) this.lockFontSubscribing = ko.observable(false) this.bAllowImageDragAndDrop = !Browser.ie10AndAbove this.aFonts = ['Arial', 'Arial Black', 'Courier New', 'Tahoma', 'Times New Roman', 'Verdana'] this.sDefaultFont = Settings.DefaultFontName this.correctFontFromSettings() this.selectedFont = ko.observable('') this.selectedFont.subscribe(function () { if (this.oCrea && !this.lockFontSubscribing() && !this.inactive()) { this.oCrea.fontName(this.selectedFont()) } }, this) this.iDefaultSize = Settings.DefaultFontSize this.selectedSize = ko.observable(0) this.selectedSize.subscribe(function () { if (this.oCrea && !this.lockFontSubscribing() && !this.inactive()) { this.oCrea.fontSize(this.selectedSize()) } }, this) this.visibleInsertLinkPopup = ko.observable(false) this.linkForInsert = ko.observable('') this.linkFocused = ko.observable(false) this.visibleLinkPopup = ko.observable(false) this.linkPopupDom = ko.observable(null) this.linkHrefDom = ko.observable(null) this.linkHref = ko.observable('') this.visibleLinkHref = ko.observable(false) this.visibleImagePopup = ko.observable(false) this.visibleImagePopup.subscribe(function () { this.onImageOut() }, this) this.imagePopupTop = ko.observable(0) this.imagePopupLeft = ko.observable(0) this.imageSelected = ko.observable(false) this.tooltipText = ko.observable('') this.tooltipPopupTop = ko.observable(0) this.tooltipPopupLeft = ko.observable(0) this.visibleInsertImagePopup = ko.observable(false) this.imageUploaderButton = ko.observable(null) this.aUploadedImagesData = [] this.imagePathFromWeb = ko.observable('') this.visibleTemplatePopup = ko.observable(false) this.visibleFontColorPopup = ko.observable(false) this.oFontColorPickerView = new CColorPickerView( TextUtils.i18n('%MODULENAME%/LABEL_TEXT_COLOR'), this.setTextColorFromPopup, this ) this.oBackColorPickerView = new CColorPickerView( TextUtils.i18n('%MODULENAME%/LABEL_BACKGROUND_COLOR'), this.setBackColorFromPopup, this ) this.inactive = ko.observable(false) this.sPlaceholderText = '' this.bAllowChangeInputDirection = UserSettings.IsRTL || Settings.AllowChangeInputDirection this.disableEdit = ko.observable(false) this.textChanged = ko.observable(false) this.actualTextChanged = ko.observable(false) this.templates = ko.observableArray([]) TemplatesUtils.initTemplatesSubscription(this.templates) this.imageResizeOptions = [] _.each(Settings.ImageResizerOptions, (value, label) => { this.imageResizeOptions.push({ label: TextUtils.i18n(label), value: value, }) }) } CHtmlEditorView.prototype.ViewTemplate = '%ModuleName%_HtmlEditorView' CHtmlEditorView.prototype.setInactive = function (bInactive) { this.inactive(bInactive) if (this.inactive()) { if (this.editSourceMode()) { this.toggleSourceEdit() } this.setPlaceholder() } else { this.removePlaceholder() } } CHtmlEditorView.prototype.setPlaceholder = function () { var sText = this.removeAllTags(this.getText()) if (sText === '' || sText === ' ') { this.setText('
' + this.sPlaceholderText + '
') if (this.oCrea) { this.oCrea.setBlur() } } } CHtmlEditorView.prototype.removePlaceholder = function () { var sText = this.oCrea ? this.removeAllTags(this.oCrea.getText(false)) : '' if (sText === this.sPlaceholderText) { this.setText('') if (this.oCrea) { this.oCrea.setFocus(true) } } } CHtmlEditorView.prototype.hasOpenedPopup = function () { return ( this.visibleInsertLinkPopup() || this.visibleLinkPopup() || this.visibleImagePopup() || this.visibleInsertImagePopup() || this.visibleFontColorPopup() || this.visibleTemplatePopup() ) } CHtmlEditorView.prototype.setDisableEdit = function (bDisableEdit) { this.disableEdit(!!bDisableEdit) } CHtmlEditorView.prototype.correctFontFromSettings = function () { var sDefaultFont = this.sDefaultFont, bFound = false _.each(this.aFonts, function (sFont) { if (sFont.toLowerCase() === sDefaultFont.toLowerCase()) { sDefaultFont = sFont bFound = true } }) if (bFound) { this.sDefaultFont = sDefaultFont } else { this.aFonts.push(sDefaultFont) } } /** * @param {Object} $link */ CHtmlEditorView.prototype.showLinkPopup = function ($link) { var $workarea = $(this.workareaDom()), $composePopup = $workarea.closest('.panel.compose'), oWorkareaPos = $workarea.position(), oPos = $link.position(), iHeight = $link.height(), iLeft = Math.round(oPos.left + oWorkareaPos.left), iTop = Math.round(oPos.top + iHeight + oWorkareaPos.top) this.linkHref($link.attr('href') || $link.text()) $(this.linkPopupDom()).css({ left: iLeft, top: iTop, }) $(this.linkHrefDom()).css({ left: iLeft, top: iTop, }) if (!Browser.firefox && $composePopup.length === 1) { $(this.linkPopupDom()).css({ 'max-width': $composePopup.width() - iLeft - 40 + 'px', 'white-space': 'pre-line', 'word-wrap': 'break-word', }) } this.visibleLinkPopup(true) } CHtmlEditorView.prototype.hideLinkPopup = function () { this.visibleLinkPopup(false) } CHtmlEditorView.prototype.showChangeLink = function () { this.visibleLinkHref(true) this.hideLinkPopup() } CHtmlEditorView.prototype.changeLink = function () { this.oCrea.changeLink(this.linkHref()) this.hideChangeLink() } CHtmlEditorView.prototype.hideChangeLink = function () { this.visibleLinkHref(false) } /** * @param {jQuery} $image * @param {Object} oEvent */ CHtmlEditorView.prototype.showImagePopup = function ($image, oEvent) { var $workarea = $(this.workareaDom()), oWorkareaPos = $workarea.position(), oWorkareaOffset = $workarea.offset() this.imagePopupLeft(Math.round(oEvent.pageX + oWorkareaPos.left - oWorkareaOffset.left)) this.imagePopupTop(Math.round(oEvent.pageY + oWorkareaPos.top - oWorkareaOffset.top)) this.visibleImagePopup(true) } CHtmlEditorView.prototype.hideImagePopup = function () { this.visibleImagePopup(false) } CHtmlEditorView.prototype.resizeImage = function (sSize) { var oParams = { width: 'auto', height: 'auto', } if (sSize) { oParams.width = sSize } this.oCrea.changeCurrentImage(oParams) this.visibleImagePopup(false) } CHtmlEditorView.prototype.onImageOver = function (oEvent) { if (oEvent.target.nodeName === 'IMG' && !this.visibleImagePopup()) { this.imageSelected(true) this.tooltipText(TextUtils.i18n('%MODULENAME%/ACTION_CLICK_TO_EDIT_IMAGE')) var self = this, $workarea = $(this.workareaDom()) $workarea.bind('mousemove.image', function (oEvent) { var oWorkareaPos = $workarea.position(), oWorkareaOffset = $workarea.offset() self.tooltipPopupTop(Math.round(oEvent.pageY + oWorkareaPos.top - oWorkareaOffset.top)) self.tooltipPopupLeft(Math.round(oEvent.pageX + oWorkareaPos.left - oWorkareaOffset.left)) }) } return true } CHtmlEditorView.prototype.onImageOut = function (oEvent) { if (this.imageSelected()) { this.imageSelected(false) var $workarea = $(this.workareaDom()) $workarea.unbind('mousemove.image') } return true } CHtmlEditorView.prototype.commit = function () { this.textChanged(false) } /** * @param {string} sText * @param {boolean} bPlain * @param {string} sTabIndex * @param {string} sPlaceholderText */ CHtmlEditorView.prototype.init = function (sText, bPlain, sTabIndex, sPlaceholderText) { this.sPlaceholderText = sPlaceholderText || '' if (this.oCrea) { this.oCrea.$container = $('#' + this.oCrea.oOptions.creaId) // in case if knockoutjs destroyed dom element with html editor if (this.oCrea.$container.children().length === 0) { this.oCrea.start(this.isEnable()) // this.editorUploader must be re-initialized because compose popup is destroyed after it is closed this.initEditorUploader() } } else { $(document.body).on( 'click', _.bind(function (oEvent) { var oParent = $(oEvent.target).parents('span.dropdown_helper') if (oParent.length === 0) { this.closeAllPopups(true) } }, this) ) this.initEditorUploader() this.oCrea = new CCrea({ creaId: this.creaId, fontNameArray: this.aFonts, defaultFontName: this.sDefaultFont, defaultFontSize: this.iDefaultSize, alwaysTryUseImageWhilePasting: Settings.AlwaysTryUseImageWhilePasting, isRtl: UserSettings.IsRTL, enableDrop: false, onChange: _.bind(function () { this.textChanged(true) this.actualTextChanged.valueHasMutated() }, this), onCursorMove: _.bind(this.setFontValuesFromText, this), onFocus: _.bind(this.onCreaFocus, this), onBlur: _.bind(this.onCreaBlur, this), onUrlIn: _.bind(this.showLinkPopup, this), onUrlOut: _.bind(this.hideLinkPopup, this), onImageSelect: _.bind(this.showImagePopup, this), onImageBlur: _.bind(this.hideImagePopup, this), onItemOver: Browser.mobileDevice || App.isMobile() ? null : _.bind(this.onImageOver, this), onItemOut: Browser.mobileDevice || App.isMobile() ? null : _.bind(this.onImageOut, this), openInsertLinkDialog: _.bind(this.insertLink, this), onUrlClicked: true, }) this.oCrea.start(this.isEnable()) sourceEditor.setOnChangeHandler(() => { this.textChanged(true) this.actualTextChanged.valueHasMutated() }) } if (this.plaintextDom()) { this.plaintextDom().on('keyup paste', () => { this.textChanged(true) this.actualTextChanged.valueHasMutated() }) } this.oCrea.setTabIndex(sTabIndex) this.clearUndoRedo() this.editSourceMode(false) sourceEditor.clear() this.setText(sText, bPlain) this.setFontValuesFromText() this.aUploadedImagesData = [] this.selectedFont(this.sDefaultFont) this.selectedSize(this.iDefaultSize) TemplatesUtils.fillTemplatesOptions(this.templates) } CHtmlEditorView.prototype.toggleTemplatePopup = function (oViewModel, oEvent) { if (this.visibleTemplatePopup()) { this.visibleTemplatePopup(false) } else { oEvent.stopPropagation() this.closeAllPopups() this.visibleTemplatePopup(true) } } CHtmlEditorView.prototype.insertTemplate = function (sHtml, oEvent) { oEvent.stopPropagation() this.insertHtml(sHtml) } CHtmlEditorView.prototype.isInitialized = function () { return !!this.oCrea } CHtmlEditorView.prototype.setFocus = function () { if (this.oCrea) { this.oCrea.setFocus(false) } } /** * @param {string} sNewSignatureContent * @param {string} sOldSignatureContent */ CHtmlEditorView.prototype.changeSignatureContent = function (sNewSignatureContent, sOldSignatureContent) { if (this.oCrea && !this.disableEdit()) { this.oCrea.changeSignatureContent(sNewSignatureContent, sOldSignatureContent) } } CHtmlEditorView.prototype.setFontValuesFromText = function () { this.lockFontSubscribing(true) this.isFWBold(this.oCrea.getIsBold()) this.isFSItalic(this.oCrea.getIsItalic()) this.isTDUnderline(this.oCrea.getIsUnderline()) this.isTDStrikeThrough(this.oCrea.getIsStrikeThrough()) this.isEnumeration(this.oCrea.getIsEnumeration()) this.isBullets(this.oCrea.getIsBullets()) this.selectedFont(this.oCrea.getFontName()) this.selectedSize(this.oCrea.getFontSizeInNumber().toString()) this.lockFontSubscribing(false) } CHtmlEditorView.prototype.isUndoAvailable = function () { if (this.oCrea) { return this.oCrea.isUndoAvailable() } return false } CHtmlEditorView.prototype.getPlainText = function () { if (this.oCrea) { return this.oCrea.getPlainText() } return '' } /** * @param {boolean=} bRemoveSignatureAnchor = false */ CHtmlEditorView.prototype.getText = function (bRemoveSignatureAnchor) { if (this.plainTextMode()) { return this.plaintextDom() ? this.plaintextDom().val() : '' } if (this.editSourceMode() && sourceEditor.isInitialized()) { return sourceEditor.getText() } const sText = this.oCrea ? this.oCrea.getText(bRemoveSignatureAnchor) : '' return this.sPlaceholderText !== '' && this.removeAllTags(sText) === this.sPlaceholderText ? '' : sText } CHtmlEditorView.prototype.getEditableArea = function () { return this.oCrea.$editableArea } /** * @param {string} sText * @param {boolean} bPlain */ CHtmlEditorView.prototype.setText = function (sText, bPlain = null) { if (this.oCrea && !this.disableEdit()) { if (bPlain !== null) { this.plainTextMode(!!bPlain) } if (this.plainTextMode()) { if (TextUtils.isHtml(sText)) { sText = TextUtils.htmlToPlain(sText) } this.plaintextDom().val(sText) } else { if (!TextUtils.isHtml(sText)) { sText = TextUtils.plainToHtml(sText) } this.oCrea.setText(sText) } if (this.inactive() && sText === '') { this.setPlaceholder() } } } CHtmlEditorView.prototype.undoAndClearRedo = function () { if (this.oCrea) { this.oCrea.undo() this.oCrea.clearRedo() } } CHtmlEditorView.prototype.clearUndoRedo = function () { if (this.oCrea) { this.oCrea.clearUndoRedo() } } /** * @param {string} sText */ CHtmlEditorView.prototype.removeAllTags = function (sText) { return sText.replace(/