/** * @file Configuration helper plugin for CKEditor * Copyright (C) 2012 Alfonso Martínez de Lizarrondo * */ /* global CKEDITOR */ (function () { "use strict"; // Check if the browser supports the placeholder attribute on textareas natively. var supportsPlaceholder = "placeholder" in document.createElement("textarea"); // If the data is "empty" (BR, P) or the placeholder then return an empty string. // Otherwise return the original data function dataIsEmpty(data) { if (!data) return true; if (data.length > 20) return false; var value = data.replace(/[\n|\t]*/g, "").toLowerCase(); if ( !value || value == "
" || value == "

 

" || value == "


" || value == "

" || value == "

 

" || value == " " || value == " " || value == " 
" || value == "
" ) return true; return false; } function addPlaceholder(ev) { var editor = ev.editor; // do not add placeholder in readOnly mode if (editor.readOnly) return; var root = editor.editable(); var placeholder = ev.listenerData; if (!root) return; if (editor.mode == "wysiwyg") { // If the blur is due to a dialog, don't apply the placeholder if (CKEDITOR.dialog._.currentTop) return; if (!root) return; if (dataIsEmpty(root.getHtml())) { root.setHtml(placeholder); root.addClass("placeholder"); } } if (editor.mode == "source") { if (supportsPlaceholder) { if (ev.name == "mode") { root.setAttribute("placeholder", placeholder); } return; } if (dataIsEmpty(root.getValue())) { root.setValue(placeholder); root.addClass("placeholder"); } } } function removePlaceholder(ev) { var editor = ev.editor; var root = editor.editable(); if (!root) return; if (editor.mode == "wysiwyg") { if (!root.hasClass("placeholder")) return; root.removeClass("placeholder"); // fill it properly if (CKEDITOR.dtd[root.getName()]["p"]) { var value = ""; if (editor.enterMode === CKEDITOR.ENTER_P) { value = "


"; } else if (editor.enterMode === CKEDITOR.ENTER_DIV) { value = "

"; } else { // This is for CKEDITOR.ENTER_BR value = "
"; // FireFox prepends an additional line if (CKEDITOR.env.gecko || CKEDITOR.env.ie) { value = " "; } } root.setHtml(value); // Set caret in position var range = new CKEDITOR.dom.range(editor.document); range.moveToElementEditablePosition(root.getFirst(), true); editor.getSelection().selectRanges([range]); } else { root.setHtml(" "); } } if (editor.mode == "source") { if (!root.hasClass("placeholder")) return; root.removeClass("placeholder"); root.setValue(""); } } function handleReadOnlyChange(ev) { var editor = ev.editor; if (editor.readOnly) { removePlaceholder(ev); } else { addPlaceholder(ev); } } function getLang(element) { if (!element) return null; return element.getAttribute("lang") || getLang(element.getParent()); } CKEDITOR.plugins.add("confighelper", { getPlaceholderCss: function () { return ".placeholder{ color: #999; }"; }, onLoad: function () { CKEDITOR.addCss(this.getPlaceholderCss()); }, init: function (editor) { // correct focus status after switch mode editor.on("mode", function (ev) { // Let's update to match reality ev.editor.focusManager.hasFocus = false; // Now focus it: }); // Placeholder - Start // Get the placeholder from the replaced element or from the configuration var placeholder = editor.element.getAttribute("placeholder") || editor.config.placeholder; if (placeholder) { // CSS for textarea mode var node = CKEDITOR.document.getHead().append("style"); node.setAttribute("type", "text/css"); var content = "textarea.placeholder { color: #999; font-style: italic; }"; if (CKEDITOR.env.ie && CKEDITOR.env.version < 11) node.$.styleSheet.cssText = content; else node.$.innerHTML = content; // Watch for the calls to getData to remove the placeholder editor.on("getData", function (ev) { var element = editor.editable(); if (element && element.hasClass("placeholder")) ev.data.dataValue = ""; }); // Watch for setData to remove placeholder class editor.on("setData", function (ev) { if (CKEDITOR.dialog._.currentTop) return; if (editor.mode == "source" && supportsPlaceholder) return; var root = editor.editable(); if (!root) return; if (!dataIsEmpty(ev.data.dataValue)) { // Remove the class if new data is not empty if (root.hasClass("placeholder")) root.removeClass("placeholder"); } else { // if data is empty, set it to the placeholder addPlaceholder(ev); } }); editor.on("blur", addPlaceholder, null, placeholder); editor.on("mode", addPlaceholder, null, placeholder); editor.on("contentDom", addPlaceholder, null, placeholder); editor.on("focus", removePlaceholder); editor.on("key", removePlaceholder); editor.on("beforeModeUnload", removePlaceholder); editor.on("readOnly", handleReadOnlyChange, null, placeholder); } // Placeholder - End // SCAYT lang from element lang: var lang = editor.config.contentsLanguage || getLang(editor.element); if (lang && editor.plugins.scayt && !editor.config.scayt_sLang) { try { // Remove the stored language if (localStorage) localStorage.removeItem("scayt_0_lang"); } catch (e) { /* */ } // Convert from HTML5 Lang to spellchecker.net values var map = { en: "en_US", "en-us": "en_US", "en-gb": "en_GB", "pt-br": "pt_BR", da: "da_DK", "da-dk": "da_DK", "nl-nl": "nl_NL", "en-ca": "en_CA", "fi-fi": "fi_FI", fr: "fr_FR", "fr-fr": "fr_FR", "fr-ca": "fr_CA", de: "de_DE", "de-de": "de_DE", "el-gr": "el_GR", it: "it_IT", "it-it": "it_IT", "nb-no": "nb_NO", pt: "pt_PT", "pt-pt": "pt_PT", es: "es_ES", "es-es": "es_ES", "sv-se": "sv_SE", }; editor.config.scayt_sLang = map[lang.toLowerCase()]; } // Parse the config to turn it into a js object // format= dialogName:tabName:fieldName var parseDefinitionToObject = function (value) { // Allow JSON definitions if (typeof value == "object") return value; var contents = value.split(";"), tabsToProcess = {}, i; for (i = 0; i < contents.length; i++) { var parts = contents[i].split(":"); if (parts.length == 3) { var dialogName = parts[0], tabName = parts[1], fieldName = parts[2]; if (!tabsToProcess[dialogName]) tabsToProcess[dialogName] = {}; if (!tabsToProcess[dialogName][tabName]) tabsToProcess[dialogName][tabName] = []; tabsToProcess[dialogName][tabName].push(fieldName); } } return tabsToProcess; }; // Customize dialogs: function customizeDialogs(ev) { if (editor != ev.editor) return; var dialogName = ev.data.name, dialogDefinition = ev.data.definition, tabsToProcess, i, name, fields, tab; if (dialogName == "tableProperties") dialogName = "table"; // Parse the config to turn it into a js object if ( !("removeDialogFields" in editor._) && editor.config.removeDialogFields ) editor._.removeDialogFields = parseDefinitionToObject( editor.config.removeDialogFields ); // Remove fields of this dialog. if ( editor._.removeDialogFields && (tabsToProcess = editor._.removeDialogFields[dialogName]) ) { for (name in tabsToProcess) { fields = tabsToProcess[name]; tab = dialogDefinition.getContents(name); if (!tab) continue; for (i = 0; i < fields.length; i++) tab.remove(fields[i]); } } if (!("hideDialogFields" in editor._) && editor.config.hideDialogFields) editor._.hideDialogFields = parseDefinitionToObject( editor.config.hideDialogFields ); // Remove fields of this dialog. if ( editor._.hideDialogFields && (tabsToProcess = editor._.hideDialogFields[dialogName]) ) { for (name in tabsToProcess) { fields = tabsToProcess[name]; tab = dialogDefinition.getContents(name); if (!tab) continue; for (i = 0; i < fields.length; i++) tab.get(fields[i]).hidden = true; } } // Set default values. if ( editor.config.dialogFieldsDefaultValues && (tabsToProcess = editor.config.dialogFieldsDefaultValues[dialogName]) ) { for (name in tabsToProcess) { fields = tabsToProcess[name]; tab = dialogDefinition.getContents(name); if (!tab) continue; for (var fieldName in fields) { var dialogField = tab.get(fieldName); if (dialogField) dialogField["default"] = fields[fieldName]; } } } } CKEDITOR.on("dialogDefinition", customizeDialogs); editor.once("beforeDestroy", function () { CKEDITOR.removeListener("dialogDefinition", customizeDialogs); }); }, }); })(); /** * Allows to define which dialog fiels must be removed * @name CKEDITOR.config.removeDialogFields * @type {String} * @example * editor.config.removeDialogFields = "image:info:txtBorder;image:info:txtHSpace"; */ /** * Allows to define which dialog fiels must be hidden * @name CKEDITOR.config.hideDialogFields * @type {String} * @example * editor.config.hideDialogFields = "image:info:htmlPreview"; */ /** * Allows to define default values for dialog fields * @name CKEDITOR.config.dialogFieldsDefaultValues * @type {Object} * @example config.dialogFieldsDefaultValues = { image: { advanced: { txtGenClass : 'myClass', txtGenTitle : 'Image title' } } }; */ /** * Placeholder text for empty editor * @name CKEDITOR.config.placeholder * @type {String} * @example * editor.config.placeholder = "Please, type here..."; */