/**
* @file SimpleUploads plugin for CKEditor
* Version: 4.3.12
* Uploads pasted images and files inside the editor to the server for Firefox and Chrome
* Feature introduced in: https://bugzilla.mozilla.org/show_bug.cgi?id=490879
* doesn't include images inside HTML (paste from word). IE11 does.
https://bugzilla.mozilla.org/show_bug.cgi?id=665341
https://www.libreoffice.org/bugzilla/show_bug.cgi?id=72083
* Includes Drag&Drop file uploads for all the new browsers.
* Two toolbar buttons to perform quick upload of files.
* Copyright (C) 2012-14 Alfonso Martínez de Lizarrondo
*
improvements: allow d&d between 2 editors in Firefox
https://bugzilla.mozilla.org/show_bug.cgi?id=454832
*/
(function() {
"use strict";
// If the selected image is a bmp converts it to a png
function convertToBmp(ev)
{
var data = ev.data,
isBmp = /\.bmp$/.test(data.name),
editor = ev.editor;
if (!isBmp)
return;
var img = data.image;
var canvas = document.createElement("canvas");
canvas.width = img.width;
canvas.height = img.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img, 0, 0);
data.file = canvas.toDataURL("image/png");
data.name = data.name.replace(/\.bmp$/, ".png");
}
// Verifies if the selected image is within the allowed dimensions
function checkDimension(ev)
{
var data = ev.data,
editor = ev.editor,
config = editor.config,
maximum = config.simpleuploads_maximumDimensions;
var img = data.image;
if (maximum.width && img.width > maximum.width)
{
alert(editor.lang.simpleuploads.imageTooWide);
ev.cancel();
return;
}
if (maximum.height && img.height > maximum.height)
{
alert(editor.lang.simpleuploads.imageTooTall);
ev.cancel();
return;
}
}
// Custom rule similar to the fake Object to avoid generating anything if the user tries to do something strange while a file is being uploaded
var htmlFilterRules = {
elements: {
$: function( element ) {
var attributes = element.attributes,
className = attributes && attributes[ "class" ];
// remove our wrappers
if ( className == "SimpleUploadsTmpWrapper" )
return false;
}
}
};
// CSS that we add to the editor for our internal styling
function getEditorCss( config ) {
var imgUpload = 'span.SimpleUploadsTmpWrapper>span { top: 50%; margin-top: -0.5em; width: 100%; text-align: center; color: #fff; ' +
'text-shadow: 2px 2px 4px rgba(0, 0, 0, 0.5); font-size: 50px; font-family: Calibri,Arial,Sans-serif; pointer-events: none; ' +
'position: absolute; display: inline-block;}';
if (config.simpleuploads_hideImageProgress)
imgUpload = 'span.SimpleUploadsTmpWrapper { color:#333; background-color:#fff; padding:4px; border:1px solid #EEE;}';
return '.SimpleUploadsOverEditor { ' + (config.simpleuploads_editorover || 'box-shadow: 0 0 10px 1px #999999 inset !important;') + ' }' +
'a.SimpleUploadsTmpWrapper { color:#333; background-color:#fff; padding:4px; border:1px solid #EEE;}' +
'.SimpleUploadsTmpWrapper { display: inline-block; position: relative; pointer-events: none;}' +
imgUpload +
'.uploadRect {display: inline-block;height: 0.9em;vertical-align: middle;width: 20px;}' +
'.uploadRect span {background-color: #999;display: inline-block;height: 100%;vertical-align: top;}' +
'.SimpleUploadsTmpWrapper .uploadCancel { background-color: #333333;border-radius: 0.5em;color: #FFFFFF;cursor: pointer !important;' +
'display: inline-block;height: 1em;line-height: 0.8em;margin-left: 4px;padding-left: 0.18em;pointer-events: auto;' +
'position: relative; text-decoration:none; top: -2px;width: 0.7em;}' +
'.SimpleUploadsTmpWrapper span uploadCancel { width:1em; padding-left:0}';
}
var filePicker,
filePickerEditor,
filePickerForceLink;
var IEUpload_fileName,
IEUpload_caller,
IEUpload_callback,
IEUpload_forImage;
function PickAndSendFile(editor, forImage, caller, callback) {
if (IEUpload_fileName)
{
alert("Please, wait to finish the current upload");
return;
}
filePickerForceLink = !forImage;
filePickerEditor = editor;
if (typeof FormData == 'undefined')
{
// old IE
var iframe = document.getElementById("simpleUploadsTarget");
if (!iframe) {
iframe = document.createElement("iframe");
iframe.style.display = "none";
iframe.id = "simpleUploadsTarget";
document.body.appendChild(iframe);
}
IEUpload_caller = caller;
IEUpload_callback = callback;
IEUpload_forImage = forImage;
var fnNumber = editor._.simpleuploadsFormUploadFn;
var fnInitPicker = editor._.simpleuploadsFormInitFn;
if (!fnNumber)
{
editor._.simpleuploadsFormUploadFn = fnNumber = CKEDITOR.tools.addFunction( setUrl, editor );
editor._.simpleuploadsFormInitFn = fnInitPicker = CKEDITOR.tools.addFunction( function() {
window.setTimeout(function() {
var picker = document.getElementById("simpleUploadsTarget").contentWindow.document.getElementById( getUploadInputName(editor) );
picker.onchange=function() {
var evdata = {
name: this.value,
url: this.form.action,
context : IEUpload_caller,
id: 'IEUpload',
requiresImage: IEUpload_forImage
};
// , mode : {type : 'selectedFileIE'}
// Remove C:\FakePath\
var m = evdata.name.match(/\\([^\\]*)$/);
if (m)
evdata.name = m[1];
var result = filePickerEditor.fire("simpleuploads.startUpload", evdata );
// in v3 cancel() returns true and in v4 returns false
// if not canceled it's the evdata object
if ( typeof result == "boolean" )
return;
if (evdata.requiresImage && !CKEDITOR.plugins.simpleuploads.isImageExtension(filePickerEditor, evdata.name))
{
alert(filePickerEditor.lang.simpleuploads.nonImageExtension);
return;
}
if (IEUpload_callback && IEUpload_callback.start)
IEUpload_callback.start( evdata );
IEUpload_fileName = this.value;
this.form.action = evdata.url;
// Add extra fields if provided
if (evdata.extraFields)
{
var obj = evdata.extraFields;
var doc = this.ownerDocument;
for (var prop in obj)
{
if( obj.hasOwnProperty( prop ) )
{
var field = doc.createElement("input");
field.type="hidden";
field.name = prop;
field.value = obj[prop];
this.form.appendChild(field);
}
}
}
this.form.submit();
};
picker.click();
}, 100);
}, editor);
editor.on( "destroy", function () {
CKEDITOR.tools.removeFunction( this._.simpleuploadsFormUploadFn );
CKEDITOR.tools.removeFunction( this._.simpleuploadsFormInitFn );
} );
}
var inputName = getUploadInputName(editor);
var form = "
";
var src= 'document.open(); document.write("' + form + '");document.close();' +
'window.parent.CKEDITOR.tools.callFunction(' + fnInitPicker + ');';
iframe.src = 'javascript:void(function(){' + encodeURIComponent( src ) + '}())';
// Detect when the file upload ends to check for errors
iframe.onreadystatechange = function() {
if (iframe.readyState == "complete") {
window.setTimeout(function() {
if (IEUpload_fileName)
{
alert("The file upload has failed");
IEUpload_fileName=null;
}
}, 100);
}
};
filePicker = null;
return;
}
if (!filePicker)
{
filePicker=document.createElement("input");
filePicker.type="file";
filePicker.style.overflow="hidden";
filePicker.style.width="1px";
filePicker.style.height="1px";
filePicker.style.opacity=0.1;
filePicker.multiple = "multiple";
// to trick jQueryUI
filePicker.position = "absolute";
filePicker.zIndex = 1000;
document.body.appendChild(filePicker);
filePicker.addEventListener("change", function ()
{
var count = filePicker.files.length;
if (!count)
return;
// Create Undo image
filePickerEditor.fire( "saveSnapshot" );
for(var i=0; i 0 ; i-- )
throbberBlocks[i].className = throbberBlocks[i-1].className ;
// For the first one, copy the last class (rotation).
throbberBlocks[0].className = lastClass ;
},
create: function( dialog )
{
if (this.throbberCover)
return;
var cover = CKEDITOR.dom.element.createFromHtml( '');
dialog.parts.close.setStyle("z-index", 101);
// IE8
if (CKEDITOR.env.ie && CKEDITOR.env.version<9)
{
cover.setStyle("zoom", 1);
cover.setStyle("filter", "progid:DXImageTransform.Microsoft.gradient(startColorstr=#EEFFFFFF,endColorstr=#EEFFFFFF)");
}
cover.appendTo(dialog.parts.dialog);
this.throbberCover = cover;
//dialog.throbberCover = cover;
var mainThrobber = new CKEDITOR.dom.element("div");
this.mainThrobber = mainThrobber;
var throbberParent = new CKEDITOR.dom.element("div");
this.throbberParent = throbberParent;
var throbberTitle = new CKEDITOR.dom.element("div");
this.throbberTitle = throbberTitle;
cover.append(mainThrobber).addClass("cke_throbberMain");
mainThrobber.append(throbberTitle).addClass("cke_throbberTitle");
mainThrobber.append(throbberParent).addClass("cke_throbber");
// Create the throbber blocks.
var classIds = [ 1,2,3,4,5,4,3,2 ] ;
while ( classIds.length > 0 )
throbberParent.append( new CKEDITOR.dom.element("div") ).addClass('cke_throbber_' + classIds.shift()) ;
this.center();
// Protection if the dialog is closed without removing the throbber
dialog.on("hide", this.hide, this);
},
center : function()
{
var mainThrobber = this.mainThrobber,
cover = this.throbberCover;
// Center the throbber
var x = ( cover.$.offsetWidth - mainThrobber.$.offsetWidth ) / 2,
y = ( cover.$.offsetHeight - mainThrobber.$.offsetHeight ) / 2;
mainThrobber.setStyle( "left", x.toFixed() + "px" );
mainThrobber.setStyle( "top", y.toFixed() + "px" );
},
show : function()
{
this.create(CKEDITOR.dialog.getCurrent());
this.throbberCover.setStyle("visibility", "");
// Setup the animation interval.
this.timer = setInterval( CKEDITOR.tools.bind(this.update, this), 100 ) ;
},
hide : function()
{
if ( this.timer )
{
clearInterval( this.timer ) ;
this.timer = null ;
}
if (!this.throbberCover)
return;
this.throbberCover.setStyle("visibility", "hidden");
}
};
}
this.throbber.show();
};
// Add a listener to check file size and valid extensions
editor.on( "simpleuploads.startUpload" , function(ev)
{
var editor = ev.editor,
config = editor.config,
file = ev.data && ev.data.file;
if (config.simpleuploads_maxFileSize &&
file && file.size &&
file.size > config.simpleuploads_maxFileSize )
{
alert( editor.lang.simpleuploads.fileTooBig );
ev.cancel();
}
var name = ev.data.name;
if (config.simpleuploads_invalidExtensions)
{
var reInvalid = new RegExp( "\.(?:" + config.simpleuploads_invalidExtensions + ")$", "i");
if ( reInvalid.test( name ) )
{
alert( editor.lang.simpleuploads.invalidExtension );
ev.cancel();
}
}
if (config.simpleuploads_acceptedExtensions)
{
var reAccepted = new RegExp( "\.(?:" + config.simpleuploads_acceptedExtensions + ")$", "i");
if ( !reAccepted.test( name ) )
{
alert( editor.lang.simpleuploads.nonAcceptedExtension.replace("%0", config.simpleuploads_acceptedExtensions) );
ev.cancel();
}
}
});
// Special listener that captures uploads of images and if there's some listener set for "simpleuploads.localImageReady"
// event, prepare an image with the local data (to check dimensions, convert between formats, resize...)
editor.on( 'simpleuploads.startUpload' , function(ev) {
var data = ev.data,
editor = ev.editor;
// If this function has already pre-processed the file, exit.
if (data.image)
return;
// Handle here only images
if (data.forceLink || !CKEDITOR.plugins.simpleuploads.isImageExtension(editor, data.name))
return;
// If the mode hasn't been set (picked files in IE8), don't process the data
if (!data.mode || !data.mode.type)
return;
// As this forces an asynchronous callback use it only when there's a listener set.
if (!editor.hasListeners( 'simpleuploads.localImageReady' ))
return;
// Cancel the default processing
ev.cancel();
if (data.mode.type=="base64paste")
{
// to handle multiple images in IE11, insert a marker for each one.
// we add our class so it won't remain if it's rejected in another step
var idTmp = CKEDITOR.plugins.simpleuploads.getTimeStampId();
data.result = " ";
data.mode.id = idTmp;
}
var img = new Image;
img.onload = function() {
var evData = CKEDITOR.tools.extend({}, data);
evData.image = img;
var result = editor.fire('simpleuploads.localImageReady', evData);
// in v3 cancel() returns true and in v4 returns false
// if not canceled it's the evdata object
if ( typeof result == "boolean" )
return;
CKEDITOR.plugins.simpleuploads.insertProcessedFile(ev.editor, evData);
};
if (typeof data.file == "string")
img.src = data.file; // base64 encoded
else
img.src = nativeURL.createObjectURL( data.file ); // FileReader
});
// Setup listeners if the config specifies that they should be used
if (config.simpleuploads_convertBmp)
editor.on( 'simpleuploads.localImageReady', convertToBmp);
if (config.simpleuploads_maximumDimensions)
editor.on( 'simpleuploads.localImageReady', checkDimension);
// workaround for image2 support
editor.on( 'simpleuploads.finishedUpload' , function(ev) {
if (editor.widgets && editor.plugins.image2) {
var element = ev.data.element;
if (element.getName()=="img")
{
var widget = editor.widgets.getByElement(element);
if (widget)
{
widget.data.src = element.data( 'cke-saved-src' );
widget.data.width = element.$.width;
widget.data.height = element.$.height;
}
else
{
// They have renamed the widget after the initial release :-(
// Let's try with both, one of them will work
editor.widgets.initOn(element, "image2");
editor.widgets.initOn(element, "image");
}
}
}
});
// Paste from clipboard:
editor.on( "paste", function(e) {
var pasteData = e.data,
html = (pasteData.html || ( pasteData.type && pasteData.type=='html' && pasteData.dataValue));
if (!html)
return;
// strip out webkit-fake-url as they are useless:
if (CKEDITOR.env.webkit && (html.indexOf("webkit-fake-url")>0) )
{
alert("Sorry, the images pasted with Safari aren't usable");
window.open("https://bugs.webkit.org/show_bug.cgi?id=49141");
html = html.replace( /
/g, "");
}
// Handles image pasting in Firefox
// Replace data: images in Firefox and upload them.
// No longer required with Firefox 22
html = html.replace( /
/g, function( img )
{
if (!editor.config.filebrowserImageUploadUrl)
return "";
var match = img.match(/"(data:image\/(.{3,4});base64,.*?)"/),
imgData = match[1],
type = match[2].toLowerCase(),
id = CKEDITOR.plugins.simpleuploads.getTimeStampId();
// If it's too small then leave it as is.
if (imgData.length<128)
return img;
if (type=="jpeg")
type="jpg";
var fileName = id + '.' + type,
uploadData = {
context : "pastedimage",
name : fileName,
id : id,
forceLink : false,
file : imgData,
mode : { type: "base64paste"}
};
if (!uploadFile(editor, uploadData))
return uploadData.result;
var animation = uploadData.element,
content = animation.$.innerHTML;
animation.$.innerHTML = " ";
// only once
editor.on( "afterPaste" , function( ev ) {
ev.removeListener();
var span = editor.document.$.getElementById(id);
if (!span)
return;
// fight against ACF in v4.1 and IE11, insert svg afterwards
span.innerHTML = content;
setupCancelButton( editor, uploadData );
} );
return animation.getOuterHtml();
});
if (e.data.html)
e.data.html = html;
else
e.data.dataValue = html;
});
var avoidBadUndo = function(e) {
if (editor.mode != "wysiwyg")
return;
var root = editor.document;
if (editor.editable)
root = editor.editable();
// detect now if the contents include our tmp node
if (root.$.querySelector( ".SimpleUploadsTmpWrapper") )
{
var move = e.name.substr(5).toLowerCase();
// If the user tried to redo but there are no more saved images forward and this is a bad image, move back instead.
if ( move=="redo" && editor.getCommand(move).state == CKEDITOR.TRISTATE_DISABLED )
move = "undo";
// Move one extra step back/forward
editor.execCommand( move );
}
};
// on dev mode plugins might not load in the right order with empty cache
var cmd = editor.getCommand('undo');
cmd && cmd.on('afterUndo', avoidBadUndo );
cmd = editor.getCommand('redo');
cmd && editor.getCommand('redo').on('afterRedo', avoidBadUndo );
// http://dev.ckeditor.com/ticket/10101
editor.on('afterUndo', avoidBadUndo );
editor.on('afterRedo', avoidBadUndo );
// Buttons to launch the file picker easily
// Files
editor.addCommand( 'addFile', {
exec: function( editor ) {
PickAndSendFile(editor, false, this);
}
});
editor.ui.addButton( 'addFile', {
label: editor.lang.simpleuploads.addFile,
command: 'addFile',
icon : this.path + 'icons/addfile.png', // %REMOVE_LINE_CORE%
toolbar: 'insert',
allowedContent : 'a[!href];span[id](SimpleUploadsTmpWrapper);',
requiredContent : 'a[href]'
});
// Images
editor.addCommand( 'addImage', {
exec: function( editor ) {
PickAndSendFile(editor, true, this);
}
});
editor.ui.addButton( 'addImage', {
label: editor.lang.simpleuploads.addImage,
command: 'addImage',
icon : this.path + 'icons/addimage.png', // %REMOVE_LINE_CORE%
toolbar: 'insert',
allowedContent : 'img[!src,width,height];span[id](SimpleUploadsTmpWrapper);',
requiredContent : 'img[src]'
});
if (typeof FormData == 'undefined')
return;
var root,
visibleRoot,
pasteRoot;
var minX=-1, minY, maxX, maxY;
// Hint in the main document
var mainMinX=-1, mainMinY, mainMaxX, mainMaxY;
var removeBaseHighlight = function() {
var dialog = CKEDITOR.dialog.getCurrent();
if ( dialog )
{
var div = dialog.parts.title.getParent();
div.removeClass( 'SimpleUploadsOverCover' );
}
else
{
editor.container.removeClass( 'SimpleUploadsOverContainer' );
}
};
editor.on( 'destroy', function() {
CKEDITOR.removeListener( 'simpleuploads.droppedFile', removeBaseHighlight);
CKEDITOR.document.removeListener( 'dragenter', CKEDITORdragenter);
CKEDITOR.document.removeListener( 'dragleave', CKEDITORdragleave);
domUnload();
});
var domUnload = function() {
if (!root || !root.removeListener)
return;
pasteRoot.removeListener( 'paste', pasteListener);
root.removeListener( 'dragenter', rootDragEnter);
root.removeListener( 'dragleave', rootDragLeave);
root.removeListener( 'dragover', rootDragOver);
root.removeListener( 'drop', rootDropListener);
pasteRoot = null;
root = null;
visibleRoot = null;
};
CKEDITOR.on( 'simpleuploads.droppedFile', removeBaseHighlight);
var CKEDITORdragenter = function(e) {
if (mainMinX == -1)
{
if (!hasFiles(e))
return;
var dialog = CKEDITOR.dialog.getCurrent();
if ( dialog )
{
if (!dialog.handleFileDrop)
return;
var div = dialog.parts.title.getParent();
div.addClass( 'SimpleUploadsOverCover' );
}
else
{
if (!editor.readOnly)
editor.container.addClass( 'SimpleUploadsOverContainer' );
}
mainMinX=0;
mainMinY=0;
mainMaxX=CKEDITOR.document.$.body.parentNode.clientWidth;
mainMaxY=CKEDITOR.document.$.body.parentNode.clientHeight;
}
};
var CKEDITORdragleave = function(e) {
if ( mainMinX == -1 )
return;
var ev = e.data.$;
if ((ev.clientX<=mainMinX) || (ev.clientY<=mainMinY) || (ev.clientX>=mainMaxX) || (ev.clientY>=mainMaxY))
{
removeBaseHighlight();
mainMinX = -1;
}
};
CKEDITOR.document.on( 'dragenter', CKEDITORdragenter);
CKEDITOR.document.on( 'dragleave', CKEDITORdragleave);
var rootDropListener = function(e) {
// editor
visibleRoot.removeClass( "SimpleUploadsOverEditor" );
minX = -1;
//container
// We fire an event on CKEDITOR so all the instances get notified and remove their class
// This is an "internal" event to the plugin
CKEDITOR.fire( 'simpleuploads.droppedFile' );
mainMinX = -1;
if (editor.readOnly)
{
e.data.preventDefault();
return false;
}
var ev = e.data.$,
data = ev.dataTransfer;
if ( data && data.files && data.files.length>0 )
{
// Create Undo image
editor.fire( "saveSnapshot" );
// Prevent default insertion
e.data.preventDefault();
var dropLocation = {
ev : ev,
range : false,
count : data.files.length,
rangeParent : ev.rangeParent,
rangeOffset : ev.rangeOffset
};
// store the location for IE
if (!dropLocation.rangeParent && !document.caretRangeFromPoint)
{
if (ev.target.nodeName.toLowerCase()!="img")
{
var doc = editor.document.$;
if ( doc.body.createTextRange )
{
var textRange = doc.body.createTextRange();
try
{
textRange.moveToPoint( ev.clientX, ev.clientY );
dropLocation.range = textRange;
}
catch (ex)
{
}
}
}
}
for( var i=0; i=maxX) || (ev.clientY>=maxY))
{
visibleRoot.removeClass( "SimpleUploadsOverEditor" );
minX = -1;
}
};
var rootDragOver = function(e) {
if (minX != -1 )
{
if (editor.readOnly)
{
e.data.$.dataTransfer.dropEffect = "none";
e.data.preventDefault();
return false;
}
// Show Copy instead of Move. Works for Chrome
// Firefox and IE10 don't respect this change (Firefox by default doesn't enter here)
// https://bugzilla.mozilla.org/show_bug.cgi?id=484511
e.data.$.dataTransfer.dropEffect = 'copy';
// IE always requires this
// Chrome almost fixed the requirement, but it's required if the body is a single line and the user drops below it.
if (!CKEDITOR.env.gecko)
e.data.preventDefault();
}
};
// drag & drop, paste
editor.on( 'contentDom', function(ev) {
root = editor.document;
visibleRoot = root.getBody().getParent();
// v4 inline editing
// ELEMENT_MODE_INLINE
if (editor.elementMode == 3 )
{
root = editor.editable();
visibleRoot = root;
}
// v4 divArea
if ( editor.elementMode == 1 && 'divarea' in editor.plugins )
{
root = editor.editable();
visibleRoot = root;
}
pasteRoot = editor.editable ? editor.editable() : root;
// Special case for IE in forcePasteAsPlainText:
// CKEditor uses the beforepaste event to move the target, but we can't use that to check for files,
// so in that case, set a listener on the document on each paste
if (CKEDITOR.env.ie && CKEDITOR.env.version>=11 && editor.config.forcePasteAsPlainText && editor.editable().isInline())
{
// Is an editable instance, so let's use attachListener here
pasteRoot.attachListener(pasteRoot, "beforepaste", function( bpEv ) {
// Only once, so we can check always which editor the paste belongs to
editor.document.on( "paste", function( pEv ) {
pEv.removeListener();
// redirect the original data to our paste listener
pasteListener(pEv);
}, null, {editor : editor });
});
}
else
{
// For everyone else, use the normal paste event
pasteRoot.on( "paste", pasteListener, null, {editor : editor }, 8);
}
root.on( 'dragenter', rootDragEnter);
root.on( 'dragleave', rootDragLeave);
// https://bugs.webkit.org/show_bug.cgi?id=57185
if ( !CKEDITOR.env.gecko )
{
root.on( 'dragover', rootDragOver);
}
// Must use CKEditor 3.6.3 for IE 10
root.on( 'drop', rootDropListener);
});
editor.on( 'contentDomUnload', domUnload);
editor.plugins.fileDropHandler = {
addTarget : function( target, callback )
{
target.on( 'dragenter', function(e) {
if (minX == -1)
{
if (!hasFiles(e))
return;
target.addClass( 'SimpleUploadsOverDialog' );
var rect = target.$.getBoundingClientRect();
minX=rect.left;
minY=rect.top;
maxX=minX + target.$.clientWidth;
maxY=minY + target.$.clientHeight;
}
});
target.on( 'dragleave', function(e) {
if ( minX == -1 )
return;
var ev = e.data.$;
if ((ev.clientX<=minX) || (ev.clientY<=minY) || (ev.clientX>=maxX) || (ev.clientY>=maxY))
{
target.removeClass( 'SimpleUploadsOverDialog' );
minX = -1;
}
});
target.on( 'dragover', function(e) {
if (minX != -1 )
{
// Show Copy instead of Move. Works for Chrome
// Firefox and IE10 don't respect this change (Firefox by default doesn't enter here)
// https://bugzilla.mozilla.org/show_bug.cgi?id=484511
e.data.$.dataTransfer.dropEffect = 'copy';
e.data.preventDefault();
}
});
target.on( 'drop', function(e) {
target.removeClass( 'SimpleUploadsOverDialog' );
minX = -1;
//container
// We fire an event on CKEDITOR so all the instances get notified and remove their class
// This is an "internal" event to the plugin
CKEDITOR.fire( 'simpleuploads.droppedFile' );
mainMinX = -1;
var ev = e.data.$,
data = ev.dataTransfer;
if ( data && data.files && data.files.length>0 )
{
// Prevent default insertion
e.data.preventDefault();
// only one
for( var i=0; i<1; i++)
{
var file = data.files[ i ];
var evData = {
context : ev,
name : file.name,
file : file,
id : CKEDITOR.tools.getNextId(),
forceLink : false,
callback : callback,
mode : { type: "callback" }
};
CKEDITOR.plugins.simpleuploads.processFileWithCallback( editor, evData );
}
}
});
}
};
}, //Init
afterInit: function( editor ) {
var dataProcessor = editor.dataProcessor,
htmlFilter = dataProcessor && dataProcessor.htmlFilter;
if ( htmlFilter )
htmlFilter.addRules( htmlFilterRules , {applyToAll :true} );
}
} );
// API
CKEDITOR.plugins.simpleuploads = {
getTimeStampId : (function()
{
var counter = 0;
return function()
{
counter++;
return (new Date()).toISOString().replace(/\..*/, "").replace(/\D/g, "_") + counter;
};
})(),
isImageExtension: function(editor, filename)
{
if (!editor.config.simpleuploads_imageExtensions)
return false;
var imageRegexp = new RegExp( "\.(?:" + editor.config.simpleuploads_imageExtensions + ")$", "i");
return imageRegexp.test( filename );
},
// Main entry point for callbacks
insertProcessedFile: function(editor, evData) {
evData.element = null;
evData.id = this.getTimeStampId(); // new id
var that = this;
switch (evData.mode.type)
{
case 'selectedFile':
window.setTimeout( function() {
that.insertSelectedFile( editor, evData );
}, 50);
break;
case 'pastedFile':
this.insertPastedFile( editor, evData );
break;
case 'callback':
window.setTimeout( function() {
that.processFileWithCallback( editor, evData );
}, 50);
break;
case 'droppedFile':
this.insertDroppedFile( editor, evData );
break;
case 'base64paste':
this.insertBase64File( editor, evData );
break;
default:
alert("Error, no valid type", evData.mode);
break;
}
},
// Insert a file from the toolbar buttons
insertSelectedFile: function(editor, evData) {
var mode = evData.mode,
i = mode.i,
count = mode.count;
// Upload the file
if (!uploadFile( editor, evData ))
return;
var element = evData.element;
if (!element)
return;
if (count == 1)
{
var selection = editor.getSelection(),
selected = selection.getSelectedElement(),
originalNode;
// If it's just one image and the user has another one selected, replace it
if (selected && selected.getName() == "img" && element.getName() == "span")
{
originalNode = selected.$;
}
// Image2 widget
if (editor.widgets)
{
var focused = editor.widgets.focused;
if (focused && focused.wrapper.equals(selected))
{
originalNode = selected.$.querySelector("img");
}
}
// a link
if (element.getName() == "a")
{
var parent = selected,
ranges = selection.getRanges(),
range = ranges && ranges[0];
if (!parent)
{
if (ranges && ranges.length == 1)
{
parent = range.startContainer.$;
if (parent.nodeType == document.TEXT_NODE)
parent = parent.parentNode;
}
}
while ( parent && (parent.nodeType == document.ELEMENT_NODE) && (parent.nodeName.toLowerCase() != "a") )
parent = parent.parentNode;
if ( parent && parent.nodeName && parent.nodeName.toLowerCase() == "a" )
{
originalNode = parent;
}
// there was no link, check the best way to create one:
// create a link
if (!originalNode && range && (selected || !range.collapsed) )
{
var style = new CKEDITOR.style({ element: 'a', attributes: {href:'#'} } );
style.type = CKEDITOR.STYLE_INLINE; // need to override... dunno why.
style.applyToRange( range );
parent = range.startContainer.$;
if (parent.nodeType == document.TEXT_NODE)
parent = parent.parentNode;
originalNode = parent;
}
}
if (originalNode)
{
originalNode.parentNode.replaceChild(element.$, originalNode);
evData.originalNode = originalNode;
editor.fire( "saveSnapshot" );
return;
}
}
// insert a space between links
if (i>0 && element.getName()=="a")
editor.insertHtml(" ");
editor.insertElement(element);
setupCancelButton( editor, evData );
},
// Insert a file that has been pasted into the content (as File)
insertPastedFile: function(editor, evData) {
// Upload the file
if (!uploadFile( editor, evData ))
return;
var element = evData.element;
var dialog = evData.mode.dialog;
if (dialog)
{
editor.fire( "updateSnapshot" );
editor.insertElement(element);
editor.fire( "updateSnapshot" );
}
else
{
// Insert in the correct position after the pastebin has been removed
var processElement = function() {
// Check if there's a valid selection or if it's the pastebin
var ranges = editor.getSelection().getRanges();
if (!ranges.length)
{
// Put back in the queue
window.setTimeout(processElement, 0);
return;
}
// verify that it has really been removed
if (editor.editable && editor.editable().$.querySelector("#cke_pastebin"))
{
// Put back in the queue
window.setTimeout(processElement, 0);
return;
}
editor.fire( "updateSnapshot" );
editor.insertElement(element);
editor.fire( "updateSnapshot" );
setupCancelButton( editor, evData );
};
window.setTimeout(processElement, 0);
}
},
// The evData includes a callback that takes care of everything (a file dropped in a dialog)
processFileWithCallback: function(editor, evData) {
uploadFile( editor, evData );
},
insertDroppedFile: function(editor, evData) {
if (!uploadFile( editor, evData ))
return;
var element = evData.element;
var dropLocation = evData.mode.dropLocation,
range = dropLocation.range,
ev = dropLocation.ev,
count = dropLocation.count;
// if we're adding several links, add a space between them
if ( range && element.getName()=="a" )
{
if ( range.pasteHTML )
range.pasteHTML( " " ); // simple space doesn't work
else
range.insertNode( editor.document.$.createTextNode( ' ' ) );
}
var target = ev.target;
if (!range)
{
var doc = editor.document.$;
// Move to insertion point
/*
standard way: only implemented in Firefox 20
if (document.caretPositionFromPoint)
{
var caret = document.caretPositionFromPoint(ev.pageX, ev.pageY),
textNode = caret.offsetNode,
offset = caret.offset;
}
*/
// Firefox, custom properties in event.
if ( dropLocation.rangeParent )
{
// it seems that they aren't preserved in the ev after resending back the info
var node = dropLocation.rangeParent,
offset = dropLocation.rangeOffset;
range = doc.createRange();
range.setStart( node, offset );
range.collapse( true );
}
else
{
// Webkit, old documentView API
if ( document.caretRangeFromPoint )
{
range = doc.caretRangeFromPoint( ev.clientX, ev.clientY );
}
else
{
// IE
if (target.nodeName.toLowerCase()=="img")
{
range = doc.createRange();
range.selectNode(target);
} else if ( document.body.createTextRange )
{
var textRange = doc.body.createTextRange();
try
{
textRange.moveToPoint( ev.clientX, ev.clientY );
/*
// Convert to W3C range:
var node = textRange.parentElement();
var start = Math.abs( textRange.duplicate().moveStart('character', -1000000) );
var r = textRange.duplicate();
r.moveToElementText( node );
r.collapse();
var start2 = Math.abs( r.moveStart('character', -1000000) );
range = doc.createRange();
range.setStart( node.firstChild, start - start2 );
range.collapse( true );
*/
range = textRange;
}
catch (ex)
{
range = doc.createRange();
range.setStartAfter( doc.body.lastChild );
range.collapse( true );
}
}
}
}
dropLocation.range = range;
}
var elementName = element.getName(),
handled = false;
if ( count==1 )
{
if (target.nodeName.toLowerCase() == "img" && elementName == "span" )
{
target.parentNode.replaceChild(element.$, target);
evData.originalNode = target;
handled = true;
}
if ( elementName == "a" )
{
var start;
if (range.startContainer)
{
start = range.startContainer;
if (start.nodeType == document.TEXT_NODE)
start = start.parentNode;
else
{
if (range.startOffset < start.childNodes.length)
start = start.childNodes[ range.startOffset ];
}
}
else
start = range.parentElement();
if (!start || target.nodeName.toLowerCase() == "img")
start = target;
var parent = start;
while ( parent && (parent.nodeType == document.ELEMENT_NODE) && (parent.nodeName.toLowerCase() != "a") )
parent = parent.parentNode;
if ( parent && parent.nodeName && parent.nodeName.toLowerCase() == "a" )
{
parent.parentNode.replaceChild(element.$, parent);
evData.originalNode = parent;
handled = true;
}
// dropping on an image without a parent link
if ( !handled && start.nodeName.toLowerCase() == "img" )
{
parent = start.ownerDocument.createElement('a');
parent.href = '#';
start.parentNode.replaceChild(parent, start);
parent.appendChild(start);
parent.parentNode.replaceChild(element.$, parent);
evData.originalNode = parent;
handled = true;
}
}
}
if (!handled)
{
if (range)
{
if ( range.pasteHTML )
range.pasteHTML( element.$.outerHTML );
else
range.insertNode( element.$ );
}
else
editor.insertElement( element );
}
setupCancelButton( editor, evData );
editor.fire( "saveSnapshot" );
},
insertBase64File: function(editor, evData) {
delete evData.result;
var id = evData.mode.id;
var tmp = editor.document.getById(id);
if (!uploadFile(editor, evData))
{
tmp.remove();
if (evData.result)
editor.insertHTML(evData.result);
return;
}
editor.getSelection().selectElement(tmp);
editor.insertElement(evData.element);
setupCancelButton( editor, evData );
}
};
// Creates the element, but doesn't insert it
function createPreview(editor, data)
{
var isImage = CKEDITOR.plugins.simpleuploads.isImageExtension( editor, data.name ),
showImageProgress = !editor.config.simpleuploads_hideImageProgress,
element;
// Create and insert our element
if ( !data.forceLink && isImage && showImageProgress)
{
element = createSVGAnimation(data.file, data.id, editor);
}
else
{
if ( isImage && !data.forceLink )
element = new CKEDITOR.dom.element( "span", editor.document );
else
element = new CKEDITOR.dom.element( "a", editor.document );
element.setAttribute( "id", data.id );
element.setAttribute( "class", "SimpleUploadsTmpWrapper");
//element.setText( data.name );
var html = "" + data.name + "" +
" " +
" x";
element.setHtml(html);
}
// Prevent selection handles in IE
element.setAttribute( 'contentEditable', false );
data.element=element;
}
function errorListener(e)
{
e.removeListener();
alert("Failed to load the image with the provided URL: '" + e.sender.data( 'cke-saved-src') + "'");
e.listenerData.remove();
}
function checkLoadedImage(img, editor, el, name)
{
if (img.$.naturalWidth === 0)
{
// when replacing an image, IE might fire the load event, but it still uses the old data
window.setTimeout( function() {checkLoadedImage(img, editor, el, name);}, 50);
return;
}
img.replace( el );
img.setAttribute("width", img.$.width);
img.setAttribute("height", img.$.height);
editor.fire('simpleuploads.finishedUpload', { name: name, element: img } );
// Correct the Undo image
editor.fire( "updateSnapshot" );
}
// Sets up a XHR object to handle the upload
function createXHRupload(editor, data)
{
var isImage = CKEDITOR.plugins.simpleuploads.isImageExtension( editor, data.name ),
attribute = "href",
forImage = false;
if ( !data.forceLink && isImage )
{
attribute = "src";
forImage=true;
}
if (data.callback)
data.callback.setup(data);
if (!data.url)
data.url = getUploadUrl(editor, 2, forImage);
if (data.requiresImage && !isImage)
{
alert(editor.lang.simpleuploads.nonImageExtension);
return null;
}
var result = editor.fire("simpleuploads.startUpload", data);
// in v3 cancel() returns true and in v4 returns false
// if not canceled it's the data object, so let's use that.
if ( typeof result == "boolean" )
return null;
// instead of uploading, use base64 encoded data
if (data.url == "base64")
{
if (typeof data.file == "string")
{
setTimeout( function() {
var fileUrl = data.file,
id = data.id,
el = editor.document.getById( id );
receivedUrl(fileUrl, data, editor, el, attribute);
}, 100);
return {};
}
else
{
var reader = new FileReader();
reader.onload = function() {
setTimeout( function() {
var fileUrl = reader.result,
id = data.id,
el = editor.document.getById( id );
receivedUrl(fileUrl, data, editor, el, attribute);
}, 100);
};
reader.readAsDataURL( data.file );
}
return {};
}
var xhr = new XMLHttpRequest(),
target = xhr.upload;
// nice progress effect. Opera used to lack xhr.upload
if ( target )
{
target.onprogress = function( evt )
{
updateProgress(editor, data.id, evt);
};
}
data.xhr = xhr;
// Upload the file
xhr.open("POST", data.url );
xhr.onload = function() {
var id = data.id,
el = editor.document.getById( id ),
fileUrl, msg;
// final update
updateProgress(editor, id, null);
// Correct the Undo image
editor.fire( "updateSnapshot" );
var evtData = { xhr: xhr, data: data, element:el };
var result = editor.fire("simpleuploads.serverResponse", evtData);
// in v3 cancel() returns true and in v4 returns false
// if not canceled it's the evdata object
if ( typeof result == "boolean" )
return; // if the listener has Cancelled the event, exit and we suppose that it took care of everything by itself.
// Check if the event has been listened and performed its own parsing
if (typeof evtData.url == "undefined")
{
// Upon finish, get the url and update the file
//var parts = xhr.responseText.match(/2,\s*("|')(.*?[^\\]?)\1(?:,\s*\1(.*?[^\\]?)\1)?\s*\)/),
//var parts = xhr.responseText.match(/\((?:"|')?\d+(?:"|')?,\s*("|')(.*?[^\\]?)\1(?:,\s*(.*?))?\s*\)\s*;?\s*<\/script>/),
var parts = xhr.responseText.match(/\((?:"|')?\d+(?:"|')?,\s*("|')(.*?[^\\]?)\1(?:,\s*(.*?))?\s*\)\s*;?/);
fileUrl = parts && parts[2];
msg = parts && parts[3];
// The server response usually is automatically parsed by the js engine, but in this case we get the "raw content"
// and must take care of un-escaping it.
// So far I haven't been able to find a single function that does it correctly in all the cases
if (fileUrl)
{
fileUrl = fileUrl.replace(/\\'/g, "'");
// Try to handle URLs with escaped chars like 51-Body/\u00E6\u00F8\u00E5.jpg
try
{
var o = JSON.parse('{"url":"' + fileUrl + '"}');
if (o && o.url)
fileUrl = o.url;
}
catch (ex) { }
}
if (msg)
{
// find out if it was a function or a string message:
var matchFunction = msg.match(/function\(\)\s*\{(.*)\}/);
if (matchFunction)
msg = new Function( matchFunction[1] );
else
{
var first=msg.substring(0,1);
if (first=="'" || first=='"')
msg = msg.substring( 1, msg.length-1 );
}
}
if (!parts)
{
msg = 'Error posting the file to ' + data.url + '\r\nInvalid data returned (check console)';
if (window.console)
console.log(xhr.responseText);
}
}
else
{
fileUrl = evtData.url;
msg = "";
}
editor.fire('simpleuploads.endUpload', { name: data.name, ok: (!!fileUrl), xhr : xhr, data : data } );
if (xhr.status!=200)
{
if (xhr.status == 413)
alert( editor.lang.simpleuploads.fileTooBig );
else
alert('Error posting the file to ' + data.url + '\r\nResponse status: ' + xhr.status);
if (window.console)
console.log(xhr);
}
if (data.callback)
{
if (!fileUrl && msg)
alert( msg );
data.callback.upload(fileUrl, msg, data);
return;
}
// If the element doesn't exists it means that the user has deleted it or pressed undo while uploading
// so let's get out
if (!el)
return;
if ( fileUrl )
{
receivedUrl(fileUrl, data, editor, el, attribute);
}
else
{
if (data.originalNode)
el.$.parentNode.replaceChild(data.originalNode, el.$);
else
el.remove();
if (msg)
alert( msg );
}
// Correct undo image
editor.fire( "updateSnapshot" );
};
xhr.onerror = function(e) {
alert('Error posting the file to ' + data.url );
if (window.console)
console.log(e);
var el = editor.document.getById( data.id );
if (el)
{
if (data.originalNode)
el.$.parentNode.replaceChild(data.originalNode, el.$);
else
el.remove();
}
// Correct undo image
editor.fire( "updateSnapshot" );
};
xhr.onabort = function(e) {
if (data.callback)
{
data.callback.upload(null);
return;
}
var el = editor.document.getById( data.id );
if (el)
{
if (data.originalNode)
el.$.parentNode.replaceChild(data.originalNode, el.$);
else
el.remove();
}
// Correct undo image
editor.fire( "updateSnapshot" );
};
// CORS https://developer.mozilla.org/en-US/docs/HTTP/Access_control_CORS
xhr.withCredentials = true;
return xhr;
}
// Takes care of uploading the file using XHR
function uploadFile(editor, data)
{
if (!data.callback)
createPreview(editor, data);
var xhr = createXHRupload(editor, data);
if (!xhr)
{
data.result = data.result || "";
return false;
}
// FileReader
if (!xhr.send)
return true;
if (data.callback && data.callback.start)
data.callback.start(data);
var inputName = data.inputName|| getUploadInputName(editor);
if (typeof data.file == "string")
sendBase64File( data, xhr, inputName);
else
sendBlobFile( data, xhr, inputName);
return true;
}
function sendBlobFile(data, xhr, inputName)
{
var formdata = new FormData();
formdata.append( inputName, data.file, data.name );
// Add extra fields if provided
if (data.extraFields)
{
var obj = data.extraFields;
for (var prop in obj)
{
if( obj.hasOwnProperty( prop ) )
formdata.append( prop, obj[prop] );
}
}
if (data.extraHeaders) {
var headers = data.extraHeaders;
for (var header in headers){
if( headers.hasOwnProperty( header )){
xhr.setRequestHeader(header, headers[header]);
}
}
}
xhr.send( formdata );
}
function sendBase64File(data, xhr, inputName)
{
// Create the multipart data upload.
var BOUNDARY = "---------------------------1966284435497298061834782736",
rn = "\r\n",
req = "--" + BOUNDARY,
type = data.name.match(/\.(\w+)$/)[1];
req += rn + 'Content-Disposition: form-data; name="' + inputName + '"; filename="' + data.name + '"';
req += rn + "Content-type: image/" + type;
req += rn + rn + window.atob( data.file.split(',')[1] );
req += rn + "--" + BOUNDARY;
// Add extra fields if provided
if (data.extraFields)
{
var obj = data.extraFields;
for (var prop in obj)
{
req += rn + "Content-Disposition: form-data; name=\"" + unescape(encodeURIComponent( prop )).replace(/=/g, "\\=") + "\"";
req += rn + rn + unescape(encodeURIComponent( obj[prop] )) ;
req += rn + "--" + BOUNDARY;
}
}
req += "--";
xhr.setRequestHeader("Content-Type", "multipart/form-data; boundary=" + BOUNDARY);
/*
if (xhr.sendAsBinary)
xhr.sendAsBinary(req);
else
{
// emulate sendAsBinary for IE11 & Chrome
*/
var bufferData = new ArrayBuffer(req.length);
var ui8a = new Uint8Array(bufferData, 0);
for (var i = 0; i < req.length; i++)
ui8a[i] = (req.charCodeAt(i) & 0xff);
xhr.send(ui8a);
/*
}
*/
}
function updateProgress(editor, id, evt)
{
if (!editor.document || !editor.document.$)
return;
var dialog = CKEDITOR.dialog.getCurrent();
var doc = (dialog ? CKEDITOR : editor ).document.$,
rect = doc.getElementById("rect" + id),
text = doc.getElementById("text" + id),
value, textValue;
if ( evt )
{
if ( !evt.lengthComputable )
return;
value = (100*evt.loaded/evt.total).toFixed(2) + "%";
textValue = (100*evt.loaded/evt.total).toFixed() + "%";
}
else
{
textValue = editor.lang.simpleuploads.processing;
value = "100%";
/*
if (text)
{
text.parentNode.removeChild(text);
text = null;
}
*/
}
if (rect)
{
rect.setAttribute("width", value);
rect.style.width = value;
if (!evt)
{
var parent = rect.parentNode;
if (parent && parent.className=="uploadRect")
parent.parentNode.removeChild(parent);
}
}
if (text)
{
text.firstChild.nodeValue = textValue;
if (!evt)
{
// Remove cancel button
var sibling = text.nextSibling;
if (sibling && sibling.nodeName.toLowerCase()=="a")
sibling.parentNode.removeChild(sibling);
}
}
}
// Show a grayscale version of the image that animates toward the full color version
function createSVGAnimation( file, id, editor )
{
var element = new CKEDITOR.dom.element( "span", editor.document ),
div = element.$,
useURL,
doc = editor.document.$,
span = doc.createElement("span");
element.setAttribute( "id", id );
element.setAttribute( "class", "SimpleUploadsTmpWrapper");
var rectSpan = doc.createElement("span");
rectSpan.setAttribute( "id" , "text" + id);
rectSpan.appendChild( doc.createTextNode("0 %"));
div.appendChild(span);
span.appendChild(rectSpan);
var cancelSpan = doc.createElement("span");
cancelSpan.appendChild( doc.createTextNode('x'));
span.appendChild(cancelSpan);
if (typeof file != "string")
{
if ( !nativeURL || !nativeURL.revokeObjectURL)
return element;
useURL = true;
}
var svg = doc.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute( "id" , "svg" + id);
// just to find out the image dimensions as they are needed for the svg block
var img = doc.createElement( "img" );
if (useURL)
{
img.onload = function(e) {
if (this.onload)
{
nativeURL.revokeObjectURL( this.src );
this.onload = null;
}
// in IE it's inserted with the HTML, so we can't reuse the svg object
var svg = doc.getElementById("svg" + id);
if (svg)
{
svg.setAttribute("width", this.width + "px");
svg.setAttribute("height", this.height + "px");
}
// Chrome
var preview = doc.getElementById(id);
if (preview)
preview.style.width = this.width + "px";
};
img.src = nativeURL.createObjectURL( file );
}
else
{
// base64 data, dimensions are available right now in Firefox
img.src = file;
// extra protection
img.onload = function(e) {
this.onload = null;
// we're pasting so it's inserted with the HTML, so we can't reuse the svg object
var svg = doc.getElementById("svg" + id);
if (svg)
{
svg.setAttribute("width", this.width + "px");
svg.setAttribute("height", this.height + "px");
}
};
svg.setAttribute("width", img.width + "px");
svg.setAttribute("height", img.height + "px");
}
div.appendChild(svg);
var filter = doc.createElementNS("http://www.w3.org/2000/svg", "filter");
filter.setAttribute("id", "SVGdesaturate");
svg.appendChild(filter);
var feColorMatrix = doc.createElementNS("http://www.w3.org/2000/svg", "feColorMatrix");
feColorMatrix.setAttribute("type", "saturate");
feColorMatrix.setAttribute("values", "0");
filter.appendChild(feColorMatrix);
var clipPath = doc.createElementNS("http://www.w3.org/2000/svg", "clipPath");
clipPath.setAttribute("id", "SVGprogress" + id);
svg.appendChild(clipPath);
var rect = doc.createElementNS("http://www.w3.org/2000/svg", "rect");
rect.setAttribute("id", "rect" + id);
rect.setAttribute("width", "0");
rect.setAttribute("height", "100%");
clipPath.appendChild(rect);
var image = doc.createElementNS("http://www.w3.org/2000/svg", "image");
image.setAttribute("width", "100%");
image.setAttribute("height", "100%");
if (useURL)
{
image.setAttributeNS('http://www.w3.org/1999/xlink',"href", nativeURL.createObjectURL( file ));
var loaded = function( e ) {
nativeURL.revokeObjectURL( image.getAttributeNS('http://www.w3.org/1999/xlink',"href") );
image.removeEventListener( "load", loaded, false);
};
image.addEventListener( "load", loaded, false);
}
else
image.setAttributeNS('http://www.w3.org/1999/xlink',"href", file );
var image2 = image.cloneNode(true);
image.setAttribute("filter", "url(#SVGdesaturate)");
image.style.opacity="0.5";
svg.appendChild(image);
image2.setAttribute("clip-path", "url(#SVGprogress" + id + ")");
svg.appendChild(image2);
return element;
}
// Compatibility between CKEditor 3 and 4
if (CKEDITOR.skins)
{
CKEDITOR.plugins.setLang = CKEDITOR.tools.override( CKEDITOR.plugins.setLang , function( originalFunction )
{
return function( plugin, lang, obj )
{
if (plugin != "devtools" && typeof obj[plugin] != "object")
{
var newObj = {};
newObj[ plugin ] = obj;
obj = newObj;
}
originalFunction.call(this, plugin, lang, obj);
};
});
}
function createSimpleUpload( editor, dialogName, definition, element )
{
if (element.type=="file")
return;
var forImage = (dialogName.substr(0,5)=="image" || element.requiresImage);
var targetField = element.filebrowser.target.split(":");
var callback = {
setup : function(data) {
if (!definition.uploadUrl)
return;
if (forImage)
data.requiresImage = true;
var params = {};
params.CKEditor = editor.name;
params.CKEditorFuncNum = 2;
params.langCode = editor.langCode;
data.url = addQueryString( definition.uploadUrl, params );
},
start : function(data) {
var dialog = CKEDITOR.dialog.getCurrent();
dialog.showThrobber();
var throbber = dialog.throbber;
if (data.xhr)
{
var html = "" + data.name + "" +
" " +
" x";
throbber.throbberTitle.setHtml(html);
var cover = throbber.throbberCover;
var xhr = data.xhr;
if ( cover.timer )
{
clearInterval( cover.timer ) ;
cover.timer = null ;
}
throbber.throbberParent.setStyle("display", "none");
throbber.throbberTitle.getLast().on('click', function() {
xhr.abort();
});
// protection to check that the upload isn't pending when forcing to close the dialog
dialog.on('hide', function() {
if (xhr.readyState == 1)
xhr.abort();
});
}
throbber.center();
},
upload : function(url, msg, data) {
var dialog = CKEDITOR.dialog.getCurrent();
dialog.throbber.hide();
if ( typeof msg == 'function' && msg.call( data.context.sender ) === false )
return;
if (definition.onFileSelect) {
if ( definition.onFileSelect.call( data.context.sender, url, msg ) === false )
return;
}
if (!url)
return;
dialog.getContentElement( targetField[ 0 ], targetField[ 1 ] ).setValue( url );
dialog.selectPage( targetField[ 0 ] );
}
};
if (element.filebrowser.action == "QuickUpload") {
definition.hasQuickUpload = true;
definition.onFileSelect = null;
if (!editor.config.simpleuploads_respectDialogUploads)
{
element.label = ( forImage ? editor.lang.simpleuploads.addImage : editor.lang.simpleuploads.addFile);
element.onClick = function( evt )
{
// "element" here means the definition object, so we need to find the correct
// button to scope the event call
//var sender = evt.sender;
PickAndSendFile(editor, forImage, evt, callback);
return false;
};
var picker = definition.getContents( element[ "for" ][ 0 ] ).get( element[ "for" ][ 1 ] );
picker.hidden = true;
}
} else {
// if the dialog has already been configured with quickUpload there's no need to use the file browser config
if (definition.hasQuickUpload)
return;
if (element.filebrowser.onSelect)
definition.onFileSelect = element.filebrowser.onSelect;
}
if (!editor.plugins.fileDropHandler)
return;
if (element.filebrowser.action == "QuickUpload")
definition.uploadUrl = element.filebrowser.url;
var original = definition.onShow || (function(){});
definition.onShow = CKEDITOR.tools.override( original, function( original )
{
return function()
{
if ( typeof original == 'function' )
original.call( this );
if (element.filebrowser.action != "QuickUpload" && definition.hasQuickUpload)
return;
var dialog = this;
if (dialog.handleFileDrop)
return;
dialog.handleFileDrop = true;
dialog.getParentEditor().plugins.fileDropHandler.addTarget( dialog.parts.contents, callback );
};
} );
}
// Searches for elements in the dialog definition where we can apply our enhancements
function applySimpleUpload( editor, dialogName, definition, elements )
{
for ( var i in elements )
{
var element = elements[ i ];
// If due to some customization or external library the object isn't valid, skip it.
if (!element)
continue;
if ( element.type == 'hbox' || element.type == 'vbox' || element.type == 'fieldset' )
applySimpleUpload( editor, dialogName, definition, element.children );
if ( element.filebrowser && element.filebrowser.url )
createSimpleUpload( editor, dialogName, definition, element );
}
}
function setupCancelButton( editor, data ) {
var element = editor.document.getById( data.id );
if (!element)
return;
var links = element.$.getElementsByTagName("a");
if (!links || !links.length)
{
links = element.$.getElementsByTagName("span");
if (!links || !links.length)
return;
}
for(var i=0; i