/* * The "codemirror" plugin. It's indented to enhance the * "sourcearea" editing mode, which displays the xhtml source code with * syntax highlight and line numbers. * Licensed under the MIT license * CodeMirror Plugin: http://codemirror.net/ (MIT License) */ (function() { CKEDITOR.plugins.add("codemirror", { icons: "searchcode,autoformat,commentselectedrange,uncommentselectedrange,autocomplete", // %REMOVE_LINE_CORE% lang: "af,ar,bg,bn,bs,ca,cs,cy,da,de,el,en-au,en-ca,en-gb,en,eo,es,et,eu,fa,fi,fo,fr-ca,fr,gl,gu,he,hi,hr,hu,is,it,ja,ka,km,ko,ku,lt,lv,mk,mn,ms,nb,nl,no,pl,pt-br,pt,ro,ru,sk,sl,sr-latn,sr,sv,th,tr,ug,uk,vi,zh-cn,zh", // %REMOVE_LINE_CORE% version: "1.17.11", init: function (editor) { var rootPath = this.path, defaultConfig = { autoCloseBrackets: true, autoCloseTags: true, autoFormatOnStart: false, autoFormatOnUncomment: false, autoLoadCodeMirror: true, continueComments: true, enableCodeFolding: true, enableCodeFormatting: true, enableSearchTools: true, highlightMatches: true, indentWithTabs: false, lineNumbers: true, lineWrapping: true, mode: "htmlmixed", matchBrackets: true, maxHighlightLineLength: 1000, matchTags: true, showAutoCompleteButton: true, showCommentButton: true, showFormatButton: true, showSearchButton: true, showTrailingSpace: true, showUncommentButton: true, styleActiveLine: true, theme: "default", useBeautifyOnStart: false }; // Get Config & Lang var config = CKEDITOR.tools.extend(defaultConfig, editor.config.codemirror || {}, true), lang = editor.lang.codemirror; // check for old config settings for legacy support if (editor.config.codemirror_theme) { config.theme = editor.config.codemirror_theme; } if (editor.config.codemirror_autoFormatOnStart) { config.autoFormatOnStart = editor.config.codemirror_autoFormatOnStart; } // automatically switch to bbcode mode if bbcode plugin is enabled if (editor.plugins.bbcode && config.mode.indexOf("bbcode") <= 0) { config.mode = "bbcode"; } var requirePresent = "function" === typeof require && "function" === typeof require.config; var pluginRequire; if (requirePresent){ var requireContext = config.requireContext || "_"; var location = CKEDITOR.getUrl("plugins/codemirror/js"); pluginRequire = require.config({ context: requireContext, packages: [{ name: "codemirror", location: location, main: "codemirror.min.js" }, { name: "codemirror-mode-handlebars", location: location, main: "codemirror.mode.handlebars.min.js" }, { name: "codemirror-mode-twig", location: location, main: "codemirror.mode.twig.min.js" }, { name: "codemirror-mode-html", location: location, main: "codemirror.mode.htmlmixed.min.js" }, { name: "codemirror-mode-php", location: location, main: "codemirror.mode.php.min.js" }, { name: "codemirror-mode-js", location: location, main: "codemirror.mode.js.min.js" }, { name: "codemirror-addons", location: location, main: "codemirror.addons.min.js" }, { name: "codemirror-addon-search", location: location, main: "codemirror.addons.search.min.js" }, { name: "codemirror-beautify", location: location, main: "beautify.min.js" }], bundles: { 'codemirror': ["core", "codemirror.js"], 'codemirror-mode-handlebars': ["modeHandlebars"], 'codemirror-mode-twig': ["modeTwig"], 'codemirror-mode-html': ["modeHtml"], 'codemirror-mode-php': ["modePHP"], 'codemirror-mode-js': ["modeJS"], 'codemirror-addons': ["addons"], 'codemirror-addon-search': ["addonSearch"], 'codemirror-beautify': ["beautifyModule"] }, map: { '*': { //all the requires pointing to ../../lib/codemirror from addons will be redirected to module named codemirror.js //which is located in bundle 'codemirror' whose js file is codemirror.min.js 'lib/codemirror': "codemirror.js" } } }); } // Source mode isn't available in inline mode yet. if (editor.elementMode === CKEDITOR.ELEMENT_MODE_INLINE || editor.plugins.sourcedialog) { // Override Source Dialog CKEDITOR.dialog.add("sourcedialog", function (editor) { var sizeDialog = CKEDITOR.document.getWindow().getViewPaneSize(), minWidth = Math.min(sizeDialog.width - 70, 800), minHeight = sizeDialog.height / 1.5, oldData; function loadCodeMirrorInline(editor, textarea, dialog) { var size = dialog.getSize(), width = size.width, height = size.height / 1.5; window["codemirror_" + editor.id] = CodeMirror.fromTextArea(textarea, { mode: config.mode === "handlebars" ? { name: "handlebars", base: "text/html" } : config.mode, matchBrackets: config.matchBrackets, maxHighlightLineLength: config.maxHighlightLineLength, matchTags: config.matchTags, workDelay: 300, workTime: 35, readOnly: editor.readOnly, lineNumbers: config.lineNumbers, lineWrapping: config.lineWrapping, autoCloseTags: config.autoCloseTags, autoCloseBrackets: config.autoCloseBrackets, highlightSelectionMatches: config.highlightMatches, continueComments: config.continueComments, indentWithTabs: config.indentWithTabs, theme: config.theme, showTrailingSpace: config.showTrailingSpace, showCursorWhenSelecting: true, styleActiveLine: config.styleActiveLine, viewportMargin: Infinity, extraKeys: { "Ctrl-Space": "autocomplete", "Ctrl-Q": function (codeMirror_Editor) { if (config.enableCodeFolding) { window["foldFunc_" + editor.id](codeMirror_Editor, codeMirror_Editor.getCursor().line); } } }, foldGutter: true, gutters: ["CodeMirror-linenumbbers", "CodeMirror-foldgutter"] }); var holderHeight = height + "px"; var holderWidth = width + "px"; // Store config so we can access it within commands etc. window["codemirror_" + editor.id].config = config; if (config.autoFormatOnStart) { if (config.useBeautifyOnStart) { var indent_size = 4, indent_char = " ", brace_style = "collapse"; //collapse, expand, end-expand var source = window["codemirror_" + editor.id].getValue(); window["codemirror_" + editor.id].setValue(html_beautify(source, indent_size, indent_char, 120, brace_style)); } else { window["codemirror_" + editor.id].autoFormatAll({ line: 0, ch: 0 }, { line: window["codemirror_" + editor.id].lineCount(), ch: 0 }); } } function getSelectedRange() { return { from: window["codemirror_" + editor.id].getCursor(true), to: window["codemirror_" + editor.id].getCursor(false) }; } window["codemirror_" + editor.id].on("change", function () { window["codemirror_" + editor.id].save(); editor.fire("change", this); }); window["codemirror_" + editor.id].setSize(holderWidth, holderHeight); // Enable Code Folding (Requires 'lineNumbers' to be set to 'true') if (config.lineNumbers && config.enableCodeFolding) { window["codemirror_" + editor.id].on("gutterClick", window["foldFunc_" + editor.id]); } // Run config.onLoad callback, if present. if (typeof config.onLoad === "function") { config.onLoad(window["codemirror_" + editor.id], editor); } // inherit blur event window["codemirror_" + editor.id].on("blur", function () { editor.fire("blur", this); }); window["codemirror_" + editor.id].on("keypress", function (codeMirror_Editor, evt) { if (config.enableCodeFormatting) { var range = getSelectedRange(); if (evt.type === "keydown" && evt.ctrlKey && evt.keyCode === 75 && !evt.shiftKey && !evt.altKey) { window["codemirror_" + editor.id].commentRange(true, range.from, range.to); } else if (evt.type === "keydown" && evt.ctrlKey && evt.keyCode === 75 && evt.shiftKey && !evt.altKey) { window["codemirror_" + editor.id].commentRange(false, range.from, range.to); if (config.autoFormatOnUncomment) { window["codemirror_" + editor.id].autoFormatRange(range.from, range.to); } } else if (evt.type === "keydown" && evt.ctrlKey && evt.keyCode === 75 && !evt.shiftKey && evt.altKey) { window["codemirror_" + editor.id].autoFormatRange(range.from, range.to); }/* else if (evt.type === "keydown") { CodeMirror.commands.newlineAndIndentContinueMarkdownList(window["codemirror_" + editor.id]); }*/ } }); if (editor.plugins.textselection && textRange && !editor.config.fullPage) { var start, end; start = OffSetToLineChannel(window["codemirror_" + editor.id], textRange.startOffset); window["codemirror_" + editor.id].doc.setCursor(start.line + 12); if (typeof (textRange.endOffset) == "undefined") { window["codemirror_" + editor.id].focus(); window["codemirror_" + editor.id].setCursor(start); } else { window["codemirror_" + editor.id].focus(); end = OffSetToLineChannel(window["codemirror_" + editor.id], textRange.endOffset); window["codemirror_" + editor.id].setSelection(start, end); } } } return { title: editor.lang.sourcedialog.title, minWidth: minWidth, minHeight: minHeight, resizable: CKEDITOR.DIALOG_RESIZE_BOTH, onLoad: function() { this.on("resize", function (event) { var parts = event.sender.parts; var title = parts.title; var footer = parts.footer; var holderHeight = (event.data.height - title.$.offsetHeight - footer.$.offsetHeight) + "px"; var holderWidth = event.data.width + "px"; window["codemirror_" + editor.id].setSize(holderWidth, holderHeight); }, this); }, onShow: function (event) { // Set Elements this.getContentElement("main", "data").focus(); this.getContentElement("main", "AutoComplete").setValue(config.autoCloseTags, true); var textArea = this.getContentElement("main", "data").getInputElement().$; // Load the content this.setValueOf("main", "data", oldData = editor.getData()); if (config.autoLoadCodeMirror) { if (!IsStyleSheetAlreadyLoaded(rootPath + "css/codemirror.min.css")) { CKEDITOR.document.appendStyleSheet(rootPath + "css/codemirror.min.css"); } if (config.theme.length && config.theme != "default" && !IsStyleSheetAlreadyLoaded(rootPath + "theme/" + config.theme + ".css")) { CKEDITOR.document.appendStyleSheet(rootPath + "theme/" + config.theme + ".css"); } if(requirePresent) { pluginRequire(getCodeMirrorDependencies(),function (codemirror, addons){ loadCodeMirrorInline(editor, textArea, event.sender); }); } else { if (typeof (CodeMirror) == "undefined") { CKEDITOR.scriptLoader.load(rootPath + "js/codemirror.min.js", function() { CKEDITOR.scriptLoader.load(getCodeMirrorScripts(), function() { loadCodeMirrorInline(editor, textArea, event.sender); }); }); } else { if (CodeMirror.prototype["autoFormatAll"]) { loadCodeMirrorInline(editor, textArea, event.sender); } else { // loading the add-on scripts. CKEDITOR.scriptLoader.load(getCodeMirrorScripts(), function() { loadCodeMirrorInline(editor, textArea, event.sender); }); } } } } }, onCancel: function (event) { if (event.data.hide) { window["codemirror_" + editor.id].toTextArea(); // Free Memory window["codemirror_" + editor.id] = null; editor.fire("blur", this); editor.fire("focus", this); } }, onOk: (function () { function setData(newData) { var that = this; editor.setData(newData, function () { that.hide(); // Ensure correct selection. var range = editor.createRange(); range.moveToElementEditStart(editor.editable()); range.select(); }); } return function () { window["codemirror_" + editor.id].toTextArea(); // Free Memory window["codemirror_" + editor.id] = null; // Remove CR from input data for reliable comparison with editor data. var newData = this.getValueOf("main", "data").replace(/\r/g, ""); // Avoid unnecessary setData. Also preserve selection // when user changed his mind and goes back to wysiwyg editing. if (newData === oldData) { editor.fire("blur", this); editor.fire("focus", this); return true; } // Set data asynchronously to avoid errors in IE. CKEDITOR.env.ie ? CKEDITOR.tools.setTimeout(setData, 0, this, newData) : setData.call(this, newData); editor.fire("blur", this); editor.fire("focus", this); // Don't let the dialog close before setData is over. return false; }; })(), contents: [{ id: "main", label: editor.lang.sourcedialog.title, elements: [ { type: "hbox", style: "width: 80px;margin:0;", widths: ["20px", "20px", "20px", "20px"], children: [ { type: "button", id: "searchCode", label: "", title: lang.searchCode, 'class': "searchCodeButton", onClick: function() { CodeMirror.commands.find(window["codemirror_" + editor.id]); } }, { type: "button", id: "autoFormat", label: "", title: lang.autoFormat, 'class': "autoFormat", onClick: function() { var range = { from: window["codemirror_" + editor.id].getCursor(true), to: window["codemirror_" + editor.id].getCursor(false) }; window["codemirror_" + editor.id].autoFormatRange(range.from, range.to); } }, { type: "button", id: "CommentSelectedRange", label: "", title: lang.commentSelectedRange, 'class': "CommentSelectedRange", onClick: function () { var range = { from: window["codemirror_" + editor.id].getCursor(true), to: window["codemirror_" + editor.id].getCursor(false) }; window["codemirror_" + editor.id].commentRange(true, range.from, range.to); } }, { type: "button", id: "UncommentSelectedRange", label: "", title: lang.uncommentSelectedRange, 'class': "UncommentSelectedRange", onClick: function () { var range = { from: window["codemirror_" + editor.id].getCursor(true), to: window["codemirror_" + editor.id].getCursor(false) }; window["codemirror_" + editor.id].commentRange(false, range.from, range.to); if (window["codemirror_" + editor.id].config.autoFormatOnUncomment) { window["codemirror_" + editor.id].autoFormatRange(range.from, range.to); } } }] }, { type: "checkbox", id: "AutoComplete", label: lang.autoCompleteToggle, title: lang.autoCompleteToggle, onChange: function () { window["codemirror_" + editor.id].setOption("autoCloseTags", this.getValue()); } }, { type: "textarea", id: "data", dir: "ltr", inputStyle: "cursor:auto;" + "width:" + minWidth + "px;" + "height:" + minHeight + "px;" + "tab-size:4;" + "text-align:left;", 'class': "cke_source cke_enable_context_menu" } ] }] }; }); // return; } /* // Override Copy Button if (editor.commands.copy) { editor.commands.copy.modes = { wysiwyg: 1, source: 1 }; // TODO } // Override Paste Button if (editor.commands.paste) { editor.commands.paste.modes = { wysiwyg: 1, source: 1 }; // TODO } // Override Cut Button if (editor.commands.cut) { editor.commands.cut.modes = { wysiwyg: 1, source: 1 }; // TODO }*/ // Override Find Button if (editor.commands.find) { editor.commands.find.modes = { wysiwyg: 1, source: 1 }; editor.commands.find.exec = function() { if (editor.mode === "wysiwyg") { editor.openDialog("find"); } else { CodeMirror.commands.find(window["codemirror_" + editor.id]); } }; } // Override Replace Button if (editor.commands.replace) { editor.commands.replace.modes = { wysiwyg: 1, source: 1 }; editor.commands.replace.exec = function () { if (editor.mode === "wysiwyg") { editor.openDialog("find", function () { this.selectPage("replace"); }); } else { CodeMirror.commands.replace(window["codemirror_" + editor.id]); } }; } var sourcearea = CKEDITOR.plugins.sourcearea; // check if sourcearea plugin is overrriden if (!sourcearea.commands.searchCode) { CKEDITOR.plugins.sourcearea.commands = { source: { modes: { wysiwyg: 1, source: 1 }, editorFocus: false, readOnly: 1, exec: function(editorInstance) { if (editorInstance.mode === "wysiwyg") { editorInstance.fire("saveSnapshot"); } editorInstance.getCommand("source").setState(CKEDITOR.TRISTATE_DISABLED); editorInstance.setMode(editorInstance.mode === "source" ? "wysiwyg" : "source"); }, canUndo: false }, searchCode: { modes: { wysiwyg: 0, source: 1 }, editorFocus: false, readOnly: 1, exec: function (editorInstance) { CodeMirror.commands.find(window["codemirror_" + editorInstance.id]); }, canUndo: true }, autoFormat: { modes: { wysiwyg: 0, source: 1 }, editorFocus: false, readOnly: 1, exec: function (editorInstance) { var range = { from: window["codemirror_" + editorInstance.id].getCursor(true), to: window["codemirror_" + editorInstance.id].getCursor(false) }; window["codemirror_" + editorInstance.id].autoFormatRange(range.from, range.to); }, canUndo: true }, commentSelectedRange: { modes: { wysiwyg: 0, source: 1 }, editorFocus: false, readOnly: 1, exec: function (editorInstance) { var range = { from: window["codemirror_" + editorInstance.id].getCursor(true), to: window["codemirror_" + editorInstance.id].getCursor(false) }; window["codemirror_" + editorInstance.id].commentRange(true, range.from, range.to); }, canUndo: true }, uncommentSelectedRange: { modes: { wysiwyg: 0, source: 1 }, editorFocus: false, readOnly: 1, exec: function (editorInstance) { var range = { from: window["codemirror_" + editorInstance.id].getCursor(true), to: window["codemirror_" + editorInstance.id].getCursor(false) }; window["codemirror_" + editorInstance.id].commentRange(false, range.from, range.to); if (window["codemirror_" + editorInstance.id].config.autoFormatOnUncomment) { window["codemirror_" + editorInstance.id].autoFormatRange( range.from, range.to); } }, canUndo: true }, autoCompleteToggle: { modes: { wysiwyg: 0, source: 1 }, editorFocus: false, readOnly: 1, exec: function (editorInstance) { if (this.state == CKEDITOR.TRISTATE_ON) { window["codemirror_" + editorInstance.id].setOption("autoCloseTags", false); } else if (this.state == CKEDITOR.TRISTATE_OFF) { window["codemirror_" + editorInstance.id].setOption("autoCloseTags", true); } this.toggleState(); }, canUndo: true } }; } editor.addMode("source", function (callback) { if (!config.autoLoadCodeMirror) { return; } if (!IsStyleSheetAlreadyLoaded(rootPath + "css/codemirror.min.css")) { CKEDITOR.document.appendStyleSheet(rootPath + "css/codemirror.min.css"); } if (config.theme.length && config.theme != "default" && !IsStyleSheetAlreadyLoaded(rootPath + "theme/" + config.theme + ".css")) { CKEDITOR.document.appendStyleSheet(rootPath + "theme/" + config.theme + ".css"); } if (requirePresent) { pluginRequire(getCodeMirrorDependencies(), function () { loadCodeMirror(editor); callback(); }); } else { if (typeof (CodeMirror) == "undefined") { CKEDITOR.scriptLoader.load(rootPath + "js/codemirror.min.js", function() { CKEDITOR.scriptLoader.load(getCodeMirrorScripts(), function() { loadCodeMirror(editor); callback(); }); }); } else { if (CodeMirror.prototype["autoFormatAll"]) { loadCodeMirror(editor); callback(); } else { // loading the add-on scripts. CKEDITOR.scriptLoader.load(getCodeMirrorScripts(), function() { loadCodeMirror(editor); callback(); }); } } } }); function getCodeMirrorDependencies() { var dependencies = ["core", "addons"]; switch (config.mode) { case "bbcode": case "bbcodemixed": dependencies.push("modeHtml"); break; case "application/x-httpd-php": dependencies.push("modePHP"); break; case "text/javascript": dependencies.push("modeJs"); break; case "handlebars": dependencies.push("modeHandlebars"); break; case "twig": dependencies.push("modeTwig"); break; case "htmlmixed": case "text/html": default: dependencies.push("modeHtml"); } if (config.useBeautifyOnStart) { dependencies.push("beautifyModule"); } if (config.enableSearchTools) { dependencies.push("addonSearch"); } return dependencies; } function getCodeMirrorScripts() { var scriptFiles = [rootPath + "js/codemirror.addons.min.js"]; switch (config.mode) { case 'handlebars': { scriptFiles.push(rootPath + "js/codemirror.mode.handlebars.min.js"); } case "bbcode": { scriptFiles.push(rootPath + "js/codemirror.mode.bbcode.min.js"); } break; case "bbcodemixed": { scriptFiles.push(rootPath + "js/codemirror.mode.bbcodemixed.min.js"); } break; case "htmlmixed": { scriptFiles.push(rootPath + "js/codemirror.mode.htmlmixed.min.js"); } break; case "text/html": { scriptFiles.push(rootPath + "js/codemirror.mode.htmlmixed.min.js"); } break; case "application/x-httpd-php": { scriptFiles.push(rootPath + "js/codemirror.mode.php.min.js"); } break; case "text/javascript": { scriptFiles.push(rootPath + "js/codemirror.mode.javascript.min.js"); } break; case "twig": { scriptFiles.push(rootPath + "js/codemirror.mode.twig.min.js"); } break; default: scriptFiles.push(rootPath + "js/codemirror.mode.htmlmixed.min.js"); } if (config.useBeautifyOnStart) { scriptFiles.push(rootPath + "js/beautify.min.js"); } if (config.enableSearchTools) { scriptFiles.push(rootPath + "js/codemirror.addons.search.min.js"); } return scriptFiles; } function loadCodeMirror(editor) { var contentsSpace = editor.ui.space("contents"), textarea = contentsSpace.getDocument().createElement("textarea"); textarea.setStyles( CKEDITOR.tools.extend({ // IE7 has overflow the