/** * InputfieldCKEditor.js * * Initialization for CKEditor * */ /** * Get ProcessWire config settings for given CKE editor object or name * * @param editor * @returns {*} * */ function ckeGetProcessWireConfig(editor) { var editorName = typeof editor == "string" ? editor : editor.name; var configName = editorName.replace('Inputfield_', 'InputfieldCKEditor_'); var $repeaterItem = ''; var settings = {}; configName = configName.replace('Inputfield_', 'InputfieldCKEditor_'); if(typeof ProcessWire.config[configName] == "undefined" && configName.indexOf('_repeater') > 0) { configName = configName.replace(/_repeater[0-9]+/, ''); $repeaterItem = $('#' + editorName).closest('.InputfieldRepeaterItem'); } if(typeof ProcessWire.config[configName] == "undefined" && configName.indexOf('_ckeditor') > 0) { configName = configName.replace(/_ckeditor$/, ''); // inline only } if(typeof ProcessWire.config[configName] == "undefined" && configName.indexOf('__') > 0) { configName = configName.replace(/__\d+$/, ''); // remove language-id } if(typeof ProcessWire.config[configName] == "undefined") { settings.error = 'Cannot find CKEditor settings for ' + configName; } else { settings = ProcessWire.config[configName]; } if($repeaterItem.length) { settings['repeaterItem'] = $repeaterItem; } else { settings['repeaterItem'] = ''; } return settings; } /** * Add external plugins * * These are located in: * /wire/modules/Inputfield/InputfieldCKEditor/plugins/[name]/plugin.js (core external plugins) * /site/modules/InputfieldCKEditor/plugins/[name]/plugin.js (site external plugins) * */ function ckeLoadPlugins() { for(var name in ProcessWire.config.InputfieldCKEditor.plugins) { var file = ProcessWire.config.InputfieldCKEditor.plugins[name]; CKEDITOR.plugins.addExternal(name, file, ''); } } ckeLoadPlugins(); /** * Event called when an editor is blurred, so that we can check for changes * * @param event * */ function ckeBlurEvent(event) { var editor = event.editor; var $textarea = $(editor.element.$); if(editor.checkDirty()) { // value changed if($textarea.length) { if($textarea.is("textarea")) $textarea.change(); $textarea.closest(".Inputfield").addClass('InputfieldStateChanged'); } } } /** * Event called when an editor is focused * * @param event * */ function ckeFocusEvent(event) { var editor = event.editor; var $textarea = $(editor.element.$); $textarea.trigger('pw-focus'); } /** * Event called when an editor is resized vertically * * @param event * */ function ckeResizeEvent(event) { var editor = event.editor; var $textarea = $(editor.element.$); if($textarea.length) { $textarea.closest(".Inputfield").trigger('heightChanged'); } } /** * Handler for fileUploadRequest event * * @param event * */ function ckeUploadEvent(event) { var xhr = event.data.fileLoader.xhr; var fileLoader = event.data.fileLoader; var settings = ckeGetProcessWireConfig(event.editor); var uploadFieldName = settings ? settings.pwUploadField : '_unknown'; var $imageInputfield = $('#Inputfield_' + uploadFieldName); if(typeof settings.repeaterItem != "undefined" && settings.repeaterItem.length) { var $repeaterImageField = settings.repeaterItem.find('.InputfieldImage:not(.InputfieldFileSingle)'); if($repeaterImageField.length) $imageInputfield = $repeaterImageField; } if($imageInputfield.length) { xhr.open("POST", fileLoader.uploadUrl, true); $imageInputfield.trigger('pwimageupload', { 'name': fileLoader.fileName, 'file': fileLoader.file, 'xhr': xhr }); // Prevented the default behavior. event.stop(); } else { if(typeof settings.error != "undefined" && settings.error.length) { ProcessWire.alert(settings.error); } else { ProcessWire.alert('Unable to find images field for upload'); } event.stop(); return false; } } /** * Attach events common to all CKEditor instances * * @param editor CKEditor instance * */ function ckeInitEvents(editor) { editor.on('blur', ckeBlurEvent); editor.on('focus', ckeFocusEvent); editor.on('change', ckeBlurEvent); editor.on('resize', ckeResizeEvent); editor.on('fileUploadRequest', ckeUploadEvent, null, null, 4); var $textarea = $(editor.element.$); var $inputfield = $textarea.closest('.Inputfield.InputfieldColumnWidth'); if($inputfield.length) setTimeout(function() { $inputfield.trigger('heightChanged'); }, 1000); } /** * Called on saveReady or submit to copy inline contents to a form element in the POST request * * @param $inputfield * */ function ckeSaveReadyInline($inputfield) { if(!$inputfield.length) return; var $inlines = $inputfield.hasClass('.InputfieldCKEditorInline') ? $inputfield : $inputfield.find(".InputfieldCKEditorInline"); if($inlines.length) $inlines.each(function() { var $t = $(this); var value; if($t.hasClass('InputfieldCKEditorLoaded')) { var editor = CKEDITOR.instances[$t.attr('id')]; // getData() ensures there are no CKE specific remnants in the markup if(typeof editor != "undefined") { if(editor.focusManager.hasFocus) { // TMP: CKEditor 4.5.1 / 4.5.2 has documented bug that causes JS error on editor.getData() here // this section of code can be removed after they fix it (presumably in 4.5.3) editor.focusManager.focus(true); editor.focus(); } value = editor.getData(); } } else { value = $t.html(); } var $input = $t.next('input'); $input.attr('value', value); }); } /** * Called on saveReady event to force an editor.updateElement() to update original textarea * * @param $inputfield * */ function ckeSaveReadyNormal($inputfield) { var $normals = $inputfield.hasClass('InputfieldCKEditorNormal') ? $inputfield : $inputfield.find(".InputfieldCKEditorNormal"); $normals.each(function() { var $t = $(this); if(!$t.hasClass('InputfieldCKEditorLoaded')) return; var editor = CKEDITOR.instances[$t.attr('id')]; editor.updateElement(); }); } /** * Get CKEditor configuration data when $editor element is available * * @param $editor Regular editor