1 /* © 2011 Benoît Pin, MINES ParisTech */
6 var reImage
= /^image\//;
9 var PlinnCKDDUploader = function(editor
) {
11 this.uploadUrl
= editor
.config
.baseHref
+ 'attachments/put_upload';
12 this.uploadQueue
= [];
13 this._uploadQueueRunning
= false;
14 this.previewQueue
= [];
15 this._previewQueueRunning
= false;
16 this.previewsLoaded
= 0;
17 this.thumbnailSize
= 310;
19 editor
.document
.on('dragenter', function(e
) {self
.dragenter(e
);});
20 editor
.document
.on('dragover', function(e
) {self
.dragover(e
);});
21 editor
.document
.on('drop', function(e
) {self
.drop(e
);});
25 PlinnCKDDUploader
.prototype.dragenter = function(e
) {
28 disablePropagation(evt
);
31 PlinnCKDDUploader
.prototype.dragover = function(e
) {
34 disablePropagation(evt
);
35 evt
= getEventObject(evt
);
36 var dt
= evt
.dataTransfer
;
37 dt
.dropEffect
= 'copy';
40 PlinnCKDDUploader
.prototype.drop = function(e
) {
43 disablePropagation(evt
);
45 var dt
= evt
.dataTransfer
;
46 dt
.dropEffect
= 'copy';
47 this.handleFiles(dt
.files
);
50 PlinnCKDDUploader
.prototype.createLinkProxy = function(file
) {
51 var container
= new CKEDITOR
.dom
.element('span');
52 var rel
= CKEDITOR
.dom
.element
.createFromHtml('<span style="position:relative"/>');
53 container
.append(rel
);
54 var progressBar
= CKEDITOR
.dom
.element
.createFromHtml(
55 '<span style="display:block; position:absolute; background:#ef8e32; height:4px; border-radius:2px; width:0; left:0; top:1em"/>');
56 rel
.append(progressBar
);
57 var link
= new CKEDITOR
.dom
.element('a');
58 link
.setAttribute('href', '#');
59 link
.setStyle('opacity', 0.2);
60 link
.appendText(file
.name
);
61 container
.append(link
);
66 proxy
.container
= container
;
67 proxy
.progressBar
= progressBar
;
72 PlinnCKDDUploader
.prototype.createImageProxy = function(file
) {
73 var container
= new CKEDITOR
.dom
.element('span');
74 var rel
= CKEDITOR
.dom
.element
.createFromHtml('<span style="position:relative"/>');
75 container
.append(rel
);
76 var progressBar
= CKEDITOR
.dom
.element
.createFromHtml(
77 '<span style="display:block; position:absolute; background:#ef8e32; height:4px; border-radius:2px; width:0; left:0; top:1em"/>');
78 rel
.append(progressBar
);
80 var img
= new CKEDITOR
.dom
.element('img');
81 img
.setAttribute('width', 310);
82 img
.setAttribute('height', 290);
83 img
.setStyle('opacity', 0.2);
84 img
.setAttribute('src', 'no_image.jpg');
85 var size
= this.thumbnailSize
;
87 img
.on('load', function(e
) {
89 if (img
$.width
> img
$.height
) { // landscape
90 img
$.height
= Math
.round(size
* img
$.height
/ img
$.width
);
94 img
$.width
= Math
.round(size
* img
$.width
/ img
$.height
);
97 img
$.style
.opacity
= 0.2;
100 container
.append(img
);
104 proxy
.type
= 'image';
105 proxy
.container
= container
;
106 proxy
.progressBar
= progressBar
;
111 // Methods about upload
112 PlinnCKDDUploader
.prototype.handleFiles = function(files
) {
114 for (i
=0 ; i
<files
.length
; i
++) {
116 if (reImage
.test(file
.type
)) {
117 proxy
= this.createImageProxy(file
);
118 this.previewQueuePush(proxy
);
121 proxy
= this.createLinkProxy(file
);
123 this.editor
.insertElement(proxy
.container
);
124 if (files
.length
> 1 && i
< files
.length
-1) {
125 this.editor
.insertText('\n'); }
126 this.uploadQueuePush(proxy
);
132 PlinnCKDDUploader
.prototype.beforeUpload = function(item
) {
133 this.uploadedItem
= item
;
134 this.progressBar
= item
.progressBar
;
135 this.progressBarMaxSize
= item
.container
.getSize('width');
139 PlinnCKDDUploader
.prototype.upload = function(item
) {
140 // item.file must be the file to be uploaded
141 this.beforeUpload(item
);
142 var reader
= new FileReader();
143 var req
= new XMLHttpRequest();
144 var file
= item
.file
;
148 addListener(req
.upload
, 'progress', function(evt
){self
.progressHandler(evt
);});
149 addListener(req
, 'readystatechange',
151 if (req
.readyState
=== 4) {
152 self
.uploadCompleteHandler(req
);
156 req
.open("PUT", this.uploadUrl
);
157 req
.setRequestHeader("Content-Type", file
.type
);
158 req
.setRequestHeader("X-File-Name", encodeURI(file
.name
));
159 addListener(reader
, 'load',
162 req
.sendAsBinary(evt
.target
.result
);
166 reader
.readAsBinaryString(file
);
170 PlinnCKDDUploader
.prototype.uploadCompleteHandlerCB = function(req
) {
171 var item
= this.uploadedItem
;
172 var data
= req
.responseXML
.documentElement
;
175 var link
= new CKEDITOR
.dom
.element('a');
176 link
.setAttribute('href', 'attachments/' + data
.getAttribute('id'));
177 link
.appendText(data
.getAttribute('title'));
178 link
.replace(item
.container
);
181 var img
= new CKEDITOR
.dom
.element('img');
182 img
.setAttribute('src', data
.getAttribute('src'));
183 img
.setAttribute('alt', data
.getAttribute('title'));
184 img
.setAttribute('width', data
.getAttribute('width'));
185 img
.setAttribute('height', data
.getAttribute('height'));
186 img
.replace(item
.container
);
191 PlinnCKDDUploader
.prototype.uploadCompleteHandler = function(req
) {
192 this.uploadCompleteHandlerCB(req
);
193 this.uploadQueueLoadNext();
196 PlinnCKDDUploader
.prototype.progressHandlerCB = function(progress
) {
197 // 0 <= progress <= 1
198 var size
= this.progressBarMaxSize
* progress
;
199 size
= Math
.round(size
);
200 this.progressBar
.setStyle('width', String(size
) + 'px');
202 switch(this.uploadedItem
.type
) {
204 currentOpacity
= this.uploadedItem
.link
.getStyle('opacity');
205 this.uploadedItem
.link
.setStyle('opacity', Math
.max(currentOpacity
, progress
));
208 currentOpacity
= this.uploadedItem
.img
.getStyle('opacity');
209 this.uploadedItem
.img
.setStyle('opacity', Math
.max(currentOpacity
, progress
));
214 PlinnCKDDUploader
.prototype.progressHandler = function(evt
) {
215 if (evt
.lengthComputable
) {
216 var progress
= evt
.loaded
/ evt
.total
;
217 this.progressHandlerCB(progress
);
221 // Methods about upload queue
222 PlinnCKDDUploader
.prototype.uploadQueuePush = function(item
) {
223 this.uploadQueue
.push(item
);
224 if (!this._uploadQueueRunning
) {
225 this.startUploadQueue();
229 PlinnCKDDUploader
.prototype.startUploadQueue = function() {
230 this._uploadQueueRunning
= true;
231 this.uploadQueueLoadNext();
234 PlinnCKDDUploader
.prototype.uploadQueueLoadNext = function() {
235 var item
= this.uploadQueue
.shift();
240 this._uploadQueueRunning
= false;
244 // Methods about image preview queue.
245 PlinnCKDDUploader
.prototype.previewQueuePush = function(proxy
) {
246 this.previewQueue
.push(proxy
);
247 if (!this._previewQueueRunning
) {
248 this.startPreviewQueue();
252 PlinnCKDDUploader
.prototype.startPreviewQueue = function() {
253 this._previewQueueRunning
= true;
254 this.previewQueueLoadNext();
257 PlinnCKDDUploader
.prototype.previewQueueLoadNext = function() {
258 if (this.previewQueue
.length
&& this.previewsLoaded
< MAX_PREVIEW
) {
259 var proxy
= this.previewQueue
.shift();
260 this.previewUploadedImage(proxy
);
261 this.previewsLoaded
++;
264 this._previewQueueRunning
= false;
268 PlinnCKDDUploader
.prototype.previewUploadedImage = function(proxy
) {
269 var reader
= new FileReader();
270 var size
= this.thumbnailSize
;
273 reader
.onload = function(evt
) {
274 proxy
.img
.setAttribute('src', evt
.target
.result
);
275 // proxy.img.src = evt.target.result;
276 setTimeout(function(){self
.previewQueueLoadNext();}, 500);
278 reader
.readAsDataURL(proxy
.file
);
283 var reSize
= /getResizedImage\?size=(\d+)_(\d+)$/;
285 function updateImageSizeUrlParameters(img
) {
286 if (reSize
.test(img
.src
)){
287 var matches
= reSize
.exec(img
.src
);
288 var srcWidth
= parseInt(matches
[1], 10);
289 var srcHeight
= parseInt(matches
[2], 10);
291 var imgWidth
= parseInt((img
.style
.width
) ? img
.style
.width
: img
.width
, 10);
292 var imgHeight
= parseInt((img
.style
.height
) ? img
.style
.height
: img
.height
, 10);
294 if ((imgWidth
&& imgHeight
) && srcWidth
!== imgWidth
&& srcHeight
!== imgHeight
) {
295 var newUrl
= img
.getAttribute('src', 2).replace(reSize
, 'getResizedImage?size=' + imgWidth
+ '_' + imgHeight
);
296 img
.width
= imgWidth
;
297 img
.height
= imgHeight
;
303 function openPlinnImageDialog(path
, editor
) {
304 var winOptions
= "location=no,menubar=no,toolbar=no,dependent=yes,dialog=yes,minimizable=no,modal=yes,alwaysRaised=yes" +
311 var win
= open(path
+ 'dialog/plinn_image.html', 'PlinnImageDialog', winOptions
);
312 win
.dialogArguments
= {};
313 win
.dialogArguments
.editor
= editor
;
314 win
.dialogArguments
.pluginPath
= path
;
315 win
.dialogArguments
.CKEDITOR
= CKEDITOR
;
319 CKEDITOR
.plugins
.add( 'plinn_image',
321 init : function( editor
)
323 /* Add listener on getData event to compute images
324 src attributes before saving data.
326 editor
.on('instanceReady', function(){
329 var tmpDiv
= document
.createElement('div');
330 tmpDiv
.innerHTML
= evt
.data
.dataValue
;
331 var images
= tmpDiv
.getElementsByTagName('IMG');
333 for (i
= 0 ; i
< images
.length
; i
++) {
334 updateImageSizeUrlParameters(images
[i
]);}
335 evt
.data
.dataValue
= tmpDiv
.innerHTML
;
338 // drag & drop upload initialisation
339 var dd
= new PlinnCKDDUploader(editor
);
343 var pluginPath
= this.path
;
344 var allowed
= 'img[alt,!src]{border-style,border-width,float,height,margin,margin-bottom,margin-left,margin-right,margin-top,width}';
345 var required
= 'img[alt,src]';
346 var command
= editor
.addCommand('plinn_image',
348 exec : function(editor
){openPlinnImageDialog(pluginPath
, editor
);},
349 allowedContent
: allowed
,
350 requiredContent
: required
354 editor
.ui
.addButton('PlinnImage',
356 label
: editor
.lang
.common
.image
,
357 icon
: pluginPath
+ 'dialog/plinn_image.png',
358 command
: 'plinn_image'