📄 xquared.js
字号:
* @param {String} id unique identifier */ removeTemplateProcessor: function(id) {delete this.config.templateProcessors[id];}, /** * Adds or replaces context menu handler. * * @param {String} id unique identifier * @param {Object} handler string or function to be evaluated or called when onContextMenu occured */ addContextMenuHandler: function(id, handler) { this.config.contextMenuHandlers[id] = {"handler":handler}; }, /** * Adds several context menu handlers at once. * * @param {Array} list of handlers. Each element should have following structure: {id:"identifier", handler:handler} */ addContextMenuHandlers: function(list) { for(var i = 0; i < list.length; i++) { this.addContextMenuHandler(list[i].id, list[i].handler); } }, /** * Returns context menu handler matches with given id * * @param {String} id unique identifier */ getContextMenuHandler: function(id) {return this.config.contextMenuHandlers[id];}, /** * Returns entire context menu handlers' map */ getContextMenuHandlers: function() {return this.config.contextMenuHandlers;}, /** * Removes context menu handler matches with given id * * @param {String} id unique identifier */ removeContextMenuHandler: function(id) {delete this.config.contextMenuHandlers[id];}, ///////////////////////////////////////////// // Edit mode management /** * Returns current edit mode - readonly, wysiwyg, source */ getCurrentEditMode: function() { return this.currentEditMode; }, toggleSourceAndWysiwygMode: function() { var mode = this.getCurrentEditMode(); if(mode == 'readonly') return; this.setEditMode(mode == 'wysiwyg' ? 'source' : 'wysiwyg'); return true; }, /** * Switches between edit-mode/normal mode. * * @param {Object} mode false or 'readonly' means read-only mode, true or 'wysiwyg' means WYSIWYG editing mode, and 'source' means source editing mode. */ setEditMode: function(mode) { if(this.currentEditMode == mode) return; var firstCall = mode != false && mode != 'readonly' && !this.outmostWrapper; if(firstCall) { // Create editor element if needed this._createEditorFrame(); this._registerEventHandlers(); this.loadCurrentContentFromStaticContent(); this.editHistory = new xq.EditHistory(this.rdom); } if(mode == 'wysiwyg') { // Update contents if(this.currentEditMode == 'source') this.setStaticContent(this.getSourceContent()); this.loadCurrentContentFromStaticContent(); // Make static content invisible this.contentElement.style.display = "none"; // Make WYSIWYG editor visible this.sourceEditorDiv.style.display = "none"; this.wysiwygEditorDiv.style.display = "block"; this.outmostWrapper.style.display = "block"; this.currentEditMode = mode; if(!xq.Browser.isTrident) { window.setTimeout(function() { if(this.getDoc().designMode == 'On') return; // Without it, Firefox doesn't display embedded SWF this.getDoc().designMode = 'On'; // turn off Firefox's table editing feature try {this.getDoc().execCommand("enableInlineTableEditing", false, "false")} catch(ignored) {} }.bind(this), 0); } this.enableToolbarButtons(); if(!firstCall) this.focus(); } else if(mode == 'source') { // Update contents if(this.currentEditMode == 'wysiwyg') this.setStaticContent(this.getWysiwygContent()); this.loadCurrentContentFromStaticContent(); // Make static content invisible this.contentElement.style.display = "none"; // Make source editor visible this.sourceEditorDiv.style.display = "block"; this.wysiwygEditorDiv.style.display = "none"; this.outmostWrapper.style.display = "block"; this.currentEditMode = mode; this.disableToolbarButtons(['html']); if(!firstCall) this.focus(); } else { // Update contents this.setStaticContent(this.getCurrentContent()); this.loadCurrentContentFromStaticContent(); // Make editor and toolbar invisible this.outmostWrapper.style.display = "none"; // Make static content visible this.contentElement.style.display = "block"; this.currentEditMode = mode; } this._fireOnCurrentEditModeChanged(this, mode); }, /** * Load CSS into editing-mode document * * @param {string} path URL */ loadStylesheet: function(path) { var head = this.editorDoc.getElementsByTagName("HEAD")[0]; var link = this.editorDoc.createElement("LINK"); link.rel = "Stylesheet"; link.type = "text/css"; link.href = path; head.appendChild(link); }, /** * Sets editor's dynamic content from static content */ loadCurrentContentFromStaticContent: function() { // update WYSIWYG editor var html = this.validator.invalidate(this.getStaticContentAsDOM()); html = this.removeUnnecessarySpaces(html); if(html.blank()) { this.rdom.clearRoot(); } else { this.rdom.getRoot().innerHTML = html; } this.rdom.wrapAllInlineOrTextNodesAs("P", this.rdom.getRoot(), true); // update source editor var source = this.getWysiwygContent(true, true); this.sourceEditorTextarea.value = source; if(xq.Browser.isWebkit) { this.sourceEditorTextarea.innerHTML = source; } this._fireOnCurrentContentChanged(this); }, /** * Enables all toolbar buttons * * @param {Array} [exceptions] array of string containing classnames to exclude */ enableToolbarButtons: function(exceptions) { if(!this.toolbarContainer) return; this._execForAllToolbarButtons(exceptions, function(li, exception) { li.firstChild.className = !exception ? '' : 'disabled'; }); // Toolbar image icon disappears without following code: if(xq.Browser.isIE6) { this.toolbarContainer.style.display = 'none'; setTimeout(function() {this.toolbarContainer.style.display = 'block';}.bind(this), 0); } }, /** * Disables all toolbar buttons * * @param {Array} [exceptions] array of string containing classnames to exclude */ disableToolbarButtons: function(exceptions) { this._execForAllToolbarButtons(exceptions, function(li, exception) { li.firstChild.className = exception ? '' : 'disabled'; }); }, _execForAllToolbarButtons: function(exceptions, exec) { if(!this.toolbarContainer) return; exceptions = exceptions || []; var lis = this.toolbarContainer.getElementsByTagName('LI'); for(var i = 0; i < lis.length; i++) { var buttonsClassName = lis[i].className.split(" ").find(function(name) {return name != 'xq_separator'}); var exception = exceptions.indexOf(buttonsClassName) != -1; exec(lis[i], exception); } }, _updateToolbarButtonStatus: function(buttonClassName, selected) { var button = this.toolbarButtons[buttonClassName]; if(button) button.firstChild.firstChild.className = selected ? 'selected' : ''; }, updateAllToolbarButtonsStatus: function(element) { if(!this.toolbarContainer) return; if(!this.toolbarButtons) { var classNames = [ "emphasis", "strongEmphasis", "underline", "strike", "superscription", "subscription", "justifyLeft", "justifyCenter", "justifyRight", "justifyBoth", "unorderedList", "orderedList", "code", "paragraph", "heading1", "heading2", "heading3", "heading4", "heading5", "heading6" ]; this.toolbarButtons = {}; for(var i = 0; i < classNames.length; i++) { var found = xq.getElementsByClassName(this.toolbarContainer, classNames[i]); var button = found && found.length > 0 ? found[0] : null; if(button) this.toolbarButtons[classNames[i]] = button; } } var buttons = this.toolbarButtons; var info = this.rdom.collectStructureAndStyle(element); this._updateToolbarButtonStatus('emphasis', info.em); this._updateToolbarButtonStatus('strongEmphasis', info.strong); this._updateToolbarButtonStatus('underline', info.underline); this._updateToolbarButtonStatus('strike', info.strike); this._updateToolbarButtonStatus('superscription', info.superscription); this._updateToolbarButtonStatus('subscription', info.subscription); this._updateToolbarButtonStatus('justifyLeft', info.justification == 'left'); this._updateToolbarButtonStatus('justifyCenter', info.justification == 'center'); this._updateToolbarButtonStatus('justifyRight', info.justification == 'right'); this._updateToolbarButtonStatus('justifyBoth', info.justification == 'justify'); this._updateToolbarButtonStatus('orderedList', info.list == 'OL'); this._updateToolbarButtonStatus('unorderedList', info.list == 'UL'); this._updateToolbarButtonStatus('code', info.list == 'CODE'); this._updateToolbarButtonStatus('paragraph', info.block == 'P'); this._updateToolbarButtonStatus('heading1', info.block == 'H1'); this._updateToolbarButtonStatus('heading2', info.block == 'H2'); this._updateToolbarButtonStatus('heading3', info.block == 'H3'); this._updateToolbarButtonStatus('heading4', info.block == 'H4'); this._updateToolbarButtonStatus('heading5', info.block == 'H5'); this._updateToolbarButtonStatus('heading6', info.block == 'H6'); }, removeUnnecessarySpaces: function(html) { var blocks = this.rdom.tree.getBlockTags().join("|"); var regex = new RegExp("\\s*<(/?)(" + blocks + ")>\\s*", "img"); return html.replace(regex, '<$1$2>'); }, /** * Gets editor's dynamic content from current editor(source or WYSIWYG) * * @return {Object} HTML String */ getCurrentContent: function(performFullValidation) { if(this.getCurrentEditMode() == 'source') { return this.getSourceContent(performFullValidation); } else { return this.getWysiwygContent(performFullValidation); } }, /** * Gets editor's dynamic content from WYSIWYG editor * * @return {Object} HTML String */ getWysiwygContent: function(performFullValidation, dontUseCache) { if(dontUseCache || !performFullValidation) return this.validator.validate(this.rdom.getRoot(), performFullValidation); var lastModified = this.editHistory.getLastModifiedDate(); if(this._lastModified != lastModified) { this._validContentCache = this.validator.validate(this.rdom.getRoot(), performFullValidation); this._lastModified = lastModified; } return this._validContentCache; }, /** * Gets editor's dynamic content from source editor * * @return {Object} HTML String */ getSourceContent: function(performFullValidation) { var raw = this.sourceEditorTextarea[xq.Browser.isWebkit ? 'innerHTML' : 'value']; var tempDiv = document.createElement('div'); tempDiv.innerHTML = this.removeUnnecessarySpaces(raw); var rdom = xq.RichDom.createInstance(); rdom.setRoot(document.body); rdom.wrapAllInlineOrTextNodesAs("P", tempDiv, true); return this.validator.validate(tempDiv, performFullValidation); }, /** * Sets editor's original content * * @param {Object} content HTML String */ setStaticContent: function(content) { if(this.contentElement.nodeName == 'TEXTAREA') { this.contentElement.value = content; if(xq.Browser.isWebkit) { this.contentElement.innerHTML = content; } } else { this.contentElement.innerHTML = content; } this._fireOnStaticContentChanged(this, content); }, /** * Gets editor's original content * * @return {Object} HTML String */ getStaticContent: function() { var content; if(this.contentElement.nodeName == 'TEXTAREA') { content = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value']; } else { content = this.contentElement.innerHTML; } return content; }, /** * Gets editor's original content as DOM node * * @return {Object} HTML String */ getStaticContentAsDOM: function() { if(this.contentElement.nodeName == 'TEXTAREA') { var div = this.doc.createElement('DIV'); div.innerHTML = this.contentElement[xq.Browser.isWebkit ? 'innerHTML' : 'value']; return div; } else { return this.contentElement; } }, /** * Gives focus to editor */ focus: function() { if(this.getCurrentEditMode() == 'wysiwyg') { this.rdom.focus(); window.setTimeout(function() { this.updateAllToolbarButtonsStatus(this.rdom.getCurrentElement()); }.bind(this), 0); } else if(this.getCurrentEditMode() == 'source') { this.sourceEditorTextarea.focus(); } }, /** * Returns designmode iframe object */ getFrame: function() { return this.editorFrame; }, /** * Returns designmode window object */ getWin: function() { return this.editorWin; }, /** * Returns designmode document object */ getDoc: function() { return this.editorDoc; }, /** * Returns outmost wrapper element */ getOutmostWrapper: function() { return this.outmostWrapper; }, /** * Returns designmode body object */ getBody: function() { return this.editorBody; }, _createEditorFrame: function() { // create outer DIV this.outmostWrapper = this.doc.createElement('div'); this.outmostWrapper.className = "xquared"; this.contentElement.parentNode.insertBefore(this.outmostWrapper, this.contentElement); // create toolbar is needed if(!this.toolbarContainer && this.config.generateDefaultToolbar) { this.toolbarContainer = this._generateDefaultToolbar(); this.outmostWrapper.appendChild(this.toolbarContainer); } // create source editor div this.sourceEditorDiv = this.doc.createElement('div'); this.sourceEditorDiv.className = "editor source_editor"; //TODO: remove editor this.sourceEditorDiv.style.display = "none"; this.outmostWrapper.appendChild(this.sourceEditorDiv); // create TEXTAREA for source editor this.sourceEditorTextarea = this.doc.createElement('textarea'); this.sourceEditorDiv.appendChild(this.sourceEditorTextarea); // create WYSIWYG editor div this.wysiwygEditorDiv = this.doc.createElement('div'); this.wysiwygEditorDiv.className = "editor wysiwyg_editor"; //TODO: remove editor
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -