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 this.editor
.insertText(' ');
125 this.uploadQueuePush(proxy
);
131 PlinnCKDDUploader
.prototype.beforeUpload = function(item
) {
132 this.uploadedItem
= item
;
133 this.progressBar
= item
.progressBar
;
134 this.progressBarMaxSize
= item
.container
.getSize('width');
138 PlinnCKDDUploader
.prototype.upload = function(item
) {
139 // item.file must be the file to be uploaded
140 this.beforeUpload(item
);
141 var reader
= new FileReader();
142 var req
= new XMLHttpRequest();
143 var file
= item
.file
;
147 addListener(req
.upload
, 'progress', function(evt
){self
.progressHandler(evt
);});
148 addListener(req
, 'readystatechange',
150 if (req
.readyState
=== 4) {
151 self
.uploadCompleteHandler(req
);
155 req
.open("PUT", this.uploadUrl
);
156 req
.setRequestHeader("Content-Type", file
.type
);
157 req
.setRequestHeader("X-File-Name", encodeURI(file
.name
));
158 addListener(reader
, 'load',
161 req
.sendAsBinary(evt
.target
.result
);
165 reader
.readAsBinaryString(file
);
169 PlinnCKDDUploader
.prototype.uploadCompleteHandlerCB = function(req
) {
170 var item
= this.uploadedItem
;
171 var data
= req
.responseXML
.documentElement
;
174 var link
= new CKEDITOR
.dom
.element('a');
175 link
.setAttribute('href', 'attachments/' + data
.getAttribute('id'));
176 link
.appendText(data
.getAttribute('title'));
177 link
.replace(item
.container
);
180 var img
= new CKEDITOR
.dom
.element('img');
181 img
.setAttribute('src', data
.getAttribute('src'));
182 img
.setAttribute('alt', data
.getAttribute('title'));
183 img
.setAttribute('width', data
.getAttribute('width'));
184 img
.setAttribute('height', data
.getAttribute('height'));
185 img
.replace(item
.container
);
190 PlinnCKDDUploader
.prototype.uploadCompleteHandler = function(req
) {
191 this.uploadCompleteHandlerCB(req
);
192 this.uploadQueueLoadNext();
195 PlinnCKDDUploader
.prototype.progressHandlerCB = function(progress
) {
196 // 0 <= progress <= 1
197 var size
= this.progressBarMaxSize
* progress
;
198 size
= Math
.round(size
);
199 this.progressBar
.setStyle('width', String(size
) + 'px');
201 switch(this.uploadedItem
.type
) {
203 currentOpacity
= this.uploadedItem
.link
.getStyle('opacity');
204 this.uploadedItem
.link
.setStyle('opacity', Math
.max(currentOpacity
, progress
));
207 currentOpacity
= this.uploadedItem
.img
.getStyle('opacity');
208 this.uploadedItem
.img
.setStyle('opacity', Math
.max(currentOpacity
, progress
));
213 PlinnCKDDUploader
.prototype.progressHandler = function(evt
) {
214 if (evt
.lengthComputable
) {
215 var progress
= evt
.loaded
/ evt
.total
;
216 this.progressHandlerCB(progress
);
220 // Methods about upload queue
221 PlinnCKDDUploader
.prototype.uploadQueuePush = function(item
) {
222 this.uploadQueue
.push(item
);
223 if (!this._uploadQueueRunning
) {
224 this.startUploadQueue();
228 PlinnCKDDUploader
.prototype.startUploadQueue = function() {
229 this._uploadQueueRunning
= true;
230 this.uploadQueueLoadNext();
233 PlinnCKDDUploader
.prototype.uploadQueueLoadNext = function() {
234 var item
= this.uploadQueue
.shift();
239 this._uploadQueueRunning
= false;
243 // Methods about image preview queue.
244 PlinnCKDDUploader
.prototype.previewQueuePush = function(proxy
) {
245 this.previewQueue
.push(proxy
);
246 if (!this._previewQueueRunning
) {
247 this.startPreviewQueue();
251 PlinnCKDDUploader
.prototype.startPreviewQueue = function() {
252 this._previewQueueRunning
= true;
253 this.previewQueueLoadNext();
256 PlinnCKDDUploader
.prototype.previewQueueLoadNext = function() {
257 if (this.previewQueue
.length
&& this.previewsLoaded
< MAX_PREVIEW
) {
258 var proxy
= this.previewQueue
.shift();
259 this.previewUploadedImage(proxy
);
260 this.previewsLoaded
++;
263 this._previewQueueRunning
= false;
267 PlinnCKDDUploader
.prototype.previewUploadedImage = function(proxy
) {
268 var reader
= new FileReader();
269 var size
= this.thumbnailSize
;
272 reader
.onload = function(evt
) {
273 proxy
.img
.setAttribute('src', evt
.target
.result
);
274 // proxy.img.src = evt.target.result;
275 setTimeout(function(){self
.previewQueueLoadNext();}, 500);
277 reader
.readAsDataURL(proxy
.file
);
282 var reSize
= /getResizedImage\?size=(\d+)_(\d+)$/;
284 function updateImageSizeUrlParameters(img
) {
285 if (reSize
.test(img
.src
)){
286 var matches
= reSize
.exec(img
.src
);
287 var srcWidth
= parseInt(matches
[1], 10);
288 var srcHeight
= parseInt(matches
[2], 10);
290 var imgWidth
= parseInt((img
.style
.width
) ? img
.style
.width
: img
.width
, 10);
291 var imgHeight
= parseInt((img
.style
.height
) ? img
.style
.height
: img
.height
, 10);
293 if ((imgWidth
&& imgHeight
) && srcWidth
!== imgWidth
&& srcHeight
!== imgHeight
) {
294 var newUrl
= img
.getAttribute('src', 2).replace(reSize
, 'getResizedImage?size=' + imgWidth
+ '_' + imgHeight
);
295 img
.width
= imgWidth
;
296 img
.height
= imgHeight
;
302 function openPlinnImageDialog(path
, editor
) {
303 var winOptions
= "location=no,menubar=no,toolbar=no,dependent=yes,dialog=yes,minimizable=no,modal=yes,alwaysRaised=yes" +
310 var win
= open(path
+ 'dialog/plinn_image.html', 'PlinnImageDialog', winOptions
);
311 win
.dialogArguments
= {};
312 win
.dialogArguments
.editor
= editor
;
313 win
.dialogArguments
.pluginPath
= path
;
314 win
.dialogArguments
.CKEDITOR
= CKEDITOR
;
318 CKEDITOR
.plugins
.add( 'plinn_image',
320 init : function( editor
)
322 /* Add listener on getData event to compute images
323 src attributes before saving data.
325 editor
.on('instanceReady', function(){
328 var tmpDiv
= document
.createElement('div');
329 tmpDiv
.innerHTML
= evt
.data
.dataValue
;
330 var images
= tmpDiv
.getElementsByTagName('IMG');
332 for (i
= 0 ; i
< images
.length
; i
++) {
333 updateImageSizeUrlParameters(images
[i
]);}
334 evt
.data
.dataValue
= tmpDiv
.innerHTML
;
337 // drag & drop upload initialisation
338 var dd
= new PlinnCKDDUploader(editor
);
342 var pluginPath
= this.path
;
343 var allowed
= 'img[alt,!src]{border-style,border-width,float,height,margin,margin-bottom,margin-left,margin-right,margin-top,width}';
344 var required
= 'img[alt,src]';
345 var command
= editor
.addCommand('plinn_image',
347 exec : function(editor
){openPlinnImageDialog(pluginPath
, editor
);},
348 allowedContent
: allowed
,
349 requiredContent
: required
353 editor
.ui
.addButton('PlinnImage',
355 label
: editor
.lang
.common
.image
,
356 icon
: pluginPath
+ 'dialog/plinn_image.png',
357 command
: 'plinn_image'