Subversion Repositories Integrator Subversion

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 espaco 1
/**
2
 * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
3
 * v1.2.1
4
 *
5
 * Copyright 2013, Moxiecode Systems AB
6
 * Released under GPL License.
7
 *
8
 * License: http://www.plupload.com/license
9
 * Contributing: http://www.plupload.com/contributing
10
 *
11
 * Date: 2014-05-14
12
 */
13
/**
14
 * Compiled inline version. (Library mode)
15
 */
16
 
17
/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
18
/*globals $code */
19
 
20
(function(exports, undefined) {
21
        "use strict";
22
 
23
        var modules = {};
24
 
25
        function require(ids, callback) {
26
                var module, defs = [];
27
 
28
                for (var i = 0; i < ids.length; ++i) {
29
                        module = modules[ids[i]] || resolve(ids[i]);
30
                        if (!module) {
31
                                throw 'module definition dependecy not found: ' + ids[i];
32
                        }
33
 
34
                        defs.push(module);
35
                }
36
 
37
                callback.apply(null, defs);
38
        }
39
 
40
        function define(id, dependencies, definition) {
41
                if (typeof id !== 'string') {
42
                        throw 'invalid module definition, module id must be defined and be a string';
43
                }
44
 
45
                if (dependencies === undefined) {
46
                        throw 'invalid module definition, dependencies must be specified';
47
                }
48
 
49
                if (definition === undefined) {
50
                        throw 'invalid module definition, definition function must be specified';
51
                }
52
 
53
                require(dependencies, function() {
54
                        modules[id] = definition.apply(null, arguments);
55
                });
56
        }
57
 
58
        function defined(id) {
59
                return !!modules[id];
60
        }
61
 
62
        function resolve(id) {
63
                var target = exports;
64
                var fragments = id.split(/[.\/]/);
65
 
66
                for (var fi = 0; fi < fragments.length; ++fi) {
67
                        if (!target[fragments[fi]]) {
68
                                return;
69
                        }
70
 
71
                        target = target[fragments[fi]];
72
                }
73
 
74
                return target;
75
        }
76
 
77
        function expose(ids) {
78
                for (var i = 0; i < ids.length; i++) {
79
                        var target = exports;
80
                        var id = ids[i];
81
                        var fragments = id.split(/[.\/]/);
82
 
83
                        for (var fi = 0; fi < fragments.length - 1; ++fi) {
84
                                if (target[fragments[fi]] === undefined) {
85
                                        target[fragments[fi]] = {};
86
                                }
87
 
88
                                target = target[fragments[fi]];
89
                        }
90
 
91
                        target[fragments[fragments.length - 1]] = modules[id];
92
                }
93
        }
94
 
95
// Included from: src/javascript/core/utils/Basic.js
96
 
97
/**
98
 * Basic.js
99
 *
100
 * Copyright 2013, Moxiecode Systems AB
101
 * Released under GPL License.
102
 *
103
 * License: http://www.plupload.com/license
104
 * Contributing: http://www.plupload.com/contributing
105
 */
106
 
107
define('moxie/core/utils/Basic', [], function() {
108
        /**
109
        Gets the true type of the built-in object (better version of typeof).
110
        @author Angus Croll (http://javascriptweblog.wordpress.com/)
111
 
112
        @method typeOf
113
        @for Utils
114
        @static
115
        @param {Object} o Object to check.
116
        @return {String} Object [[Class]]
117
        */
118
        var typeOf = function(o) {
119
                var undef;
120
 
121
                if (o === undef) {
122
                        return 'undefined';
123
                } else if (o === null) {
124
                        return 'null';
125
                } else if (o.nodeType) {
126
                        return 'node';
127
                }
128
 
129
                // the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8
130
                return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
131
        };
132
 
133
        /**
134
        Extends the specified object with another object.
135
 
136
        @method extend
137
        @static
138
        @param {Object} target Object to extend.
139
        @param {Object} [obj]* Multiple objects to extend with.
140
        @return {Object} Same as target, the extended object.
141
        */
142
        var extend = function(target) {
143
                var undef;
144
 
145
                each(arguments, function(arg, i) {
146
                        if (i > 0) {
147
                                each(arg, function(value, key) {
148
                                        if (value !== undef) {
149
                                                if (typeOf(target[key]) === typeOf(value) && !!~inArray(typeOf(value), ['array', 'object'])) {
150
                                                        extend(target[key], value);
151
                                                } else {
152
                                                        target[key] = value;
153
                                                }
154
                                        }
155
                                });
156
                        }
157
                });
158
                return target;
159
        };
160
 
161
        /**
162
        Executes the callback function for each item in array/object. If you return false in the
163
        callback it will break the loop.
164
 
165
        @method each
166
        @static
167
        @param {Object} obj Object to iterate.
168
        @param {function} callback Callback function to execute for each item.
169
        */
170
        var each = function(obj, callback) {
171
                var length, key, i, undef;
172
 
173
                if (obj) {
174
                        try {
175
                                length = obj.length;
176
                        } catch(ex) {
177
                                length = undef;
178
                        }
179
 
180
                        if (length === undef) {
181
                                // Loop object items
182
                                for (key in obj) {
183
                                        if (obj.hasOwnProperty(key)) {
184
                                                if (callback(obj[key], key) === false) {
185
                                                        return;
186
                                                }
187
                                        }
188
                                }
189
                        } else {
190
                                // Loop array items
191
                                for (i = 0; i < length; i++) {
192
                                        if (callback(obj[i], i) === false) {
193
                                                return;
194
                                        }
195
                                }
196
                        }
197
                }
198
        };
199
 
200
        /**
201
        Checks if object is empty.
202
 
203
        @method isEmptyObj
204
        @static
205
        @param {Object} o Object to check.
206
        @return {Boolean}
207
        */
208
        var isEmptyObj = function(obj) {
209
                var prop;
210
 
211
                if (!obj || typeOf(obj) !== 'object') {
212
                        return true;
213
                }
214
 
215
                for (prop in obj) {
216
                        return false;
217
                }
218
 
219
                return true;
220
        };
221
 
222
        /**
223
        Recieve an array of functions (usually async) to call in sequence, each  function
224
        receives a callback as first argument that it should call, when it completes. Finally,
225
        after everything is complete, main callback is called. Passing truthy value to the
226
        callback as a first argument will interrupt the sequence and invoke main callback
227
        immediately.
228
 
229
        @method inSeries
230
        @static
231
        @param {Array} queue Array of functions to call in sequence
232
        @param {Function} cb Main callback that is called in the end, or in case of error
233
        */
234
        var inSeries = function(queue, cb) {
235
                var i = 0, length = queue.length;
236
 
237
                if (typeOf(cb) !== 'function') {
238
                        cb = function() {};
239
                }
240
 
241
                if (!queue || !queue.length) {
242
                        cb();
243
                }
244
 
245
                function callNext(i) {
246
                        if (typeOf(queue[i]) === 'function') {
247
                                queue[i](function(error) {
248
                                        /*jshint expr:true */
249
                                        ++i < length && !error ? callNext(i) : cb(error);
250
                                });
251
                        }
252
                }
253
                callNext(i);
254
        };
255
 
256
 
257
        /**
258
        Recieve an array of functions (usually async) to call in parallel, each  function
259
        receives a callback as first argument that it should call, when it completes. After
260
        everything is complete, main callback is called. Passing truthy value to the
261
        callback as a first argument will interrupt the process and invoke main callback
262
        immediately.
263
 
264
        @method inParallel
265
        @static
266
        @param {Array} queue Array of functions to call in sequence
267
        @param {Function} cb Main callback that is called in the end, or in case of erro
268
        */
269
        var inParallel = function(queue, cb) {
270
                var count = 0, num = queue.length, cbArgs = new Array(num);
271
 
272
                each(queue, function(fn, i) {
273
                        fn(function(error) {
274
                                if (error) {
275
                                        return cb(error);
276
                                }
277
 
278
                                var args = [].slice.call(arguments);
279
                                args.shift(); // strip error - undefined or not
280
 
281
                                cbArgs[i] = args;
282
                                count++;
283
 
284
                                if (count === num) {
285
                                        cbArgs.unshift(null);
286
                                        cb.apply(this, cbArgs);
287
                                }
288
                        });
289
                });
290
        };
291
 
292
 
293
        /**
294
        Find an element in array and return it's index if present, otherwise return -1.
295
 
296
        @method inArray
297
        @static
298
        @param {Mixed} needle Element to find
299
        @param {Array} array
300
        @return {Int} Index of the element, or -1 if not found
301
        */
302
        var inArray = function(needle, array) {
303
                if (array) {
304
                        if (Array.prototype.indexOf) {
305
                                return Array.prototype.indexOf.call(array, needle);
306
                        }
307
 
308
                        for (var i = 0, length = array.length; i < length; i++) {
309
                                if (array[i] === needle) {
310
                                        return i;
311
                                }
312
                        }
313
                }
314
                return -1;
315
        };
316
 
317
 
318
        /**
319
        Returns elements of first array if they are not present in second. And false - otherwise.
320
 
321
        @private
322
        @method arrayDiff
323
        @param {Array} needles
324
        @param {Array} array
325
        @return {Array|Boolean}
326
        */
327
        var arrayDiff = function(needles, array) {
328
                var diff = [];
329
 
330
                if (typeOf(needles) !== 'array') {
331
                        needles = [needles];
332
                }
333
 
334
                if (typeOf(array) !== 'array') {
335
                        array = [array];
336
                }
337
 
338
                for (var i in needles) {
339
                        if (inArray(needles[i], array) === -1) {
340
                                diff.push(needles[i]);
341
                        }      
342
                }
343
                return diff.length ? diff : false;
344
        };
345
 
346
 
347
        /**
348
        Find intersection of two arrays.
349
 
350
        @private
351
        @method arrayIntersect
352
        @param {Array} array1
353
        @param {Array} array2
354
        @return {Array} Intersection of two arrays or null if there is none
355
        */
356
        var arrayIntersect = function(array1, array2) {
357
                var result = [];
358
                each(array1, function(item) {
359
                        if (inArray(item, array2) !== -1) {
360
                                result.push(item);
361
                        }
362
                });
363
                return result.length ? result : null;
364
        };
365
 
366
 
367
        /**
368
        Forces anything into an array.
369
 
370
        @method toArray
371
        @static
372
        @param {Object} obj Object with length field.
373
        @return {Array} Array object containing all items.
374
        */
375
        var toArray = function(obj) {
376
                var i, arr = [];
377
 
378
                for (i = 0; i < obj.length; i++) {
379
                        arr[i] = obj[i];
380
                }
381
 
382
                return arr;
383
        };
384
 
385
 
386
        /**
387
        Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers.
388
        The only way a user would be able to get the same ID is if the two persons at the same exact milisecond manages
389
        to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique.
390
        It's more probable for the earth to be hit with an ansteriod. Y
391
 
392
        @method guid
393
        @static
394
        @param {String} prefix to prepend (by default 'o' will be prepended).
395
        @method guid
396
        @return {String} Virtually unique id.
397
        */
398
        var guid = (function() {
399
                var counter = 0;
400
 
401
                return function(prefix) {
402
                        var guid = new Date().getTime().toString(32), i;
403
 
404
                        for (i = 0; i < 5; i++) {
405
                                guid += Math.floor(Math.random() * 65535).toString(32);
406
                        }
407
 
408
                        return (prefix || 'o_') + guid + (counter++).toString(32);
409
                };
410
        }());
411
 
412
 
413
        /**
414
        Trims white spaces around the string
415
 
416
        @method trim
417
        @static
418
        @param {String} str
419
        @return {String}
420
        */
421
        var trim = function(str) {
422
                if (!str) {
423
                        return str;
424
                }
425
                return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, '');
426
        };
427
 
428
 
429
        /**
430
        Parses the specified size string into a byte value. For example 10kb becomes 10240.
431
 
432
        @method parseSizeStr
433
        @static
434
        @param {String/Number} size String to parse or number to just pass through.
435
        @return {Number} Size in bytes.
436
        */
437
        var parseSizeStr = function(size) {
438
                if (typeof(size) !== 'string') {
439
                        return size;
440
                }
441
 
442
                var muls = {
443
                                t: 1099511627776,
444
                                g: 1073741824,
445
                                m: 1048576,
446
                                k: 1024
447
                        },
448
                        mul;
449
 
450
                size = /^([0-9]+)([mgk]?)$/.exec(size.toLowerCase().replace(/[^0-9mkg]/g, ''));
451
                mul = size[2];
452
                size = +size[1];
453
 
454
                if (muls.hasOwnProperty(mul)) {
455
                        size *= muls[mul];
456
                }
457
                return size;
458
        };
459
 
460
 
461
        return {
462
                guid: guid,
463
                typeOf: typeOf,
464
                extend: extend,
465
                each: each,
466
                isEmptyObj: isEmptyObj,
467
                inSeries: inSeries,
468
                inParallel: inParallel,
469
                inArray: inArray,
470
                arrayDiff: arrayDiff,
471
                arrayIntersect: arrayIntersect,
472
                toArray: toArray,
473
                trim: trim,
474
                parseSizeStr: parseSizeStr
475
        };
476
});
477
 
478
// Included from: src/javascript/core/I18n.js
479
 
480
/**
481
 * I18n.js
482
 *
483
 * Copyright 2013, Moxiecode Systems AB
484
 * Released under GPL License.
485
 *
486
 * License: http://www.plupload.com/license
487
 * Contributing: http://www.plupload.com/contributing
488
 */
489
 
490
define("moxie/core/I18n", [
491
        "moxie/core/utils/Basic"
492
], function(Basic) {
493
        var i18n = {};
494
 
495
        return {
496
                /**
497
                 * Extends the language pack object with new items.
498
                 *
499
                 * @param {Object} pack Language pack items to add.
500
                 * @return {Object} Extended language pack object.
501
                 */
502
                addI18n: function(pack) {
503
                        return Basic.extend(i18n, pack);
504
                },
505
 
506
                /**
507
                 * Translates the specified string by checking for the english string in the language pack lookup.
508
                 *
509
                 * @param {String} str String to look for.
510
                 * @return {String} Translated string or the input string if it wasn't found.
511
                 */
512
                translate: function(str) {
513
                        return i18n[str] || str;
514
                },
515
 
516
                /**
517
                 * Shortcut for translate function
518
                 *
519
                 * @param {String} str String to look for.
520
                 * @return {String} Translated string or the input string if it wasn't found.
521
                 */
522
                _: function(str) {
523
                        return this.translate(str);
524
                },
525
 
526
                /**
527
                 * Pseudo sprintf implementation - simple way to replace tokens with specified values.
528
                 *
529
                 * @param {String} str String with tokens
530
                 * @return {String} String with replaced tokens
531
                 */
532
                sprintf: function(str) {
533
                        var args = [].slice.call(arguments, 1);
534
 
535
                        return str.replace(/%[a-z]/g, function() {
536
                                var value = args.shift();
537
                                return Basic.typeOf(value) !== 'undefined' ? value : '';
538
                        });
539
                }
540
        };
541
});
542
 
543
// Included from: src/javascript/core/utils/Mime.js
544
 
545
/**
546
 * Mime.js
547
 *
548
 * Copyright 2013, Moxiecode Systems AB
549
 * Released under GPL License.
550
 *
551
 * License: http://www.plupload.com/license
552
 * Contributing: http://www.plupload.com/contributing
553
 */
554
 
555
define("moxie/core/utils/Mime", [
556
        "moxie/core/utils/Basic",
557
        "moxie/core/I18n"
558
], function(Basic, I18n) {
559
 
560
        var mimeData = "" +
561
                "application/msword,doc dot," +
562
                "application/pdf,pdf," +
563
                "application/pgp-signature,pgp," +
564
                "application/postscript,ps ai eps," +
565
                "application/rtf,rtf," +
566
                "application/vnd.ms-excel,xls xlb," +
567
                "application/vnd.ms-powerpoint,ppt pps pot," +
568
                "application/zip,zip," +
569
                "application/x-shockwave-flash,swf swfl," +
570
                "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," +
571
                "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," +
572
                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," +
573
                "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," +
574
                "application/vnd.openxmlformats-officedocument.presentationml.template,potx," +
575
                "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," +
576
                "application/x-javascript,js," +
577
                "application/json,json," +
578
                "audio/mpeg,mp3 mpga mpega mp2," +
579
                "audio/x-wav,wav," +
580
                "audio/x-m4a,m4a," +
581
                "audio/ogg,oga ogg," +
582
                "audio/aiff,aiff aif," +
583
                "audio/flac,flac," +
584
                "audio/aac,aac," +
585
                "audio/ac3,ac3," +
586
                "audio/x-ms-wma,wma," +
587
                "image/bmp,bmp," +
588
                "image/gif,gif," +
589
                "image/jpeg,jpg jpeg jpe," +
590
                "image/photoshop,psd," +
591
                "image/png,png," +
592
                "image/svg+xml,svg svgz," +
593
                "image/tiff,tiff tif," +
594
                "text/plain,asc txt text diff log," +
595
                "text/html,htm html xhtml," +
596
                "text/css,css," +
597
                "text/csv,csv," +
598
                "text/rtf,rtf," +
599
                "video/mpeg,mpeg mpg mpe m2v," +
600
                "video/quicktime,qt mov," +
601
                "video/mp4,mp4," +
602
                "video/x-m4v,m4v," +
603
                "video/x-flv,flv," +
604
                "video/x-ms-wmv,wmv," +
605
                "video/avi,avi," +
606
                "video/webm,webm," +
607
                "video/3gpp,3gpp 3gp," +
608
                "video/3gpp2,3g2," +
609
                "video/vnd.rn-realvideo,rv," +
610
                "video/ogg,ogv," +
611
                "video/x-matroska,mkv," +
612
                "application/vnd.oasis.opendocument.formula-template,otf," +
613
                "application/octet-stream,exe";
614
 
615
 
616
        var Mime = {
617
 
618
                mimes: {},
619
 
620
                extensions: {},
621
 
622
                // Parses the default mime types string into a mimes and extensions lookup maps
623
                addMimeType: function (mimeData) {
624
                        var items = mimeData.split(/,/), i, ii, ext;
625
 
626
                        for (i = 0; i < items.length; i += 2) {
627
                                ext = items[i + 1].split(/ /);
628
 
629
                                // extension to mime lookup
630
                                for (ii = 0; ii < ext.length; ii++) {
631
                                        this.mimes[ext[ii]] = items[i];
632
                                }
633
                                // mime to extension lookup
634
                                this.extensions[items[i]] = ext;
635
                        }
636
                },
637
 
638
 
639
                extList2mimes: function (filters, addMissingExtensions) {
640
                        var self = this, ext, i, ii, type, mimes = [];
641
 
642
                        // convert extensions to mime types list
643
                        for (i = 0; i < filters.length; i++) {
644
                                ext = filters[i].extensions.split(/\s*,\s*/);
645
 
646
                                for (ii = 0; ii < ext.length; ii++) {
647
 
648
                                        // if there's an asterisk in the list, then accept attribute is not required
649
                                        if (ext[ii] === '*') {
650
                                                return [];
651
                                        }
652
 
653
                                        type = self.mimes[ext[ii]];
654
                                        if (!type) {
655
                                                if (addMissingExtensions && /^\w+$/.test(ext[ii])) {
656
                                                        mimes.push('.' + ext[ii]);
657
                                                } else {
658
                                                        return []; // accept all
659
                                                }
660
                                        } else if (Basic.inArray(type, mimes) === -1) {
661
                                                mimes.push(type);
662
                                        }
663
                                }
664
                        }
665
                        return mimes;
666
                },
667
 
668
 
669
                mimes2exts: function(mimes) {
670
                        var self = this, exts = [];
671
 
672
                        Basic.each(mimes, function(mime) {
673
                                if (mime === '*') {
674
                                        exts = [];
675
                                        return false;
676
                                }
677
 
678
                                // check if this thing looks like mime type
679
                                var m = mime.match(/^(\w+)\/(\*|\w+)$/);
680
                                if (m) {
681
                                        if (m[2] === '*') {
682
                                                // wildcard mime type detected
683
                                                Basic.each(self.extensions, function(arr, mime) {
684
                                                        if ((new RegExp('^' + m[1] + '/')).test(mime)) {
685
                                                                [].push.apply(exts, self.extensions[mime]);
686
                                                        }
687
                                                });
688
                                        } else if (self.extensions[mime]) {
689
                                                [].push.apply(exts, self.extensions[mime]);
690
                                        }
691
                                }
692
                        });
693
                        return exts;
694
                },
695
 
696
 
697
                mimes2extList: function(mimes) {
698
                        var accept = [], exts = [];
699
 
700
                        if (Basic.typeOf(mimes) === 'string') {
701
                                mimes = Basic.trim(mimes).split(/\s*,\s*/);
702
                        }
703
 
704
                        exts = this.mimes2exts(mimes);
705
 
706
                        accept.push({
707
                                title: I18n.translate('Files'),
708
                                extensions: exts.length ? exts.join(',') : '*'
709
                        });
710
 
711
                        // save original mimes string
712
                        accept.mimes = mimes;
713
 
714
                        return accept;
715
                },
716
 
717
 
718
                getFileExtension: function(fileName) {
719
                        var matches = fileName && fileName.match(/\.([^.]+)$/);
720
                        if (matches) {
721
                                return matches[1].toLowerCase();
722
                        }
723
                        return '';
724
                },
725
 
726
                getFileMime: function(fileName) {
727
                        return this.mimes[this.getFileExtension(fileName)] || '';
728
                }
729
        };
730
 
731
        Mime.addMimeType(mimeData);
732
 
733
        return Mime;
734
});
735
 
736
// Included from: src/javascript/core/utils/Env.js
737
 
738
/**
739
 * Env.js
740
 *
741
 * Copyright 2013, Moxiecode Systems AB
742
 * Released under GPL License.
743
 *
744
 * License: http://www.plupload.com/license
745
 * Contributing: http://www.plupload.com/contributing
746
 */
747
 
748
define("moxie/core/utils/Env", [
749
        "moxie/core/utils/Basic"
750
], function(Basic) {
751
 
752
        // UAParser.js v0.6.2
753
        // Lightweight JavaScript-based User-Agent string parser
754
        // https://github.com/faisalman/ua-parser-js
755
        //
756
        // Copyright © 2012-2013 Faisalman <fyzlman@gmail.com>
757
        // Dual licensed under GPLv2 & MIT
758
 
759
        var UAParser = (function (undefined) {
760
 
761
            //////////////
762
            // Constants
763
            /////////////
764
 
765
 
766
            var EMPTY       = '',
767
                UNKNOWN     = '?',
768
                FUNC_TYPE   = 'function',
769
                UNDEF_TYPE  = 'undefined',
770
                OBJ_TYPE    = 'object',
771
                MAJOR       = 'major',
772
                MODEL       = 'model',
773
                NAME        = 'name',
774
                TYPE        = 'type',
775
                VENDOR      = 'vendor',
776
                VERSION     = 'version',
777
                ARCHITECTURE= 'architecture',
778
                CONSOLE     = 'console',
779
                MOBILE      = 'mobile',
780
                TABLET      = 'tablet';
781
 
782
 
783
            ///////////
784
            // Helper
785
            //////////
786
 
787
 
788
            var util = {
789
                has : function (str1, str2) {
790
                    return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1;
791
                },
792
                lowerize : function (str) {
793
                    return str.toLowerCase();
794
                }
795
            };
796
 
797
 
798
            ///////////////
799
            // Map helper
800
            //////////////
801
 
802
 
803
            var mapper = {
804
 
805
                rgx : function () {
806
 
807
                    // loop through all regexes maps
808
                    for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) {
809
 
810
                        var regex = args[i],       // even sequence (0,2,4,..)
811
                            props = args[i + 1];   // odd sequence (1,3,5,..)
812
 
813
                        // construct object barebones
814
                        if (typeof(result) === UNDEF_TYPE) {
815
                            result = {};
816
                            for (p in props) {
817
                                q = props[p];
818
                                if (typeof(q) === OBJ_TYPE) {
819
                                    result[q[0]] = undefined;
820
                                } else {
821
                                    result[q] = undefined;
822
                                }
823
                            }
824
                        }
825
 
826
                        // try matching uastring with regexes
827
                        for (j = k = 0; j < regex.length; j++) {
828
                            matches = regex[j].exec(this.getUA());
829
                            if (!!matches) {
830
                                for (p = 0; p < props.length; p++) {
831
                                    match = matches[++k];
832
                                    q = props[p];
833
                                    // check if given property is actually array
834
                                    if (typeof(q) === OBJ_TYPE && q.length > 0) {
835
                                        if (q.length == 2) {
836
                                            if (typeof(q[1]) == FUNC_TYPE) {
837
                                                // assign modified match
838
                                                result[q[0]] = q[1].call(this, match);
839
                                            } else {
840
                                                // assign given value, ignore regex match
841
                                                result[q[0]] = q[1];
842
                                            }
843
                                        } else if (q.length == 3) {
844
                                            // check whether function or regex
845
                                            if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) {
846
                                                // call function (usually string mapper)
847
                                                result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
848
                                            } else {
849
                                                // sanitize match using given regex
850
                                                result[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
851
                                            }
852
                                        } else if (q.length == 4) {
853
                                                result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
854
                                        }
855
                                    } else {
856
                                        result[q] = match ? match : undefined;
857
                                    }
858
                                }
859
                                break;
860
                            }
861
                        }
862
 
863
                        if(!!matches) break; // break the loop immediately if match found
864
                    }
865
                    return result;
866
                },
867
 
868
                str : function (str, map) {
869
 
870
                    for (var i in map) {
871
                        // check if array
872
                        if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) {
873
                            for (var j = 0; j < map[i].length; j++) {
874
                                if (util.has(map[i][j], str)) {
875
                                    return (i === UNKNOWN) ? undefined : i;
876
                                }
877
                            }
878
                        } else if (util.has(map[i], str)) {
879
                            return (i === UNKNOWN) ? undefined : i;
880
                        }
881
                    }
882
                    return str;
883
                }
884
            };
885
 
886
 
887
            ///////////////
888
            // String map
889
            //////////////
890
 
891
 
892
            var maps = {
893
 
894
                browser : {
895
                    oldsafari : {
896
                        major : {
897
                            '1' : ['/8', '/1', '/3'],
898
                            '2' : '/4',
899
                            '?' : '/'
900
                        },
901
                        version : {
902
                            '1.0'   : '/8',
903
                            '1.2'   : '/1',
904
                            '1.3'   : '/3',
905
                            '2.0'   : '/412',
906
                            '2.0.2' : '/416',
907
                            '2.0.3' : '/417',
908
                            '2.0.4' : '/419',
909
                            '?'     : '/'
910
                        }
911
                    }
912
                },
913
 
914
                device : {
915
                    sprint : {
916
                        model : {
917
                            'Evo Shift 4G' : '7373KT'
918
                        },
919
                        vendor : {
920
                            'HTC'       : 'APA',
921
                            'Sprint'    : 'Sprint'
922
                        }
923
                    }
924
                },
925
 
926
                os : {
927
                    windows : {
928
                        version : {
929
                            'ME'        : '4.90',
930
                            'NT 3.11'   : 'NT3.51',
931
                            'NT 4.0'    : 'NT4.0',
932
                            '2000'      : 'NT 5.0',
933
                            'XP'        : ['NT 5.1', 'NT 5.2'],
934
                            'Vista'     : 'NT 6.0',
935
                            '7'         : 'NT 6.1',
936
                            '8'         : 'NT 6.2',
937
                            '8.1'       : 'NT 6.3',
938
                            'RT'        : 'ARM'
939
                        }
940
                    }
941
                }
942
            };
943
 
944
 
945
            //////////////
946
            // Regex map
947
            /////////////
948
 
949
 
950
            var regexes = {
951
 
952
                browser : [[
953
 
954
                    // Presto based
955
                    /(opera\smini)\/((\d+)?[\w\.-]+)/i,                                 // Opera Mini
956
                    /(opera\s[mobiletab]+).+version\/((\d+)?[\w\.-]+)/i,                // Opera Mobi/Tablet
957
                    /(opera).+version\/((\d+)?[\w\.]+)/i,                               // Opera > 9.80
958
                    /(opera)[\/\s]+((\d+)?[\w\.]+)/i                                    // Opera < 9.80
959
 
960
                    ], [NAME, VERSION, MAJOR], [
961
 
962
                    /\s(opr)\/((\d+)?[\w\.]+)/i                                         // Opera Webkit
963
                    ], [[NAME, 'Opera'], VERSION, MAJOR], [
964
 
965
                    // Mixed
966
                    /(kindle)\/((\d+)?[\w\.]+)/i,                                       // Kindle
967
                    /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)*/i,
968
                                                                                        // Lunascape/Maxthon/Netfront/Jasmine/Blazer
969
 
970
                    // Trident based
971
                    /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?((\d+)?[\w\.]*)/i,
972
                                                                                        // Avant/IEMobile/SlimBrowser/Baidu
973
                    /(?:ms|\()(ie)\s((\d+)?[\w\.]+)/i,                                  // Internet Explorer
974
 
975
                    // Webkit/KHTML based
976
                    /(rekonq)((?:\/)[\w\.]+)*/i,                                        // Rekonq
977
                    /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron)\/((\d+)?[\w\.-]+)/i
978
                                                                                        // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron
979
                    ], [NAME, VERSION, MAJOR], [
980
 
981
                    /(trident).+rv[:\s]((\d+)?[\w\.]+).+like\sgecko/i                   // IE11
982
                    ], [[NAME, 'IE'], VERSION, MAJOR], [
983
 
984
                    /(yabrowser)\/((\d+)?[\w\.]+)/i                                     // Yandex
985
                    ], [[NAME, 'Yandex'], VERSION, MAJOR], [
986
 
987
                    /(comodo_dragon)\/((\d+)?[\w\.]+)/i                                 // Comodo Dragon
988
                    ], [[NAME, /_/g, ' '], VERSION, MAJOR], [
989
 
990
                    /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?((\d+)?[\w\.]+)/i
991
                                                                                        // Chrome/OmniWeb/Arora/Tizen/Nokia
992
                    ], [NAME, VERSION, MAJOR], [
993
 
994
                    /(dolfin)\/((\d+)?[\w\.]+)/i                                        // Dolphin
995
                    ], [[NAME, 'Dolphin'], VERSION, MAJOR], [
996
 
997
                    /((?:android.+)crmo|crios)\/((\d+)?[\w\.]+)/i                       // Chrome for Android/iOS
998
                    ], [[NAME, 'Chrome'], VERSION, MAJOR], [
999
 
1000
                    /((?:android.+))version\/((\d+)?[\w\.]+)\smobile\ssafari/i          // Android Browser
1001
                    ], [[NAME, 'Android Browser'], VERSION, MAJOR], [
1002
 
1003
                    /version\/((\d+)?[\w\.]+).+?mobile\/\w+\s(safari)/i                 // Mobile Safari
1004
                    ], [VERSION, MAJOR, [NAME, 'Mobile Safari']], [
1005
 
1006
                    /version\/((\d+)?[\w\.]+).+?(mobile\s?safari|safari)/i              // Safari & Safari Mobile
1007
                    ], [VERSION, MAJOR, NAME], [
1008
 
1009
                    /webkit.+?(mobile\s?safari|safari)((\/[\w\.]+))/i                   // Safari < 3.0
1010
                    ], [NAME, [MAJOR, mapper.str, maps.browser.oldsafari.major], [VERSION, mapper.str, maps.browser.oldsafari.version]], [
1011
 
1012
                    /(konqueror)\/((\d+)?[\w\.]+)/i,                                    // Konqueror
1013
                    /(webkit|khtml)\/((\d+)?[\w\.]+)/i
1014
                    ], [NAME, VERSION, MAJOR], [
1015
 
1016
                    // Gecko based
1017
                    /(navigator|netscape)\/((\d+)?[\w\.-]+)/i                           // Netscape
1018
                    ], [[NAME, 'Netscape'], VERSION, MAJOR], [
1019
                    /(swiftfox)/i,                                                      // Swiftfox
1020
                    /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?((\d+)?[\w\.\+]+)/i,
1021
                                                                                        // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
1022
                    /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/((\d+)?[\w\.-]+)/i,
1023
                                                                                        // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
1024
                    /(mozilla)\/((\d+)?[\w\.]+).+rv\:.+gecko\/\d+/i,                    // Mozilla
1025
 
1026
                    // Other
1027
                    /(uc\s?browser|polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|qqbrowser)[\/\s]?((\d+)?[\w\.]+)/i,
1028
                                                                                        // UCBrowser/Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/QQBrowser
1029
                    /(links)\s\(((\d+)?[\w\.]+)/i,                                      // Links
1030
                    /(gobrowser)\/?((\d+)?[\w\.]+)*/i,                                  // GoBrowser
1031
                    /(ice\s?browser)\/v?((\d+)?[\w\._]+)/i,                             // ICE Browser
1032
                    /(mosaic)[\/\s]((\d+)?[\w\.]+)/i                                    // Mosaic
1033
                    ], [NAME, VERSION, MAJOR]
1034
                ],
1035
 
1036
                engine : [[
1037
 
1038
                    /(presto)\/([\w\.]+)/i,                                             // Presto
1039
                    /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i,     // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m
1040
                    /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i,                          // KHTML/Tasman/Links
1041
                    /(icab)[\/\s]([23]\.[\d\.]+)/i                                      // iCab
1042
                    ], [NAME, VERSION], [
1043
 
1044
                    /rv\:([\w\.]+).*(gecko)/i                                           // Gecko
1045
                    ], [VERSION, NAME]
1046
                ],
1047
 
1048
                os : [[
1049
 
1050
                    // Windows based
1051
                    /(windows)\snt\s6\.2;\s(arm)/i,                                     // Windows RT
1052
                    /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i
1053
                    ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [
1054
                    /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
1055
                    ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [
1056
 
1057
                    // Mobile/Embedded OS
1058
                    /\((bb)(10);/i                                                      // BlackBerry 10
1059
                    ], [[NAME, 'BlackBerry'], VERSION], [
1060
                    /(blackberry)\w*\/?([\w\.]+)*/i,                                    // Blackberry
1061
                    /(tizen)\/([\w\.]+)/i,                                              // Tizen
1062
                    /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego)[\/\s-]?([\w\.]+)*/i
1063
                                                                                        // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo
1064
                    ], [NAME, VERSION], [
1065
                    /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i                 // Symbian
1066
                    ], [[NAME, 'Symbian'], VERSION],[
1067
                    /mozilla.+\(mobile;.+gecko.+firefox/i                               // Firefox OS
1068
                    ], [[NAME, 'Firefox OS'], VERSION], [
1069
 
1070
                    // Console
1071
                    /(nintendo|playstation)\s([wids3portablevu]+)/i,                    // Nintendo/Playstation
1072
 
1073
                    // GNU/Linux based
1074
                    /(mint)[\/\s\(]?(\w+)*/i,                                           // Mint
1075
                    /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i,
1076
                                                                                        // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware
1077
                                                                                        // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk
1078
                    /(hurd|linux)\s?([\w\.]+)*/i,                                       // Hurd/Linux
1079
                    /(gnu)\s?([\w\.]+)*/i                                               // GNU
1080
                    ], [NAME, VERSION], [
1081
 
1082
                    /(cros)\s[\w]+\s([\w\.]+\w)/i                                       // Chromium OS
1083
                    ], [[NAME, 'Chromium OS'], VERSION],[
1084
 
1085
                    // Solaris
1086
                    /(sunos)\s?([\w\.]+\d)*/i                                           // Solaris
1087
                    ], [[NAME, 'Solaris'], VERSION], [
1088
 
1089
                    // BSD based
1090
                    /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i                   // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
1091
                    ], [NAME, VERSION],[
1092
 
1093
                    /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i             // iOS
1094
                    ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [
1095
 
1096
                    /(mac\sos\sx)\s?([\w\s\.]+\w)*/i                                    // Mac OS
1097
                    ], [NAME, [VERSION, /_/g, '.']], [
1098
 
1099
                    // Other
1100
                    /(haiku)\s(\w+)/i,                                                  // Haiku
1101
                    /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i,                               // AIX
1102
                    /(macintosh|mac(?=_powerpc)|plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos)/i,
1103
                                                                                        // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS
1104
                    /(unix)\s?([\w\.]+)*/i                                              // UNIX
1105
                    ], [NAME, VERSION]
1106
                ]
1107
            };
1108
 
1109
 
1110
            /////////////////
1111
            // Constructor
1112
            ////////////////
1113
 
1114
 
1115
            var UAParser = function (uastring) {
1116
 
1117
                var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
1118
 
1119
                this.getBrowser = function () {
1120
                    return mapper.rgx.apply(this, regexes.browser);
1121
                };
1122
                this.getEngine = function () {
1123
                    return mapper.rgx.apply(this, regexes.engine);
1124
                };
1125
                this.getOS = function () {
1126
                    return mapper.rgx.apply(this, regexes.os);
1127
                };
1128
                this.getResult = function() {
1129
                    return {
1130
                        ua      : this.getUA(),
1131
                        browser : this.getBrowser(),
1132
                        engine  : this.getEngine(),
1133
                        os      : this.getOS()
1134
                    };
1135
                };
1136
                this.getUA = function () {
1137
                    return ua;
1138
                };
1139
                this.setUA = function (uastring) {
1140
                    ua = uastring;
1141
                    return this;
1142
                };
1143
                this.setUA(ua);
1144
            };
1145
 
1146
            return new UAParser().getResult();
1147
        })();
1148
 
1149
 
1150
        function version_compare(v1, v2, operator) {
1151
          // From: http://phpjs.org/functions
1152
          // +      original by: Philippe Jausions (http://pear.php.net/user/jausions)
1153
          // +      original by: Aidan Lister (http://aidanlister.com/)
1154
          // + reimplemented by: Kankrelune (http://www.webfaktory.info/)
1155
          // +      improved by: Brett Zamir (http://brett-zamir.me)
1156
          // +      improved by: Scott Baker
1157
          // +      improved by: Theriault
1158
          // *        example 1: version_compare('8.2.5rc', '8.2.5a');
1159
          // *        returns 1: 1
1160
          // *        example 2: version_compare('8.2.50', '8.2.52', '<');
1161
          // *        returns 2: true
1162
          // *        example 3: version_compare('5.3.0-dev', '5.3.0');
1163
          // *        returns 3: -1
1164
          // *        example 4: version_compare('4.1.0.52','4.01.0.51');
1165
          // *        returns 4: 1
1166
 
1167
          // Important: compare must be initialized at 0.
1168
          var i = 0,
1169
            x = 0,
1170
            compare = 0,
1171
            // vm maps textual PHP versions to negatives so they're less than 0.
1172
            // PHP currently defines these as CASE-SENSITIVE. It is important to
1173
            // leave these as negatives so that they can come before numerical versions
1174
            // and as if no letters were there to begin with.
1175
            // (1alpha is < 1 and < 1.1 but > 1dev1)
1176
            // If a non-numerical value can't be mapped to this table, it receives
1177
            // -7 as its value.
1178
            vm = {
1179
              'dev': -6,
1180
              'alpha': -5,
1181
              'a': -5,
1182
              'beta': -4,
1183
              'b': -4,
1184
              'RC': -3,
1185
              'rc': -3,
1186
              '#': -2,
1187
              'p': 1,
1188
              'pl': 1
1189
            },
1190
            // This function will be called to prepare each version argument.
1191
            // It replaces every _, -, and + with a dot.
1192
            // It surrounds any nonsequence of numbers/dots with dots.
1193
            // It replaces sequences of dots with a single dot.
1194
            //    version_compare('4..0', '4.0') == 0
1195
            // Important: A string of 0 length needs to be converted into a value
1196
            // even less than an unexisting value in vm (-7), hence [-8].
1197
            // It's also important to not strip spaces because of this.
1198
            //   version_compare('', ' ') == 1
1199
            prepVersion = function (v) {
1200
              v = ('' + v).replace(/[_\-+]/g, '.');
1201
              v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
1202
              return (!v.length ? [-8] : v.split('.'));
1203
            },
1204
            // This converts a version component to a number.
1205
            // Empty component becomes 0.
1206
            // Non-numerical component becomes a negative number.
1207
            // Numerical component becomes itself as an integer.
1208
            numVersion = function (v) {
1209
              return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
1210
            };
1211
 
1212
          v1 = prepVersion(v1);
1213
          v2 = prepVersion(v2);
1214
          x = Math.max(v1.length, v2.length);
1215
          for (i = 0; i < x; i++) {
1216
            if (v1[i] == v2[i]) {
1217
              continue;
1218
            }
1219
            v1[i] = numVersion(v1[i]);
1220
            v2[i] = numVersion(v2[i]);
1221
            if (v1[i] < v2[i]) {
1222
              compare = -1;
1223
              break;
1224
            } else if (v1[i] > v2[i]) {
1225
              compare = 1;
1226
              break;
1227
            }
1228
          }
1229
          if (!operator) {
1230
            return compare;
1231
          }
1232
 
1233
          // Important: operator is CASE-SENSITIVE.
1234
          // "No operator" seems to be treated as "<."
1235
          // Any other values seem to make the function return null.
1236
          switch (operator) {
1237
          case '>':
1238
          case 'gt':
1239
            return (compare > 0);
1240
          case '>=':
1241
          case 'ge':
1242
            return (compare >= 0);
1243
          case '<=':
1244
          case 'le':
1245
            return (compare <= 0);
1246
          case '==':
1247
          case '=':
1248
          case 'eq':
1249
            return (compare === 0);
1250
          case '<>':
1251
          case '!=':
1252
          case 'ne':
1253
            return (compare !== 0);
1254
          case '':
1255
          case '<':
1256
          case 'lt':
1257
            return (compare < 0);
1258
          default:
1259
            return null;
1260
          }
1261
        }
1262
 
1263
 
1264
        var can = (function() {
1265
                var caps = {
1266
                                define_property: (function() {
1267
                                        /* // currently too much extra code required, not exactly worth it
1268
                                        try { // as of IE8, getters/setters are supported only on DOM elements
1269
                                                var obj = {};
1270
                                                if (Object.defineProperty) {
1271
                                                        Object.defineProperty(obj, 'prop', {
1272
                                                                enumerable: true,
1273
                                                                configurable: true
1274
                                                        });
1275
                                                        return true;
1276
                                                }
1277
                                        } catch(ex) {}
1278
 
1279
                                        if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {
1280
                                                return true;
1281
                                        }*/
1282
                                        return false;
1283
                                }()),
1284
 
1285
                                create_canvas: (function() {
1286
                                        // On the S60 and BB Storm, getContext exists, but always returns undefined
1287
                                        // so we actually have to call getContext() to verify
1288
                                        // github.com/Modernizr/Modernizr/issues/issue/97/
1289
                                        var el = document.createElement('canvas');
1290
                                        return !!(el.getContext && el.getContext('2d'));
1291
                                }()),
1292
 
1293
                                return_response_type: function(responseType) {
1294
                                        try {
1295
                                                if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) {
1296
                                                        return true;
1297
                                                } else if (window.XMLHttpRequest) {
1298
                                                        var xhr = new XMLHttpRequest();
1299
                                                        xhr.open('get', '/'); // otherwise Gecko throws an exception
1300
                                                        if ('responseType' in xhr) {
1301
                                                                xhr.responseType = responseType;
1302
                                                                // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?)
1303
                                                                if (xhr.responseType !== responseType) {
1304
                                                                        return false;
1305
                                                                }
1306
                                                                return true;
1307
                                                        }
1308
                                                }
1309
                                        } catch (ex) {}
1310
                                        return false;
1311
                                },
1312
 
1313
                                // ideas for this heavily come from Modernizr (http://modernizr.com/)
1314
                                use_data_uri: (function() {
1315
                                        var du = new Image();
1316
 
1317
                                        du.onload = function() {
1318
                                                caps.use_data_uri = (du.width === 1 && du.height === 1);
1319
                                        };
1320
 
1321
                                        setTimeout(function() {
1322
                                                du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
1323
                                        }, 1);
1324
                                        return false;
1325
                                }()),
1326
 
1327
                                use_data_uri_over32kb: function() { // IE8
1328
                                        return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9);
1329
                                },
1330
 
1331
                                use_data_uri_of: function(bytes) {
1332
                                        return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb());
1333
                                },
1334
 
1335
                                use_fileinput: function() {
1336
                                        var el = document.createElement('input');
1337
                                        el.setAttribute('type', 'file');
1338
                                        return !el.disabled;
1339
                                }
1340
                        };
1341
 
1342
                return function(cap) {
1343
                        var args = [].slice.call(arguments);
1344
                        args.shift(); // shift of cap
1345
                        return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap];
1346
                };
1347
        }());
1348
 
1349
 
1350
        var Env = {
1351
                can: can,
1352
 
1353
                browser: UAParser.browser.name,
1354
                version: parseFloat(UAParser.browser.major),
1355
                os: UAParser.os.name, // everybody intuitively types it in a lowercase for some reason
1356
                osVersion: UAParser.os.version,
1357
 
1358
                verComp: version_compare,
1359
 
1360
                swf_url: "../flash/Moxie.swf",
1361
                xap_url: "../silverlight/Moxie.xap",
1362
                global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent"
1363
        };
1364
 
1365
        // for backward compatibility
1366
        // @deprecated Use `Env.os` instead
1367
        Env.OS = Env.os;
1368
 
1369
        return Env;
1370
});
1371
 
1372
// Included from: src/javascript/core/utils/Dom.js
1373
 
1374
/**
1375
 * Dom.js
1376
 *
1377
 * Copyright 2013, Moxiecode Systems AB
1378
 * Released under GPL License.
1379
 *
1380
 * License: http://www.plupload.com/license
1381
 * Contributing: http://www.plupload.com/contributing
1382
 */
1383
 
1384
define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
1385
 
1386
        /**
1387
        Get DOM Element by it's id.
1388
 
1389
        @method get
1390
        @for Utils
1391
        @param {String} id Identifier of the DOM Element
1392
        @return {DOMElement}
1393
        */
1394
        var get = function(id) {
1395
                if (typeof id !== 'string') {
1396
                        return id;
1397
                }
1398
                return document.getElementById(id);
1399
        };
1400
 
1401
        /**
1402
        Checks if specified DOM element has specified class.
1403
 
1404
        @method hasClass
1405
        @static
1406
        @param {Object} obj DOM element like object to add handler to.
1407
        @param {String} name Class name
1408
        */
1409
        var hasClass = function(obj, name) {
1410
                if (!obj.className) {
1411
                        return false;
1412
                }
1413
 
1414
                var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
1415
                return regExp.test(obj.className);
1416
        };
1417
 
1418
        /**
1419
        Adds specified className to specified DOM element.
1420
 
1421
        @method addClass
1422
        @static
1423
        @param {Object} obj DOM element like object to add handler to.
1424
        @param {String} name Class name
1425
        */
1426
        var addClass = function(obj, name) {
1427
                if (!hasClass(obj, name)) {
1428
                        obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name;
1429
                }
1430
        };
1431
 
1432
        /**
1433
        Removes specified className from specified DOM element.
1434
 
1435
        @method removeClass
1436
        @static
1437
        @param {Object} obj DOM element like object to add handler to.
1438
        @param {String} name Class name
1439
        */
1440
        var removeClass = function(obj, name) {
1441
                if (obj.className) {
1442
                        var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
1443
                        obj.className = obj.className.replace(regExp, function($0, $1, $2) {
1444
                                return $1 === ' ' && $2 === ' ' ? ' ' : '';
1445
                        });
1446
                }
1447
        };
1448
 
1449
        /**
1450
        Returns a given computed style of a DOM element.
1451
 
1452
        @method getStyle
1453
        @static
1454
        @param {Object} obj DOM element like object.
1455
        @param {String} name Style you want to get from the DOM element
1456
        */
1457
        var getStyle = function(obj, name) {
1458
                if (obj.currentStyle) {
1459
                        return obj.currentStyle[name];
1460
                } else if (window.getComputedStyle) {
1461
                        return window.getComputedStyle(obj, null)[name];
1462
                }
1463
        };
1464
 
1465
 
1466
        /**
1467
        Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields.
1468
 
1469
        @method getPos
1470
        @static
1471
        @param {Element} node HTML element or element id to get x, y position from.
1472
        @param {Element} root Optional root element to stop calculations at.
1473
        @return {object} Absolute position of the specified element object with x, y fields.
1474
        */
1475
        var getPos = function(node, root) {
1476
                var x = 0, y = 0, parent, doc = document, nodeRect, rootRect;
1477
 
1478
                node = node;
1479
                root = root || doc.body;
1480
 
1481
                // Returns the x, y cordinate for an element on IE 6 and IE 7
1482
                function getIEPos(node) {
1483
                        var bodyElm, rect, x = 0, y = 0;
1484
 
1485
                        if (node) {
1486
                                rect = node.getBoundingClientRect();
1487
                                bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body;
1488
                                x = rect.left + bodyElm.scrollLeft;
1489
                                y = rect.top + bodyElm.scrollTop;
1490
                        }
1491
 
1492
                        return {
1493
                                x : x,
1494
                                y : y
1495
                        };
1496
                }
1497
 
1498
                // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode
1499
                if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) {
1500
                        nodeRect = getIEPos(node);
1501
                        rootRect = getIEPos(root);
1502
 
1503
                        return {
1504
                                x : nodeRect.x - rootRect.x,
1505
                                y : nodeRect.y - rootRect.y
1506
                        };
1507
                }
1508
 
1509
                parent = node;
1510
                while (parent && parent != root && parent.nodeType) {
1511
                        x += parent.offsetLeft || 0;
1512
                        y += parent.offsetTop || 0;
1513
                        parent = parent.offsetParent;
1514
                }
1515
 
1516
                parent = node.parentNode;
1517
                while (parent && parent != root && parent.nodeType) {
1518
                        x -= parent.scrollLeft || 0;
1519
                        y -= parent.scrollTop || 0;
1520
                        parent = parent.parentNode;
1521
                }
1522
 
1523
                return {
1524
                        x : x,
1525
                        y : y
1526
                };
1527
        };
1528
 
1529
        /**
1530
        Returns the size of the specified node in pixels.
1531
 
1532
        @method getSize
1533
        @static
1534
        @param {Node} node Node to get the size of.
1535
        @return {Object} Object with a w and h property.
1536
        */
1537
        var getSize = function(node) {
1538
                return {
1539
                        w : node.offsetWidth || node.clientWidth,
1540
                        h : node.offsetHeight || node.clientHeight
1541
                };
1542
        };
1543
 
1544
        return {
1545
                get: get,
1546
                hasClass: hasClass,
1547
                addClass: addClass,
1548
                removeClass: removeClass,
1549
                getStyle: getStyle,
1550
                getPos: getPos,
1551
                getSize: getSize
1552
        };
1553
});
1554
 
1555
// Included from: src/javascript/core/Exceptions.js
1556
 
1557
/**
1558
 * Exceptions.js
1559
 *
1560
 * Copyright 2013, Moxiecode Systems AB
1561
 * Released under GPL License.
1562
 *
1563
 * License: http://www.plupload.com/license
1564
 * Contributing: http://www.plupload.com/contributing
1565
 */
1566
 
1567
define('moxie/core/Exceptions', [
1568
        'moxie/core/utils/Basic'
1569
], function(Basic) {
1570
        function _findKey(obj, value) {
1571
                var key;
1572
                for (key in obj) {
1573
                        if (obj[key] === value) {
1574
                                return key;
1575
                        }
1576
                }
1577
                return null;
1578
        }
1579
 
1580
        return {
1581
                RuntimeError: (function() {
1582
                        var namecodes = {
1583
                                NOT_INIT_ERR: 1,
1584
                                NOT_SUPPORTED_ERR: 9,
1585
                                JS_ERR: 4
1586
                        };
1587
 
1588
                        function RuntimeError(code) {
1589
                                this.code = code;
1590
                                this.name = _findKey(namecodes, code);
1591
                                this.message = this.name + ": RuntimeError " + this.code;
1592
                        }
1593
 
1594
                        Basic.extend(RuntimeError, namecodes);
1595
                        RuntimeError.prototype = Error.prototype;
1596
                        return RuntimeError;
1597
                }()),
1598
 
1599
                OperationNotAllowedException: (function() {
1600
 
1601
                        function OperationNotAllowedException(code) {
1602
                                this.code = code;
1603
                                this.name = 'OperationNotAllowedException';
1604
                        }
1605
 
1606
                        Basic.extend(OperationNotAllowedException, {
1607
                                NOT_ALLOWED_ERR: 1
1608
                        });
1609
 
1610
                        OperationNotAllowedException.prototype = Error.prototype;
1611
 
1612
                        return OperationNotAllowedException;
1613
                }()),
1614
 
1615
                ImageError: (function() {
1616
                        var namecodes = {
1617
                                WRONG_FORMAT: 1,
1618
                                MAX_RESOLUTION_ERR: 2
1619
                        };
1620
 
1621
                        function ImageError(code) {
1622
                                this.code = code;
1623
                                this.name = _findKey(namecodes, code);
1624
                                this.message = this.name + ": ImageError " + this.code;
1625
                        }
1626
 
1627
                        Basic.extend(ImageError, namecodes);
1628
                        ImageError.prototype = Error.prototype;
1629
 
1630
                        return ImageError;
1631
                }()),
1632
 
1633
                FileException: (function() {
1634
                        var namecodes = {
1635
                                NOT_FOUND_ERR: 1,
1636
                                SECURITY_ERR: 2,
1637
                                ABORT_ERR: 3,
1638
                                NOT_READABLE_ERR: 4,
1639
                                ENCODING_ERR: 5,
1640
                                NO_MODIFICATION_ALLOWED_ERR: 6,
1641
                                INVALID_STATE_ERR: 7,
1642
                                SYNTAX_ERR: 8
1643
                        };
1644
 
1645
                        function FileException(code) {
1646
                                this.code = code;
1647
                                this.name = _findKey(namecodes, code);
1648
                                this.message = this.name + ": FileException " + this.code;
1649
                        }
1650
 
1651
                        Basic.extend(FileException, namecodes);
1652
                        FileException.prototype = Error.prototype;
1653
                        return FileException;
1654
                }()),
1655
 
1656
                DOMException: (function() {
1657
                        var namecodes = {
1658
                                INDEX_SIZE_ERR: 1,
1659
                                DOMSTRING_SIZE_ERR: 2,
1660
                                HIERARCHY_REQUEST_ERR: 3,
1661
                                WRONG_DOCUMENT_ERR: 4,
1662
                                INVALID_CHARACTER_ERR: 5,
1663
                                NO_DATA_ALLOWED_ERR: 6,
1664
                                NO_MODIFICATION_ALLOWED_ERR: 7,
1665
                                NOT_FOUND_ERR: 8,
1666
                                NOT_SUPPORTED_ERR: 9,
1667
                                INUSE_ATTRIBUTE_ERR: 10,
1668
                                INVALID_STATE_ERR: 11,
1669
                                SYNTAX_ERR: 12,
1670
                                INVALID_MODIFICATION_ERR: 13,
1671
                                NAMESPACE_ERR: 14,
1672
                                INVALID_ACCESS_ERR: 15,
1673
                                VALIDATION_ERR: 16,
1674
                                TYPE_MISMATCH_ERR: 17,
1675
                                SECURITY_ERR: 18,
1676
                                NETWORK_ERR: 19,
1677
                                ABORT_ERR: 20,
1678
                                URL_MISMATCH_ERR: 21,
1679
                                QUOTA_EXCEEDED_ERR: 22,
1680
                                TIMEOUT_ERR: 23,
1681
                                INVALID_NODE_TYPE_ERR: 24,
1682
                                DATA_CLONE_ERR: 25
1683
                        };
1684
 
1685
                        function DOMException(code) {
1686
                                this.code = code;
1687
                                this.name = _findKey(namecodes, code);
1688
                                this.message = this.name + ": DOMException " + this.code;
1689
                        }
1690
 
1691
                        Basic.extend(DOMException, namecodes);
1692
                        DOMException.prototype = Error.prototype;
1693
                        return DOMException;
1694
                }()),
1695
 
1696
                EventException: (function() {
1697
                        function EventException(code) {
1698
                                this.code = code;
1699
                                this.name = 'EventException';
1700
                        }
1701
 
1702
                        Basic.extend(EventException, {
1703
                                UNSPECIFIED_EVENT_TYPE_ERR: 0
1704
                        });
1705
 
1706
                        EventException.prototype = Error.prototype;
1707
 
1708
                        return EventException;
1709
                }())
1710
        };
1711
});
1712
 
1713
// Included from: src/javascript/core/EventTarget.js
1714
 
1715
/**
1716
 * EventTarget.js
1717
 *
1718
 * Copyright 2013, Moxiecode Systems AB
1719
 * Released under GPL License.
1720
 *
1721
 * License: http://www.plupload.com/license
1722
 * Contributing: http://www.plupload.com/contributing
1723
 */
1724
 
1725
define('moxie/core/EventTarget', [
1726
        'moxie/core/Exceptions',
1727
        'moxie/core/utils/Basic'
1728
], function(x, Basic) {
1729
        /**
1730
        Parent object for all event dispatching components and objects
1731
 
1732
        @class EventTarget
1733
        @constructor EventTarget
1734
        */
1735
        function EventTarget() {
1736
                // hash of event listeners by object uid
1737
                var eventpool = {};
1738
 
1739
                Basic.extend(this, {
1740
 
1741
                        /**
1742
                        Unique id of the event dispatcher, usually overriden by children
1743
 
1744
                        @property uid
1745
                        @type String
1746
                        */
1747
                        uid: null,
1748
 
1749
                        /**
1750
                        Can be called from within a child  in order to acquire uniqie id in automated manner
1751
 
1752
                        @method init
1753
                        */
1754
                        init: function() {
1755
                                if (!this.uid) {
1756
                                        this.uid = Basic.guid('uid_');
1757
                                }
1758
                        },
1759
 
1760
                        /**
1761
                        Register a handler to a specific event dispatched by the object
1762
 
1763
                        @method addEventListener
1764
                        @param {String} type Type or basically a name of the event to subscribe to
1765
                        @param {Function} fn Callback function that will be called when event happens
1766
                        @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
1767
                        @param {Object} [scope=this] A scope to invoke event handler in
1768
                        */
1769
                        addEventListener: function(type, fn, priority, scope) {
1770
                                var self = this, list;
1771
 
1772
                                type = Basic.trim(type);
1773
 
1774
                                if (/\s/.test(type)) {
1775
                                        // multiple event types were passed for one handler
1776
                                        Basic.each(type.split(/\s+/), function(type) {
1777
                                                self.addEventListener(type, fn, priority, scope);
1778
                                        });
1779
                                        return;
1780
                                }
1781
 
1782
                                type = type.toLowerCase();
1783
                                priority = parseInt(priority, 10) || 0;
1784
 
1785
                                list = eventpool[this.uid] && eventpool[this.uid][type] || [];
1786
                                list.push({fn : fn, priority : priority, scope : scope || this});
1787
 
1788
                                if (!eventpool[this.uid]) {
1789
                                        eventpool[this.uid] = {};
1790
                                }
1791
                                eventpool[this.uid][type] = list;
1792
                        },
1793
 
1794
                        /**
1795
                        Check if any handlers were registered to the specified event
1796
 
1797
                        @method hasEventListener
1798
                        @param {String} type Type or basically a name of the event to check
1799
                        @return {Mixed} Returns a handler if it was found and false, if - not
1800
                        */
1801
                        hasEventListener: function(type) {
1802
                                return type ? !!(eventpool[this.uid] && eventpool[this.uid][type]) : !!eventpool[this.uid];
1803
                        },
1804
 
1805
                        /**
1806
                        Unregister the handler from the event, or if former was not specified - unregister all handlers
1807
 
1808
                        @method removeEventListener
1809
                        @param {String} type Type or basically a name of the event
1810
                        @param {Function} [fn] Handler to unregister
1811
                        */
1812
                        removeEventListener: function(type, fn) {
1813
                                type = type.toLowerCase();
1814
 
1815
                                var list = eventpool[this.uid] && eventpool[this.uid][type], i;
1816
 
1817
                                if (list) {
1818
                                        if (fn) {
1819
                                                for (i = list.length - 1; i >= 0; i--) {
1820
                                                        if (list[i].fn === fn) {
1821
                                                                list.splice(i, 1);
1822
                                                                break;
1823
                                                        }
1824
                                                }
1825
                                        } else {
1826
                                                list = [];
1827
                                        }
1828
 
1829
                                        // delete event list if it has become empty
1830
                                        if (!list.length) {
1831
                                                delete eventpool[this.uid][type];
1832
 
1833
                                                // and object specific entry in a hash if it has no more listeners attached
1834
                                                if (Basic.isEmptyObj(eventpool[this.uid])) {
1835
                                                        delete eventpool[this.uid];
1836
                                                }
1837
                                        }
1838
                                }
1839
                        },
1840
 
1841
                        /**
1842
                        Remove all event handlers from the object
1843
 
1844
                        @method removeAllEventListeners
1845
                        */
1846
                        removeAllEventListeners: function() {
1847
                                if (eventpool[this.uid]) {
1848
                                        delete eventpool[this.uid];
1849
                                }
1850
                        },
1851
 
1852
                        /**
1853
                        Dispatch the event
1854
 
1855
                        @method dispatchEvent
1856
                        @param {String/Object} Type of event or event object to dispatch
1857
                        @param {Mixed} [...] Variable number of arguments to be passed to a handlers
1858
                        @return {Boolean} true by default and false if any handler returned false
1859
                        */
1860
                        dispatchEvent: function(type) {
1861
                                var uid, list, args, tmpEvt, evt = {}, result = true, undef;
1862
 
1863
                                if (Basic.typeOf(type) !== 'string') {
1864
                                        // we can't use original object directly (because of Silverlight)
1865
                                        tmpEvt = type;
1866
 
1867
                                        if (Basic.typeOf(tmpEvt.type) === 'string') {
1868
                                                type = tmpEvt.type;
1869
 
1870
                                                if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event
1871
                                                        evt.total = tmpEvt.total;
1872
                                                        evt.loaded = tmpEvt.loaded;
1873
                                                }
1874
                                                evt.async = tmpEvt.async || false;
1875
                                        } else {
1876
                                                throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR);
1877
                                        }
1878
                                }
1879
 
1880
                                // check if event is meant to be dispatched on an object having specific uid
1881
                                if (type.indexOf('::') !== -1) {
1882
                                        (function(arr) {
1883
                                                uid = arr[0];
1884
                                                type = arr[1];
1885
                                        }(type.split('::')));
1886
                                } else {
1887
                                        uid = this.uid;
1888
                                }
1889
 
1890
                                type = type.toLowerCase();
1891
 
1892
                                list = eventpool[uid] && eventpool[uid][type];
1893
 
1894
                                if (list) {
1895
                                        // sort event list by prority
1896
                                        list.sort(function(a, b) { return b.priority - a.priority; });
1897
 
1898
                                        args = [].slice.call(arguments);
1899
 
1900
                                        // first argument will be pseudo-event object
1901
                                        args.shift();
1902
                                        evt.type = type;
1903
                                        args.unshift(evt);
1904
 
1905
                                        // Dispatch event to all listeners
1906
                                        var queue = [];
1907
                                        Basic.each(list, function(handler) {
1908
                                                // explicitly set the target, otherwise events fired from shims do not get it
1909
                                                args[0].target = handler.scope;
1910
                                                // if event is marked as async, detach the handler
1911
                                                if (evt.async) {
1912
                                                        queue.push(function(cb) {
1913
                                                                setTimeout(function() {
1914
                                                                        cb(handler.fn.apply(handler.scope, args) === false);
1915
                                                                }, 1);
1916
                                                        });
1917
                                                } else {
1918
                                                        queue.push(function(cb) {
1919
                                                                cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation
1920
                                                        });
1921
                                                }
1922
                                        });
1923
                                        if (queue.length) {
1924
                                                Basic.inSeries(queue, function(err) {
1925
                                                        result = !err;
1926
                                                });
1927
                                        }
1928
                                }
1929
                                return result;
1930
                        },
1931
 
1932
                        /**
1933
                        Alias for addEventListener
1934
 
1935
                        @method bind
1936
                        @protected
1937
                        */
1938
                        bind: function() {
1939
                                this.addEventListener.apply(this, arguments);
1940
                        },
1941
 
1942
                        /**
1943
                        Alias for removeEventListener
1944
 
1945
                        @method unbind
1946
                        @protected
1947
                        */
1948
                        unbind: function() {
1949
                                this.removeEventListener.apply(this, arguments);
1950
                        },
1951
 
1952
                        /**
1953
                        Alias for removeAllEventListeners
1954
 
1955
                        @method unbindAll
1956
                        @protected
1957
                        */
1958
                        unbindAll: function() {
1959
                                this.removeAllEventListeners.apply(this, arguments);
1960
                        },
1961
 
1962
                        /**
1963
                        Alias for dispatchEvent
1964
 
1965
                        @method trigger
1966
                        @protected
1967
                        */
1968
                        trigger: function() {
1969
                                return this.dispatchEvent.apply(this, arguments);
1970
                        },
1971
 
1972
 
1973
                        /**
1974
                        Converts properties of on[event] type to corresponding event handlers,
1975
                        is used to avoid extra hassle around the process of calling them back
1976
 
1977
                        @method convertEventPropsToHandlers
1978
                        @private
1979
                        */
1980
                        convertEventPropsToHandlers: function(handlers) {
1981
                                var h;
1982
 
1983
                                if (Basic.typeOf(handlers) !== 'array') {
1984
                                        handlers = [handlers];
1985
                                }
1986
 
1987
                                for (var i = 0; i < handlers.length; i++) {
1988
                                        h = 'on' + handlers[i];
1989
 
1990
                                        if (Basic.typeOf(this[h]) === 'function') {
1991
                                                this.addEventListener(handlers[i], this[h]);
1992
                                        } else if (Basic.typeOf(this[h]) === 'undefined') {
1993
                                                this[h] = null; // object must have defined event properties, even if it doesn't make use of them
1994
                                        }
1995
                                }
1996
                        }
1997
 
1998
                });
1999
        }
2000
 
2001
        EventTarget.instance = new EventTarget();
2002
 
2003
        return EventTarget;
2004
});
2005
 
2006
// Included from: src/javascript/core/utils/Encode.js
2007
 
2008
/**
2009
 * Encode.js
2010
 *
2011
 * Copyright 2013, Moxiecode Systems AB
2012
 * Released under GPL License.
2013
 *
2014
 * License: http://www.plupload.com/license
2015
 * Contributing: http://www.plupload.com/contributing
2016
 */
2017
 
2018
define('moxie/core/utils/Encode', [], function() {
2019
 
2020
        /**
2021
        Encode string with UTF-8
2022
 
2023
        @method utf8_encode
2024
        @for Utils
2025
        @static
2026
        @param {String} str String to encode
2027
        @return {String} UTF-8 encoded string
2028
        */
2029
        var utf8_encode = function(str) {
2030
                return unescape(encodeURIComponent(str));
2031
        };
2032
 
2033
        /**
2034
        Decode UTF-8 encoded string
2035
 
2036
        @method utf8_decode
2037
        @static
2038
        @param {String} str String to decode
2039
        @return {String} Decoded string
2040
        */
2041
        var utf8_decode = function(str_data) {
2042
                return decodeURIComponent(escape(str_data));
2043
        };
2044
 
2045
        /**
2046
        Decode Base64 encoded string (uses browser's default method if available),
2047
        from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js
2048
 
2049
        @method atob
2050
        @static
2051
        @param {String} data String to decode
2052
        @return {String} Decoded string
2053
        */
2054
        var atob = function(data, utf8) {
2055
                if (typeof(window.atob) === 'function') {
2056
                        return utf8 ? utf8_decode(window.atob(data)) : window.atob(data);
2057
                }
2058
 
2059
                // http://kevin.vanzonneveld.net
2060
                // +   original by: Tyler Akins (http://rumkin.com)
2061
                // +   improved by: Thunder.m
2062
                // +      input by: Aman Gupta
2063
                // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
2064
                // +   bugfixed by: Onno Marsman
2065
                // +   bugfixed by: Pellentesque Malesuada
2066
                // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
2067
                // +      input by: Brett Zamir (http://brett-zamir.me)
2068
                // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
2069
                // *     example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
2070
                // *     returns 1: 'Kevin van Zonneveld'
2071
                // mozilla has this native
2072
                // - but breaks in 2.0.0.12!
2073
                //if (typeof this.window.atob == 'function') {
2074
                //    return atob(data);
2075
                //}
2076
                var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
2077
                var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
2078
                        ac = 0,
2079
                        dec = "",
2080
                        tmp_arr = [];
2081
 
2082
                if (!data) {
2083
                        return data;
2084
                }
2085
 
2086
                data += '';
2087
 
2088
                do { // unpack four hexets into three octets using index points in b64
2089
                        h1 = b64.indexOf(data.charAt(i++));
2090
                        h2 = b64.indexOf(data.charAt(i++));
2091
                        h3 = b64.indexOf(data.charAt(i++));
2092
                        h4 = b64.indexOf(data.charAt(i++));
2093
 
2094
                        bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
2095
 
2096
                        o1 = bits >> 16 & 0xff;
2097
                        o2 = bits >> 8 & 0xff;
2098
                        o3 = bits & 0xff;
2099
 
2100
                        if (h3 == 64) {
2101
                                tmp_arr[ac++] = String.fromCharCode(o1);
2102
                        } else if (h4 == 64) {
2103
                                tmp_arr[ac++] = String.fromCharCode(o1, o2);
2104
                        } else {
2105
                                tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
2106
                        }
2107
                } while (i < data.length);
2108
 
2109
                dec = tmp_arr.join('');
2110
 
2111
                return utf8 ? utf8_decode(dec) : dec;
2112
        };
2113
 
2114
        /**
2115
        Base64 encode string (uses browser's default method if available),
2116
        from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js
2117
 
2118
        @method btoa
2119
        @static
2120
        @param {String} data String to encode
2121
        @return {String} Base64 encoded string
2122
        */
2123
        var btoa = function(data, utf8) {
2124
                if (utf8) {
2125
                        utf8_encode(data);
2126
                }
2127
 
2128
                if (typeof(window.btoa) === 'function') {
2129
                        return window.btoa(data);
2130
                }
2131
 
2132
                // http://kevin.vanzonneveld.net
2133
                // +   original by: Tyler Akins (http://rumkin.com)
2134
                // +   improved by: Bayron Guevara
2135
                // +   improved by: Thunder.m
2136
                // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
2137
                // +   bugfixed by: Pellentesque Malesuada
2138
                // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
2139
                // +   improved by: RafaÅ‚ Kukawski (http://kukawski.pl)
2140
                // *     example 1: base64_encode('Kevin van Zonneveld');
2141
                // *     returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
2142
                // mozilla has this native
2143
                // - but breaks in 2.0.0.12!
2144
                var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
2145
                var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
2146
                        ac = 0,
2147
                        enc = "",
2148
                        tmp_arr = [];
2149
 
2150
                if (!data) {
2151
                        return data;
2152
                }
2153
 
2154
                do { // pack three octets into four hexets
2155
                        o1 = data.charCodeAt(i++);
2156
                        o2 = data.charCodeAt(i++);
2157
                        o3 = data.charCodeAt(i++);
2158
 
2159
                        bits = o1 << 16 | o2 << 8 | o3;
2160
 
2161
                        h1 = bits >> 18 & 0x3f;
2162
                        h2 = bits >> 12 & 0x3f;
2163
                        h3 = bits >> 6 & 0x3f;
2164
                        h4 = bits & 0x3f;
2165
 
2166
                        // use hexets to index into b64, and append result to encoded string
2167
                        tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
2168
                } while (i < data.length);
2169
 
2170
                enc = tmp_arr.join('');
2171
 
2172
                var r = data.length % 3;
2173
 
2174
                return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
2175
        };
2176
 
2177
 
2178
        return {
2179
                utf8_encode: utf8_encode,
2180
                utf8_decode: utf8_decode,
2181
                atob: atob,
2182
                btoa: btoa
2183
        };
2184
});
2185
 
2186
// Included from: src/javascript/runtime/Runtime.js
2187
 
2188
/**
2189
 * Runtime.js
2190
 *
2191
 * Copyright 2013, Moxiecode Systems AB
2192
 * Released under GPL License.
2193
 *
2194
 * License: http://www.plupload.com/license
2195
 * Contributing: http://www.plupload.com/contributing
2196
 */
2197
 
2198
define('moxie/runtime/Runtime', [
2199
        "moxie/core/utils/Basic",
2200
        "moxie/core/utils/Dom",
2201
        "moxie/core/EventTarget"
2202
], function(Basic, Dom, EventTarget) {
2203
        var runtimeConstructors = {}, runtimes = {};
2204
 
2205
        /**
2206
        Common set of methods and properties for every runtime instance
2207
 
2208
        @class Runtime
2209
 
2210
        @param {Object} options
2211
        @param {String} type Sanitized name of the runtime
2212
        @param {Object} [caps] Set of capabilities that differentiate specified runtime
2213
        @param {Object} [modeCaps] Set of capabilities that do require specific operational mode
2214
        @param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested
2215
        */
2216
        function Runtime(options, type, caps, modeCaps, preferredMode) {
2217
                /**
2218
                Dispatched when runtime is initialized and ready.
2219
                Results in RuntimeInit on a connected component.
2220
 
2221
                @event Init
2222
                */
2223
 
2224
                /**
2225
                Dispatched when runtime fails to initialize.
2226
                Results in RuntimeError on a connected component.
2227
 
2228
                @event Error
2229
                */
2230
 
2231
                var self = this
2232
                , _shim
2233
                , _uid = Basic.guid(type + '_')
2234
                , defaultMode = preferredMode || 'browser'
2235
                ;
2236
 
2237
                options = options || {};
2238
 
2239
                // register runtime in private hash
2240
                runtimes[_uid] = this;
2241
 
2242
                /**
2243
                Default set of capabilities, which can be redifined later by specific runtime
2244
 
2245
                @private
2246
                @property caps
2247
                @type Object
2248
                */
2249
                caps = Basic.extend({
2250
                        // Runtime can:
2251
                        // provide access to raw binary data of the file
2252
                        access_binary: false,
2253
                        // provide access to raw binary data of the image (image extension is optional)
2254
                        access_image_binary: false,
2255
                        // display binary data as thumbs for example
2256
                        display_media: false,
2257
                        // make cross-domain requests
2258
                        do_cors: false,
2259
                        // accept files dragged and dropped from the desktop
2260
                        drag_and_drop: false,
2261
                        // filter files in selection dialog by their extensions
2262
                        filter_by_extension: true,
2263
                        // resize image (and manipulate it raw data of any file in general)
2264
                        resize_image: false,
2265
                        // periodically report how many bytes of total in the file were uploaded (loaded)
2266
                        report_upload_progress: false,
2267
                        // provide access to the headers of http response
2268
                        return_response_headers: false,
2269
                        // support response of specific type, which should be passed as an argument
2270
                        // e.g. runtime.can('return_response_type', 'blob')
2271
                        return_response_type: false,
2272
                        // return http status code of the response
2273
                        return_status_code: true,
2274
                        // send custom http header with the request
2275
                        send_custom_headers: false,
2276
                        // pick up the files from a dialog
2277
                        select_file: false,
2278
                        // select whole folder in file browse dialog
2279
                        select_folder: false,
2280
                        // select multiple files at once in file browse dialog
2281
                        select_multiple: true,
2282
                        // send raw binary data, that is generated after image resizing or manipulation of other kind
2283
                        send_binary_string: false,
2284
                        // send cookies with http request and therefore retain session
2285
                        send_browser_cookies: true,
2286
                        // send data formatted as multipart/form-data
2287
                        send_multipart: true,
2288
                        // slice the file or blob to smaller parts
2289
                        slice_blob: false,
2290
                        // upload file without preloading it to memory, stream it out directly from disk
2291
                        stream_upload: false,
2292
                        // programmatically trigger file browse dialog
2293
                        summon_file_dialog: false,
2294
                        // upload file of specific size, size should be passed as argument
2295
                        // e.g. runtime.can('upload_filesize', '500mb')
2296
                        upload_filesize: true,
2297
                        // initiate http request with specific http method, method should be passed as argument
2298
                        // e.g. runtime.can('use_http_method', 'put')
2299
                        use_http_method: true
2300
                }, caps);
2301
 
2302
 
2303
                // default to the mode that is compatible with preferred caps
2304
                if (options.preferred_caps) {
2305
                        defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode);
2306
                }
2307
 
2308
                // small extension factory here (is meant to be extended with actual extensions constructors)
2309
                _shim = (function() {
2310
                        var objpool = {};
2311
                        return {
2312
                                exec: function(uid, comp, fn, args) {
2313
                                        if (_shim[comp]) {
2314
                                                if (!objpool[uid]) {
2315
                                                        objpool[uid] = {
2316
                                                                context: this,
2317
                                                                instance: new _shim[comp]()
2318
                                                        };
2319
                                                }
2320
                                                if (objpool[uid].instance[fn]) {
2321
                                                        return objpool[uid].instance[fn].apply(this, args);
2322
                                                }
2323
                                        }
2324
                                },
2325
 
2326
                                removeInstance: function(uid) {
2327
                                        delete objpool[uid];
2328
                                },
2329
 
2330
                                removeAllInstances: function() {
2331
                                        var self = this;
2332
                                        Basic.each(objpool, function(obj, uid) {
2333
                                                if (Basic.typeOf(obj.instance.destroy) === 'function') {
2334
                                                        obj.instance.destroy.call(obj.context);
2335
                                                }
2336
                                                self.removeInstance(uid);
2337
                                        });
2338
                                }
2339
                        };
2340
                }());
2341
 
2342
 
2343
                // public methods
2344
                Basic.extend(this, {
2345
                        /**
2346
                        Specifies whether runtime instance was initialized or not
2347
 
2348
                        @property initialized
2349
                        @type {Boolean}
2350
                        @default false
2351
                        */
2352
                        initialized: false, // shims require this flag to stop initialization retries
2353
 
2354
                        /**
2355
                        Unique ID of the runtime
2356
 
2357
                        @property uid
2358
                        @type {String}
2359
                        */
2360
                        uid: _uid,
2361
 
2362
                        /**
2363
                        Runtime type (e.g. flash, html5, etc)
2364
 
2365
                        @property type
2366
                        @type {String}
2367
                        */
2368
                        type: type,
2369
 
2370
                        /**
2371
                        Runtime (not native one) may operate in browser or client mode.
2372
 
2373
                        @property mode
2374
                        @private
2375
                        @type {String|Boolean} current mode or false, if none possible
2376
                        */
2377
                        mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode),
2378
 
2379
                        /**
2380
                        id of the DOM container for the runtime (if available)
2381
 
2382
                        @property shimid
2383
                        @type {String}
2384
                        */
2385
                        shimid: _uid + '_container',
2386
 
2387
                        /**
2388
                        Number of connected clients. If equal to zero, runtime can be destroyed
2389
 
2390
                        @property clients
2391
                        @type {Number}
2392
                        */
2393
                        clients: 0,
2394
 
2395
                        /**
2396
                        Runtime initialization options
2397
 
2398
                        @property options
2399
                        @type {Object}
2400
                        */
2401
                        options: options,
2402
 
2403
                        /**
2404
                        Checks if the runtime has specific capability
2405
 
2406
                        @method can
2407
                        @param {String} cap Name of capability to check
2408
                        @param {Mixed} [value] If passed, capability should somehow correlate to the value
2409
                        @param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set)
2410
                        @return {Boolean} true if runtime has such capability and false, if - not
2411
                        */
2412
                        can: function(cap, value) {
2413
                                var refCaps = arguments[2] || caps;
2414
 
2415
                                // if cap var is a comma-separated list of caps, convert it to object (key/value)
2416
                                if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') {
2417
                                        cap = Runtime.parseCaps(cap);
2418
                                }
2419
 
2420
                                if (Basic.typeOf(cap) === 'object') {
2421
                                        for (var key in cap) {
2422
                                                if (!this.can(key, cap[key], refCaps)) {
2423
                                                        return false;
2424
                                                }
2425
                                        }
2426
                                        return true;
2427
                                }
2428
 
2429
                                // check the individual cap
2430
                                if (Basic.typeOf(refCaps[cap]) === 'function') {
2431
                                        return refCaps[cap].call(this, value);
2432
                                } else {
2433
                                        return (value === refCaps[cap]);
2434
                                }
2435
                        },
2436
 
2437
                        /**
2438
                        Returns container for the runtime as DOM element
2439
 
2440
                        @method getShimContainer
2441
                        @return {DOMElement}
2442
                        */
2443
                        getShimContainer: function() {
2444
                                var container, shimContainer = Dom.get(this.shimid);
2445
 
2446
                                // if no container for shim, create one
2447
                                if (!shimContainer) {
2448
                                        container = this.options.container ? Dom.get(this.options.container) : document.body;
2449
 
2450
                                        // create shim container and insert it at an absolute position into the outer container
2451
                                        shimContainer = document.createElement('div');
2452
                                        shimContainer.id = this.shimid;
2453
                                        shimContainer.className = 'moxie-shim moxie-shim-' + this.type;
2454
 
2455
                                        Basic.extend(shimContainer.style, {
2456
                                                position: 'absolute',
2457
                                                top: '0px',
2458
                                                left: '0px',
2459
                                                width: '1px',
2460
                                                height: '1px',
2461
                                                overflow: 'hidden'
2462
                                        });
2463
 
2464
                                        container.appendChild(shimContainer);
2465
                                        container = null;
2466
                                }
2467
 
2468
                                return shimContainer;
2469
                        },
2470
 
2471
                        /**
2472
                        Returns runtime as DOM element (if appropriate)
2473
 
2474
                        @method getShim
2475
                        @return {DOMElement}
2476
                        */
2477
                        getShim: function() {
2478
                                return _shim;
2479
                        },
2480
 
2481
                        /**
2482
                        Invokes a method within the runtime itself (might differ across the runtimes)
2483
 
2484
                        @method shimExec
2485
                        @param {Mixed} []
2486
                        @protected
2487
                        @return {Mixed} Depends on the action and component
2488
                        */
2489
                        shimExec: function(component, action) {
2490
                                var args = [].slice.call(arguments, 2);
2491
                                return self.getShim().exec.call(this, this.uid, component, action, args);
2492
                        },
2493
 
2494
                        /**
2495
                        Operaional interface that is used by components to invoke specific actions on the runtime
2496
                        (is invoked in the scope of component)
2497
 
2498
                        @method exec
2499
                        @param {Mixed} []*
2500
                        @protected
2501
                        @return {Mixed} Depends on the action and component
2502
                        */
2503
                        exec: function(component, action) { // this is called in the context of component, not runtime
2504
                                var args = [].slice.call(arguments, 2);
2505
 
2506
                                if (self[component] && self[component][action]) {
2507
                                        return self[component][action].apply(this, args);
2508
                                }
2509
                                return self.shimExec.apply(this, arguments);
2510
                        },
2511
 
2512
                        /**
2513
                        Destroys the runtime (removes all events and deletes DOM structures)
2514
 
2515
                        @method destroy
2516
                        */
2517
                        destroy: function() {
2518
                                if (!self) {
2519
                                        return; // obviously already destroyed
2520
                                }
2521
 
2522
                                var shimContainer = Dom.get(this.shimid);
2523
                                if (shimContainer) {
2524
                                        shimContainer.parentNode.removeChild(shimContainer);
2525
                                }
2526
 
2527
                                if (_shim) {
2528
                                        _shim.removeAllInstances();
2529
                                }
2530
 
2531
                                this.unbindAll();
2532
                                delete runtimes[this.uid];
2533
                                this.uid = null; // mark this runtime as destroyed
2534
                                _uid = self = _shim = shimContainer = null;
2535
                        }
2536
                });
2537
 
2538
                // once we got the mode, test against all caps
2539
                if (this.mode && options.required_caps && !this.can(options.required_caps)) {
2540
                        this.mode = false;
2541
                }      
2542
        }
2543
 
2544
 
2545
        /**
2546
        Default order to try different runtime types
2547
 
2548
        @property order
2549
        @type String
2550
        @static
2551
        */
2552
        Runtime.order = 'html5,flash,silverlight,html4';
2553
 
2554
 
2555
        /**
2556
        Retrieves runtime from private hash by it's uid
2557
 
2558
        @method getRuntime
2559
        @private
2560
        @static
2561
        @param {String} uid Unique identifier of the runtime
2562
        @return {Runtime|Boolean} Returns runtime, if it exists and false, if - not
2563
        */
2564
        Runtime.getRuntime = function(uid) {
2565
                return runtimes[uid] ? runtimes[uid] : false;
2566
        };
2567
 
2568
 
2569
        /**
2570
        Register constructor for the Runtime of new (or perhaps modified) type
2571
 
2572
        @method addConstructor
2573
        @static
2574
        @param {String} type Runtime type (e.g. flash, html5, etc)
2575
        @param {Function} construct Constructor for the Runtime type
2576
        */
2577
        Runtime.addConstructor = function(type, constructor) {
2578
                constructor.prototype = EventTarget.instance;
2579
                runtimeConstructors[type] = constructor;
2580
        };
2581
 
2582
 
2583
        /**
2584
        Get the constructor for the specified type.
2585
 
2586
        method getConstructor
2587
        @static
2588
        @param {String} type Runtime type (e.g. flash, html5, etc)
2589
        @return {Function} Constructor for the Runtime type
2590
        */
2591
        Runtime.getConstructor = function(type) {
2592
                return runtimeConstructors[type] || null;
2593
        };
2594
 
2595
 
2596
        /**
2597
        Get info about the runtime (uid, type, capabilities)
2598
 
2599
        @method getInfo
2600
        @static
2601
        @param {String} uid Unique identifier of the runtime
2602
        @return {Mixed} Info object or null if runtime doesn't exist
2603
        */
2604
        Runtime.getInfo = function(uid) {
2605
                var runtime = Runtime.getRuntime(uid);
2606
 
2607
                if (runtime) {
2608
                        return {
2609
                                uid: runtime.uid,
2610
                                type: runtime.type,
2611
                                mode: runtime.mode,
2612
                                can: function() {
2613
                                        return runtime.can.apply(runtime, arguments);
2614
                                }
2615
                        };
2616
                }
2617
                return null;
2618
        };
2619
 
2620
 
2621
        /**
2622
        Convert caps represented by a comma-separated string to the object representation.
2623
 
2624
        @method parseCaps
2625
        @static
2626
        @param {String} capStr Comma-separated list of capabilities
2627
        @return {Object}
2628
        */
2629
        Runtime.parseCaps = function(capStr) {
2630
                var capObj = {};
2631
 
2632
                if (Basic.typeOf(capStr) !== 'string') {
2633
                        return capStr || {};
2634
                }
2635
 
2636
                Basic.each(capStr.split(','), function(key) {
2637
                        capObj[key] = true; // we assume it to be - true
2638
                });
2639
 
2640
                return capObj;
2641
        };
2642
 
2643
        /**
2644
        Test the specified runtime for specific capabilities.
2645
 
2646
        @method can
2647
        @static
2648
        @param {String} type Runtime type (e.g. flash, html5, etc)
2649
        @param {String|Object} caps Set of capabilities to check
2650
        @return {Boolean} Result of the test
2651
        */
2652
        Runtime.can = function(type, caps) {
2653
                var runtime
2654
                , constructor = Runtime.getConstructor(type)
2655
                , mode
2656
                ;
2657
                if (constructor) {
2658
                        runtime = new constructor({
2659
                                required_caps: caps
2660
                        });
2661
                        mode = runtime.mode;
2662
                        runtime.destroy();
2663
                        return !!mode;
2664
                }
2665
                return false;
2666
        };
2667
 
2668
 
2669
        /**
2670
        Figure out a runtime that supports specified capabilities.
2671
 
2672
        @method thatCan
2673
        @static
2674
        @param {String|Object} caps Set of capabilities to check
2675
        @param {String} [runtimeOrder] Comma-separated list of runtimes to check against
2676
        @return {String} Usable runtime identifier or null
2677
        */
2678
        Runtime.thatCan = function(caps, runtimeOrder) {
2679
                var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/);
2680
                for (var i in types) {
2681
                        if (Runtime.can(types[i], caps)) {
2682
                                return types[i];
2683
                        }
2684
                }
2685
                return null;
2686
        };
2687
 
2688
 
2689
        /**
2690
        Figure out an operational mode for the specified set of capabilities.
2691
 
2692
        @method getMode
2693
        @static
2694
        @param {Object} modeCaps Set of capabilities that depend on particular runtime mode
2695
        @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for
2696
        @param {String|Boolean} [defaultMode='browser'] Default mode to use
2697
        @return {String|Boolean} Compatible operational mode
2698
        */
2699
        Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) {
2700
                var mode = null;
2701
 
2702
                if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified
2703
                        defaultMode = 'browser';
2704
                }
2705
 
2706
                if (requiredCaps && !Basic.isEmptyObj(modeCaps)) {
2707
                        // loop over required caps and check if they do require the same mode
2708
                        Basic.each(requiredCaps, function(value, cap) {
2709
                                if (modeCaps.hasOwnProperty(cap)) {
2710
                                        var capMode = modeCaps[cap](value);
2711
 
2712
                                        // make sure we always have an array
2713
                                        if (typeof(capMode) === 'string') {
2714
                                                capMode = [capMode];
2715
                                        }
2716
 
2717
                                        if (!mode) {
2718
                                                mode = capMode;
2719
                                        } else if (!(mode = Basic.arrayIntersect(mode, capMode))) {
2720
                                                // if cap requires conflicting mode - runtime cannot fulfill required caps
2721
                                                return (mode = false);
2722
                                        }
2723
                                }
2724
                        });
2725
 
2726
                        if (mode) {
2727
                                return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0];
2728
                        } else if (mode === false) {
2729
                                return false;
2730
                        }
2731
                }
2732
                return defaultMode;
2733
        };
2734
 
2735
 
2736
        /**
2737
        Capability check that always returns true
2738
 
2739
        @private
2740
        @static
2741
        @return {True}
2742
        */
2743
        Runtime.capTrue = function() {
2744
                return true;
2745
        };
2746
 
2747
        /**
2748
        Capability check that always returns false
2749
 
2750
        @private
2751
        @static
2752
        @return {False}
2753
        */
2754
        Runtime.capFalse = function() {
2755
                return false;
2756
        };
2757
 
2758
        /**
2759
        Evaluate the expression to boolean value and create a function that always returns it.
2760
 
2761
        @private
2762
        @static
2763
        @param {Mixed} expr Expression to evaluate
2764
        @return {Function} Function returning the result of evaluation
2765
        */
2766
        Runtime.capTest = function(expr) {
2767
                return function() {
2768
                        return !!expr;
2769
                };
2770
        };
2771
 
2772
        return Runtime;
2773
});
2774
 
2775
// Included from: src/javascript/runtime/RuntimeClient.js
2776
 
2777
/**
2778
 * RuntimeClient.js
2779
 *
2780
 * Copyright 2013, Moxiecode Systems AB
2781
 * Released under GPL License.
2782
 *
2783
 * License: http://www.plupload.com/license
2784
 * Contributing: http://www.plupload.com/contributing
2785
 */
2786
 
2787
define('moxie/runtime/RuntimeClient', [
2788
        'moxie/core/Exceptions',
2789
        'moxie/core/utils/Basic',
2790
        'moxie/runtime/Runtime'
2791
], function(x, Basic, Runtime) {
2792
        /**
2793
        Set of methods and properties, required by a component to acquire ability to connect to a runtime
2794
 
2795
        @class RuntimeClient
2796
        */
2797
        return function RuntimeClient() {
2798
                var runtime;
2799
 
2800
                Basic.extend(this, {
2801
                        /**
2802
                        Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one.
2803
                        Increments number of clients connected to the specified runtime.
2804
 
2805
                        @method connectRuntime
2806
                        @param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites
2807
                        */
2808
                        connectRuntime: function(options) {
2809
                                var comp = this, ruid;
2810
 
2811
                                function initialize(items) {
2812
                                        var type, constructor;
2813
 
2814
                                        // if we ran out of runtimes
2815
                                        if (!items.length) {
2816
                                                comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
2817
                                                runtime = null;
2818
                                                return;
2819
                                        }
2820
 
2821
                                        type = items.shift();
2822
                                        constructor = Runtime.getConstructor(type);
2823
                                        if (!constructor) {
2824
                                                initialize(items);
2825
                                                return;
2826
                                        }
2827
 
2828
                                        // try initializing the runtime
2829
                                        runtime = new constructor(options);
2830
 
2831
                                        runtime.bind('Init', function() {
2832
                                                // mark runtime as initialized
2833
                                                runtime.initialized = true;
2834
 
2835
                                                // jailbreak ...
2836
                                                setTimeout(function() {
2837
                                                        runtime.clients++;
2838
                                                        // this will be triggered on component
2839
                                                        comp.trigger('RuntimeInit', runtime);
2840
                                                }, 1);
2841
                                        });
2842
 
2843
                                        runtime.bind('Error', function() {
2844
                                                runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here
2845
                                                initialize(items);
2846
                                        });
2847
 
2848
                                        /*runtime.bind('Exception', function() { });*/
2849
 
2850
                                        // check if runtime managed to pick-up operational mode
2851
                                        if (!runtime.mode) {
2852
                                                runtime.trigger('Error');
2853
                                                return;
2854
                                        }
2855
 
2856
                                        runtime.init();
2857
                                }
2858
 
2859
                                // check if a particular runtime was requested
2860
                                if (Basic.typeOf(options) === 'string') {
2861
                                        ruid = options;
2862
                                } else if (Basic.typeOf(options.ruid) === 'string') {
2863
                                        ruid = options.ruid;
2864
                                }
2865
 
2866
                                if (ruid) {
2867
                                        runtime = Runtime.getRuntime(ruid);
2868
                                        if (runtime) {
2869
                                                runtime.clients++;
2870
                                                return runtime;
2871
                                        } else {
2872
                                                // there should be a runtime and there's none - weird case
2873
                                                throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR);
2874
                                        }
2875
                                }
2876
 
2877
                                // initialize a fresh one, that fits runtime list and required features best
2878
                                initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/));
2879
                        },
2880
 
2881
                        /**
2882
                        Returns the runtime to which the client is currently connected.
2883
 
2884
                        @method getRuntime
2885
                        @return {Runtime} Runtime or null if client is not connected
2886
                        */
2887
                        getRuntime: function() {
2888
                                if (runtime && runtime.uid) {
2889
                                        return runtime;
2890
                                }
2891
                                runtime = null; // make sure we do not leave zombies rambling around
2892
                                return null;
2893
                        },
2894
 
2895
                        /**
2896
                        Disconnects from the runtime. Decrements number of clients connected to the specified runtime.
2897
 
2898
                        @method disconnectRuntime
2899
                        */
2900
                        disconnectRuntime: function() {
2901
                                if (runtime && --runtime.clients <= 0) {
2902
                                        runtime.destroy();
2903
                                        runtime = null;
2904
                                }
2905
                        }
2906
 
2907
                });
2908
        };
2909
 
2910
 
2911
});
2912
 
2913
// Included from: src/javascript/file/Blob.js
2914
 
2915
/**
2916
 * Blob.js
2917
 *
2918
 * Copyright 2013, Moxiecode Systems AB
2919
 * Released under GPL License.
2920
 *
2921
 * License: http://www.plupload.com/license
2922
 * Contributing: http://www.plupload.com/contributing
2923
 */
2924
 
2925
define('moxie/file/Blob', [
2926
        'moxie/core/utils/Basic',
2927
        'moxie/core/utils/Encode',
2928
        'moxie/runtime/RuntimeClient'
2929
], function(Basic, Encode, RuntimeClient) {
2930
 
2931
        var blobpool = {};
2932
 
2933
        /**
2934
        @class Blob
2935
        @constructor
2936
        @param {String} ruid Unique id of the runtime, to which this blob belongs to
2937
        @param {Object} blob Object "Native" blob object, as it is represented in the runtime
2938
        */
2939
        function Blob(ruid, blob) {
2940
 
2941
                function _sliceDetached(start, end, type) {
2942
                        var blob, data = blobpool[this.uid];
2943
 
2944
                        if (Basic.typeOf(data) !== 'string' || !data.length) {
2945
                                return null; // or throw exception
2946
                        }
2947
 
2948
                        blob = new Blob(null, {
2949
                                type: type,
2950
                                size: end - start
2951
                        });
2952
                        blob.detach(data.substr(start, blob.size));
2953
 
2954
                        return blob;
2955
                }
2956
 
2957
                RuntimeClient.call(this);
2958
 
2959
                if (ruid) {    
2960
                        this.connectRuntime(ruid);
2961
                }
2962
 
2963
                if (!blob) {
2964
                        blob = {};
2965
                } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string
2966
                        blob = { data: blob };
2967
                }
2968
 
2969
                Basic.extend(this, {
2970
 
2971
                        /**
2972
                        Unique id of the component
2973
 
2974
                        @property uid
2975
                        @type {String}
2976
                        */
2977
                        uid: blob.uid || Basic.guid('uid_'),
2978
 
2979
                        /**
2980
                        Unique id of the connected runtime, if falsy, then runtime will have to be initialized
2981
                        before this Blob can be used, modified or sent
2982
 
2983
                        @property ruid
2984
                        @type {String}
2985
                        */
2986
                        ruid: ruid,
2987
 
2988
                        /**
2989
                        Size of blob
2990
 
2991
                        @property size
2992
                        @type {Number}
2993
                        @default 0
2994
                        */
2995
                        size: blob.size || 0,
2996
 
2997
                        /**
2998
                        Mime type of blob
2999
 
3000
                        @property type
3001
                        @type {String}
3002
                        @default ''
3003
                        */
3004
                        type: blob.type || '',
3005
 
3006
                        /**
3007
                        @method slice
3008
                        @param {Number} [start=0]
3009
                        */
3010
                        slice: function(start, end, type) {            
3011
                                if (this.isDetached()) {
3012
                                        return _sliceDetached.apply(this, arguments);
3013
                                }
3014
                                return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type);
3015
                        },
3016
 
3017
                        /**
3018
                        Returns "native" blob object (as it is represented in connected runtime) or null if not found
3019
 
3020
                        @method getSource
3021
                        @return {Blob} Returns "native" blob object or null if not found
3022
                        */
3023
                        getSource: function() {
3024
                                if (!blobpool[this.uid]) {
3025
                                        return null;   
3026
                                }
3027
                                return blobpool[this.uid];
3028
                        },
3029
 
3030
                        /**
3031
                        Detaches blob from any runtime that it depends on and initialize with standalone value
3032
 
3033
                        @method detach
3034
                        @protected
3035
                        @param {DOMString} [data=''] Standalone value
3036
                        */
3037
                        detach: function(data) {
3038
                                if (this.ruid) {
3039
                                        this.getRuntime().exec.call(this, 'Blob', 'destroy');
3040
                                        this.disconnectRuntime();
3041
                                        this.ruid = null;
3042
                                }
3043
 
3044
                                data = data || '';
3045
 
3046
                                // if dataUrl, convert to binary string
3047
                                var matches = data.match(/^data:([^;]*);base64,/);
3048
                                if (matches) {
3049
                                        this.type = matches[1];
3050
                                        data = Encode.atob(data.substring(data.indexOf('base64,') + 7));
3051
                                }
3052
 
3053
                                this.size = data.length;
3054
 
3055
                                blobpool[this.uid] = data;
3056
                        },
3057
 
3058
                        /**
3059
                        Checks if blob is standalone (detached of any runtime)
3060
 
3061
                        @method isDetached
3062
                        @protected
3063
                        @return {Boolean}
3064
                        */
3065
                        isDetached: function() {
3066
                                return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string';
3067
                        },
3068
 
3069
                        /**
3070
                        Destroy Blob and free any resources it was using
3071
 
3072
                        @method destroy
3073
                        */
3074
                        destroy: function() {
3075
                                this.detach();
3076
                                delete blobpool[this.uid];
3077
                        }
3078
                });
3079
 
3080
 
3081
                if (blob.data) {
3082
                        this.detach(blob.data); // auto-detach if payload has been passed
3083
                } else {
3084
                        blobpool[this.uid] = blob;     
3085
                }
3086
        }
3087
 
3088
        return Blob;
3089
});
3090
 
3091
// Included from: src/javascript/file/File.js
3092
 
3093
/**
3094
 * File.js
3095
 *
3096
 * Copyright 2013, Moxiecode Systems AB
3097
 * Released under GPL License.
3098
 *
3099
 * License: http://www.plupload.com/license
3100
 * Contributing: http://www.plupload.com/contributing
3101
 */
3102
 
3103
define('moxie/file/File', [
3104
        'moxie/core/utils/Basic',
3105
        'moxie/core/utils/Mime',
3106
        'moxie/file/Blob'
3107
], function(Basic, Mime, Blob) {
3108
        /**
3109
        @class File
3110
        @extends Blob
3111
        @constructor
3112
        @param {String} ruid Unique id of the runtime, to which this blob belongs to
3113
        @param {Object} file Object "Native" file object, as it is represented in the runtime
3114
        */
3115
        function File(ruid, file) {
3116
                var name, type;
3117
 
3118
                if (!file) { // avoid extra errors in case we overlooked something
3119
                        file = {};
3120
                }
3121
 
3122
                // figure out the type
3123
                if (file.type && file.type !== '') {
3124
                        type = file.type;
3125
                } else {
3126
                        type = Mime.getFileMime(file.name);
3127
                }
3128
 
3129
                // sanitize file name or generate new one
3130
                if (file.name) {
3131
                        name = file.name.replace(/\\/g, '/');
3132
                        name = name.substr(name.lastIndexOf('/') + 1);
3133
                } else {
3134
                        var prefix = type.split('/')[0];
3135
                        name = Basic.guid((prefix !== '' ? prefix : 'file') + '_');
3136
 
3137
                        if (Mime.extensions[type]) {
3138
                                name += '.' + Mime.extensions[type][0]; // append proper extension if possible
3139
                        }
3140
                }
3141
 
3142
                Blob.apply(this, arguments);
3143
 
3144
                Basic.extend(this, {
3145
                        /**
3146
                        File mime type
3147
 
3148
                        @property type
3149
                        @type {String}
3150
                        @default ''
3151
                        */
3152
                        type: type || '',
3153
 
3154
                        /**
3155
                        File name
3156
 
3157
                        @property name
3158
                        @type {String}
3159
                        @default UID
3160
                        */
3161
                        name: name || Basic.guid('file_'),
3162
 
3163
                        /**
3164
                        Date of last modification
3165
 
3166
                        @property lastModifiedDate
3167
                        @type {String}
3168
                        @default now
3169
                        */
3170
                        lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)
3171
                });
3172
        }
3173
 
3174
        File.prototype = Blob.prototype;
3175
 
3176
        return File;
3177
});
3178
 
3179
// Included from: src/javascript/file/FileInput.js
3180
 
3181
/**
3182
 * FileInput.js
3183
 *
3184
 * Copyright 2013, Moxiecode Systems AB
3185
 * Released under GPL License.
3186
 *
3187
 * License: http://www.plupload.com/license
3188
 * Contributing: http://www.plupload.com/contributing
3189
 */
3190
 
3191
define('moxie/file/FileInput', [
3192
        'moxie/core/utils/Basic',
3193
        'moxie/core/utils/Mime',
3194
        'moxie/core/utils/Dom',
3195
        'moxie/core/Exceptions',
3196
        'moxie/core/EventTarget',
3197
        'moxie/core/I18n',
3198
        'moxie/file/File',
3199
        'moxie/runtime/Runtime',
3200
        'moxie/runtime/RuntimeClient'
3201
], function(Basic, Mime, Dom, x, EventTarget, I18n, File, Runtime, RuntimeClient) {
3202
        /**
3203
        Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click,
3204
        converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory
3205
        with _FileReader_ or uploaded to a server through _XMLHttpRequest_.
3206
 
3207
        @class FileInput
3208
        @constructor
3209
        @extends EventTarget
3210
        @uses RuntimeClient
3211
        @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_.
3212
                @param {String|DOMElement} options.browse_button DOM Element to turn into file picker.
3213
                @param {Array} [options.accept] Array of mime types to accept. By default accepts all.
3214
                @param {String} [options.file='file'] Name of the file field (not the filename).
3215
                @param {Boolean} [options.multiple=false] Enable selection of multiple files.
3216
                @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time).
3217
                @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode
3218
                for _browse\_button_.
3219
                @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support.
3220
 
3221
        @example
3222
                <div id="container">
3223
                        <a id="file-picker" href="javascript:;">Browse...</a>
3224
                </div>
3225
 
3226
                <script>
3227
                        var fileInput = new mOxie.FileInput({
3228
                                browse_button: 'file-picker', // or document.getElementById('file-picker')
3229
                                container: 'container',
3230
                                accept: [
3231
                                        {title: "Image files", extensions: "jpg,gif,png"} // accept only images
3232
                                ],
3233
                                multiple: true // allow multiple file selection
3234
                        });
3235
 
3236
                        fileInput.onchange = function(e) {
3237
                                // do something to files array
3238
                                console.info(e.target.files); // or this.files or fileInput.files
3239
                        };
3240
 
3241
                        fileInput.init(); // initialize
3242
                </script>
3243
        */
3244
        var dispatches = [
3245
                /**
3246
                Dispatched when runtime is connected and file-picker is ready to be used.
3247
 
3248
                @event ready
3249
                @param {Object} event
3250
                */
3251
                'ready',
3252
 
3253
                /**
3254
                Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked.
3255
                Check [corresponding documentation entry](#method_refresh) for more info.
3256
 
3257
                @event refresh
3258
                @param {Object} event
3259
                */
3260
 
3261
                /**
3262
                Dispatched when selection of files in the dialog is complete.
3263
 
3264
                @event change
3265
                @param {Object} event
3266
                */
3267
                'change',
3268
 
3269
                'cancel', // TODO: might be useful
3270
 
3271
                /**
3272
                Dispatched when mouse cursor enters file-picker area. Can be used to style element
3273
                accordingly.
3274
 
3275
                @event mouseenter
3276
                @param {Object} event
3277
                */
3278
                'mouseenter',
3279
 
3280
                /**
3281
                Dispatched when mouse cursor leaves file-picker area. Can be used to style element
3282
                accordingly.
3283
 
3284
                @event mouseleave
3285
                @param {Object} event
3286
                */
3287
                'mouseleave',
3288
 
3289
                /**
3290
                Dispatched when functional mouse button is pressed on top of file-picker area.
3291
 
3292
                @event mousedown
3293
                @param {Object} event
3294
                */
3295
                'mousedown',
3296
 
3297
                /**
3298
                Dispatched when functional mouse button is released on top of file-picker area.
3299
 
3300
                @event mouseup
3301
                @param {Object} event
3302
                */
3303
                'mouseup'
3304
        ];
3305
 
3306
        function FileInput(options) {
3307
                var self = this,
3308
                        container, browseButton, defaults;
3309
 
3310
                // if flat argument passed it should be browse_button id
3311
                if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) {
3312
                        options = { browse_button : options };
3313
                }
3314
 
3315
                // this will help us to find proper default container
3316
                browseButton = Dom.get(options.browse_button);
3317
                if (!browseButton) {
3318
                        // browse button is required
3319
                        throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
3320
                }
3321
 
3322
                // figure out the options
3323
                defaults = {
3324
                        accept: [{
3325
                                title: I18n.translate('All Files'),
3326
                                extensions: '*'
3327
                        }],
3328
                        name: 'file',
3329
                        multiple: false,
3330
                        required_caps: false,
3331
                        container: browseButton.parentNode || document.body
3332
                };
3333
 
3334
                options = Basic.extend({}, defaults, options);
3335
 
3336
                // convert to object representation
3337
                if (typeof(options.required_caps) === 'string') {
3338
                        options.required_caps = Runtime.parseCaps(options.required_caps);
3339
                }
3340
 
3341
                // normalize accept option (could be list of mime types or array of title/extensions pairs)
3342
                if (typeof(options.accept) === 'string') {
3343
                        options.accept = Mime.mimes2extList(options.accept);
3344
                }
3345
 
3346
                container = Dom.get(options.container);
3347
                // make sure we have container
3348
                if (!container) {
3349
                        container = document.body;
3350
                }
3351
 
3352
                // make container relative, if it's not
3353
                if (Dom.getStyle(container, 'position') === 'static') {
3354
                        container.style.position = 'relative';
3355
                }
3356
 
3357
                container = browseButton = null; // IE
3358
 
3359
                RuntimeClient.call(self);
3360
 
3361
                Basic.extend(self, {
3362
                        /**
3363
                        Unique id of the component
3364
 
3365
                        @property uid
3366
                        @protected
3367
                        @readOnly
3368
                        @type {String}
3369
                        @default UID
3370
                        */
3371
                        uid: Basic.guid('uid_'),
3372
 
3373
                        /**
3374
                        Unique id of the connected runtime, if any.
3375
 
3376
                        @property ruid
3377
                        @protected
3378
                        @type {String}
3379
                        */
3380
                        ruid: null,
3381
 
3382
                        /**
3383
                        Unique id of the runtime container. Useful to get hold of it for various manipulations.
3384
 
3385
                        @property shimid
3386
                        @protected
3387
                        @type {String}
3388
                        */
3389
                        shimid: null,
3390
 
3391
                        /**
3392
                        Array of selected mOxie.File objects
3393
 
3394
                        @property files
3395
                        @type {Array}
3396
                        @default null
3397
                        */
3398
                        files: null,
3399
 
3400
                        /**
3401
                        Initializes the file-picker, connects it to runtime and dispatches event ready when done.
3402
 
3403
                        @method init
3404
                        */
3405
                        init: function() {
3406
                                self.convertEventPropsToHandlers(dispatches);
3407
 
3408
                                self.bind('RuntimeInit', function(e, runtime) {
3409
                                        self.ruid = runtime.uid;
3410
                                        self.shimid = runtime.shimid;
3411
 
3412
                                        self.bind("Ready", function() {
3413
                                                self.trigger("Refresh");
3414
                                        }, 999);
3415
 
3416
                                        self.bind("Change", function() {
3417
                                                var files = runtime.exec.call(self, 'FileInput', 'getFiles');
3418
 
3419
                                                self.files = [];
3420
 
3421
                                                Basic.each(files, function(file) {
3422
                                                        // ignore empty files (IE10 for example hangs if you try to send them via XHR)
3423
                                                        if (file.size === 0) {
3424
                                                                return true;
3425
                                                        }
3426
                                                        self.files.push(new File(self.ruid, file));
3427
                                                });
3428
                                        }, 999);
3429
 
3430
                                        // re-position and resize shim container
3431
                                        self.bind('Refresh', function() {
3432
                                                var pos, size, browseButton, shimContainer;
3433
 
3434
                                                browseButton = Dom.get(options.browse_button);
3435
                                                shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist
3436
 
3437
                                                if (browseButton) {
3438
                                                        pos = Dom.getPos(browseButton, Dom.get(options.container));
3439
                                                        size = Dom.getSize(browseButton);
3440
 
3441
                                                        if (shimContainer) {
3442
                                                                Basic.extend(shimContainer.style, {
3443
                                                                        top     : pos.y + 'px',
3444
                                                                        left    : pos.x + 'px',
3445
                                                                        width   : size.w + 'px',
3446
                                                                        height  : size.h + 'px'
3447
                                                                });
3448
                                                        }
3449
                                                }
3450
                                                shimContainer = browseButton = null;
3451
                                        });
3452
 
3453
                                        runtime.exec.call(self, 'FileInput', 'init', options);
3454
                                });
3455
 
3456
                                // runtime needs: options.required_features, options.runtime_order and options.container
3457
                                self.connectRuntime(Basic.extend({}, options, {
3458
                                        required_caps: {
3459
                                                select_file: true
3460
                                        }
3461
                                }));
3462
                        },
3463
 
3464
                        /**
3465
                        Disables file-picker element, so that it doesn't react to mouse clicks.
3466
 
3467
                        @method disable
3468
                        @param {Boolean} [state=true] Disable component if - true, enable if - false
3469
                        */
3470
                        disable: function(state) {
3471
                                var runtime = this.getRuntime();
3472
                                if (runtime) {
3473
                                        runtime.exec.call(this, 'FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state);
3474
                                }
3475
                        },
3476
 
3477
 
3478
                        /**
3479
                        Reposition and resize dialog trigger to match the position and size of browse_button element.
3480
 
3481
                        @method refresh
3482
                        */
3483
                        refresh: function() {
3484
                                self.trigger("Refresh");
3485
                        },
3486
 
3487
 
3488
                        /**
3489
                        Destroy component.
3490
 
3491
                        @method destroy
3492
                        */
3493
                        destroy: function() {
3494
                                var runtime = this.getRuntime();
3495
                                if (runtime) {
3496
                                        runtime.exec.call(this, 'FileInput', 'destroy');
3497
                                        this.disconnectRuntime();
3498
                                }
3499
 
3500
                                if (Basic.typeOf(this.files) === 'array') {
3501
                                        // no sense in leaving associated files behind
3502
                                        Basic.each(this.files, function(file) {
3503
                                                file.destroy();
3504
                                        });
3505
                                }
3506
                                this.files = null;
3507
                        }
3508
                });
3509
        }
3510
 
3511
        FileInput.prototype = EventTarget.instance;
3512
 
3513
        return FileInput;
3514
});
3515
 
3516
// Included from: src/javascript/file/FileDrop.js
3517
 
3518
/**
3519
 * FileDrop.js
3520
 *
3521
 * Copyright 2013, Moxiecode Systems AB
3522
 * Released under GPL License.
3523
 *
3524
 * License: http://www.plupload.com/license
3525
 * Contributing: http://www.plupload.com/contributing
3526
 */
3527
 
3528
define('moxie/file/FileDrop', [
3529
        'moxie/core/I18n',
3530
        'moxie/core/utils/Dom',
3531
        'moxie/core/Exceptions',
3532
        'moxie/core/utils/Basic',
3533
        'moxie/file/File',
3534
        'moxie/runtime/RuntimeClient',
3535
        'moxie/core/EventTarget',
3536
        'moxie/core/utils/Mime'
3537
], function(I18n, Dom, x, Basic, File, RuntimeClient, EventTarget, Mime) {
3538
        /**
3539
        Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used
3540
        in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through
3541
        _XMLHttpRequest_.
3542
 
3543
        @example
3544
                <div id="drop_zone">
3545
                        Drop files here
3546
                </div>
3547
                <br />
3548
                <div id="filelist"></div>
3549
 
3550
                <script type="text/javascript">
3551
                        var fileDrop = new mOxie.FileDrop('drop_zone'), fileList = mOxie.get('filelist');
3552
 
3553
                        fileDrop.ondrop = function() {
3554
                                mOxie.each(this.files, function(file) {
3555
                                        fileList.innerHTML += '<div>' + file.name + '</div>';
3556
                                });
3557
                        };
3558
 
3559
                        fileDrop.init();
3560
                </script>
3561
 
3562
        @class FileDrop
3563
        @constructor
3564
        @extends EventTarget
3565
        @uses RuntimeClient
3566
        @param {Object|String} options If options has typeof string, argument is considered as options.drop_zone
3567
                @param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone
3568
                @param {Array} [options.accept] Array of mime types to accept. By default accepts all
3569
                @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support
3570
        */
3571
        var dispatches = [
3572
                /**
3573
                Dispatched when runtime is connected and drop zone is ready to accept files.
3574
 
3575
                @event ready
3576
                @param {Object} event
3577
                */
3578
                'ready',
3579
 
3580
                /**
3581
                Dispatched when dragging cursor enters the drop zone.
3582
 
3583
                @event dragenter
3584
                @param {Object} event
3585
                */
3586
                'dragenter',
3587
 
3588
                /**
3589
                Dispatched when dragging cursor leaves the drop zone.
3590
 
3591
                @event dragleave
3592
                @param {Object} event
3593
                */
3594
                'dragleave',
3595
 
3596
                /**
3597
                Dispatched when file is dropped onto the drop zone.
3598
 
3599
                @event drop
3600
                @param {Object} event
3601
                */
3602
                'drop',
3603
 
3604
                /**
3605
                Dispatched if error occurs.
3606
 
3607
                @event error
3608
                @param {Object} event
3609
                */
3610
                'error'
3611
        ];
3612
 
3613
        function FileDrop(options) {
3614
                var self = this, defaults;
3615
 
3616
                // if flat argument passed it should be drop_zone id
3617
                if (typeof(options) === 'string') {
3618
                        options = { drop_zone : options };
3619
                }
3620
 
3621
                // figure out the options
3622
                defaults = {
3623
                        accept: [{
3624
                                title: I18n.translate('All Files'),
3625
                                extensions: '*'
3626
                        }],
3627
                        required_caps: {
3628
                                drag_and_drop: true
3629
                        }
3630
                };
3631
 
3632
                options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults;
3633
 
3634
                // this will help us to find proper default container
3635
                options.container = Dom.get(options.drop_zone) || document.body;
3636
 
3637
                // make container relative, if it is not
3638
                if (Dom.getStyle(options.container, 'position') === 'static') {
3639
                        options.container.style.position = 'relative';
3640
                }
3641
 
3642
                // normalize accept option (could be list of mime types or array of title/extensions pairs)
3643
                if (typeof(options.accept) === 'string') {
3644
                        options.accept = Mime.mimes2extList(options.accept);
3645
                }
3646
 
3647
                RuntimeClient.call(self);
3648
 
3649
                Basic.extend(self, {
3650
                        uid: Basic.guid('uid_'),
3651
 
3652
                        ruid: null,
3653
 
3654
                        files: null,
3655
 
3656
                        init: function() {
3657
 
3658
                                self.convertEventPropsToHandlers(dispatches);
3659
 
3660
                                self.bind('RuntimeInit', function(e, runtime) {
3661
                                        self.ruid = runtime.uid;
3662
 
3663
                                        self.bind("Drop", function() {
3664
                                                var files = runtime.exec.call(self, 'FileDrop', 'getFiles');
3665
 
3666
                                                self.files = [];
3667
 
3668
                                                Basic.each(files, function(file) {
3669
                                                        self.files.push(new File(self.ruid, file));
3670
                                                });
3671
                                        }, 999);
3672
 
3673
                                        runtime.exec.call(self, 'FileDrop', 'init', options);
3674
 
3675
                                        self.dispatchEvent('ready');
3676
                                });
3677
 
3678
                                // runtime needs: options.required_features, options.runtime_order and options.container
3679
                                self.connectRuntime(options); // throws RuntimeError
3680
                        },
3681
 
3682
                        destroy: function() {
3683
                                var runtime = this.getRuntime();
3684
                                if (runtime) {
3685
                                        runtime.exec.call(this, 'FileDrop', 'destroy');
3686
                                        this.disconnectRuntime();
3687
                                }
3688
                                this.files = null;
3689
                        }
3690
                });
3691
        }
3692
 
3693
        FileDrop.prototype = EventTarget.instance;
3694
 
3695
        return FileDrop;
3696
});
3697
 
3698
// Included from: src/javascript/runtime/RuntimeTarget.js
3699
 
3700
/**
3701
 * RuntimeTarget.js
3702
 *
3703
 * Copyright 2013, Moxiecode Systems AB
3704
 * Released under GPL License.
3705
 *
3706
 * License: http://www.plupload.com/license
3707
 * Contributing: http://www.plupload.com/contributing
3708
 */
3709
 
3710
define('moxie/runtime/RuntimeTarget', [
3711
        'moxie/core/utils/Basic',
3712
        'moxie/runtime/RuntimeClient',
3713
        "moxie/core/EventTarget"
3714
], function(Basic, RuntimeClient, EventTarget) {
3715
        /**
3716
        Instance of this class can be used as a target for the events dispatched by shims,
3717
        when allowing them onto components is for either reason inappropriate
3718
 
3719
        @class RuntimeTarget
3720
        @constructor
3721
        @protected
3722
        @extends EventTarget
3723
        */
3724
        function RuntimeTarget() {
3725
                this.uid = Basic.guid('uid_');
3726
 
3727
                RuntimeClient.call(this);
3728
 
3729
                this.destroy = function() {
3730
                        this.disconnectRuntime();
3731
                        this.unbindAll();
3732
                };
3733
        }
3734
 
3735
        RuntimeTarget.prototype = EventTarget.instance;
3736
 
3737
        return RuntimeTarget;
3738
});
3739
 
3740
// Included from: src/javascript/file/FileReader.js
3741
 
3742
/**
3743
 * FileReader.js
3744
 *
3745
 * Copyright 2013, Moxiecode Systems AB
3746
 * Released under GPL License.
3747
 *
3748
 * License: http://www.plupload.com/license
3749
 * Contributing: http://www.plupload.com/contributing
3750
 */
3751
 
3752
define('moxie/file/FileReader', [
3753
        'moxie/core/utils/Basic',
3754
        'moxie/core/utils/Encode',
3755
        'moxie/core/Exceptions',
3756
        'moxie/core/EventTarget',
3757
        'moxie/file/Blob',
3758
        'moxie/file/File',
3759
        'moxie/runtime/RuntimeTarget'
3760
], function(Basic, Encode, x, EventTarget, Blob, File, RuntimeTarget) {
3761
        /**
3762
        Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader)
3763
        interface. Where possible uses native FileReader, where - not falls back to shims.
3764
 
3765
        @class FileReader
3766
        @constructor FileReader
3767
        @extends EventTarget
3768
        @uses RuntimeClient
3769
        */
3770
        var dispatches = [
3771
 
3772
                /**
3773
                Dispatched when the read starts.
3774
 
3775
                @event loadstart
3776
                @param {Object} event
3777
                */
3778
                'loadstart',
3779
 
3780
                /**
3781
                Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total).
3782
 
3783
                @event progress
3784
                @param {Object} event
3785
                */
3786
                'progress',
3787
 
3788
                /**
3789
                Dispatched when the read has successfully completed.
3790
 
3791
                @event load
3792
                @param {Object} event
3793
                */
3794
                'load',
3795
 
3796
                /**
3797
                Dispatched when the read has been aborted. For instance, by invoking the abort() method.
3798
 
3799
                @event abort
3800
                @param {Object} event
3801
                */
3802
                'abort',
3803
 
3804
                /**
3805
                Dispatched when the read has failed.
3806
 
3807
                @event error
3808
                @param {Object} event
3809
                */
3810
                'error',
3811
 
3812
                /**
3813
                Dispatched when the request has completed (either in success or failure).
3814
 
3815
                @event loadend
3816
                @param {Object} event
3817
                */
3818
                'loadend'
3819
        ];
3820
 
3821
        function FileReader() {
3822
                var self = this, _fr;
3823
 
3824
                Basic.extend(this, {
3825
                        /**
3826
                        UID of the component instance.
3827
 
3828
                        @property uid
3829
                        @type {String}
3830
                        */
3831
                        uid: Basic.guid('uid_'),
3832
 
3833
                        /**
3834
                        Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING
3835
                        and FileReader.DONE.
3836
 
3837
                        @property readyState
3838
                        @type {Number}
3839
                        @default FileReader.EMPTY
3840
                        */
3841
                        readyState: FileReader.EMPTY,
3842
 
3843
                        /**
3844
                        Result of the successful read operation.
3845
 
3846
                        @property result
3847
                        @type {String}
3848
                        */
3849
                        result: null,
3850
 
3851
                        /**
3852
                        Stores the error of failed asynchronous read operation.
3853
 
3854
                        @property error
3855
                        @type {DOMError}
3856
                        */
3857
                        error: null,
3858
 
3859
                        /**
3860
                        Initiates reading of File/Blob object contents to binary string.
3861
 
3862
                        @method readAsBinaryString
3863
                        @param {Blob|File} blob Object to preload
3864
                        */
3865
                        readAsBinaryString: function(blob) {
3866
                                _read.call(this, 'readAsBinaryString', blob);
3867
                        },
3868
 
3869
                        /**
3870
                        Initiates reading of File/Blob object contents to dataURL string.
3871
 
3872
                        @method readAsDataURL
3873
                        @param {Blob|File} blob Object to preload
3874
                        */
3875
                        readAsDataURL: function(blob) {
3876
                                _read.call(this, 'readAsDataURL', blob);
3877
                        },
3878
 
3879
                        /**
3880
                        Initiates reading of File/Blob object contents to string.
3881
 
3882
                        @method readAsText
3883
                        @param {Blob|File} blob Object to preload
3884
                        */
3885
                        readAsText: function(blob) {
3886
                                _read.call(this, 'readAsText', blob);
3887
                        },
3888
 
3889
                        /**
3890
                        Aborts preloading process.
3891
 
3892
                        @method abort
3893
                        */
3894
                        abort: function() {
3895
                                this.result = null;
3896
 
3897
                                if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) {
3898
                                        return;
3899
                                } else if (this.readyState === FileReader.LOADING) {
3900
                                        this.readyState = FileReader.DONE;
3901
                                }
3902
 
3903
                                if (_fr) {
3904
                                        _fr.getRuntime().exec.call(this, 'FileReader', 'abort');
3905
                                }
3906
 
3907
                                this.trigger('abort');
3908
                                this.trigger('loadend');
3909
                        },
3910
 
3911
                        /**
3912
                        Destroy component and release resources.
3913
 
3914
                        @method destroy
3915
                        */
3916
                        destroy: function() {
3917
                                this.abort();
3918
 
3919
                                if (_fr) {
3920
                                        _fr.getRuntime().exec.call(this, 'FileReader', 'destroy');
3921
                                        _fr.disconnectRuntime();
3922
                                }
3923
 
3924
                                self = _fr = null;
3925
                        }
3926
                });
3927
 
3928
 
3929
                function _read(op, blob) {
3930
                        _fr = new RuntimeTarget();
3931
 
3932
                        function error(err) {
3933
                                self.readyState = FileReader.DONE;
3934
                                self.error = err;
3935
                                self.trigger('error');
3936
                                loadEnd();
3937
                        }
3938
 
3939
                        function loadEnd() {
3940
                                _fr.destroy();
3941
                                _fr = null;
3942
                                self.trigger('loadend');
3943
                        }
3944
 
3945
                        function exec(runtime) {
3946
                                _fr.bind('Error', function(e, err) {
3947
                                        error(err);
3948
                                });
3949
 
3950
                                _fr.bind('Progress', function(e) {
3951
                                        self.result = runtime.exec.call(_fr, 'FileReader', 'getResult');
3952
                                        self.trigger(e);
3953
                                });
3954
 
3955
                                _fr.bind('Load', function(e) {
3956
                                        self.readyState = FileReader.DONE;
3957
                                        self.result = runtime.exec.call(_fr, 'FileReader', 'getResult');
3958
                                        self.trigger(e);
3959
                                        loadEnd();
3960
                                });
3961
 
3962
                                runtime.exec.call(_fr, 'FileReader', 'read', op, blob);
3963
                        }
3964
 
3965
                        this.convertEventPropsToHandlers(dispatches);
3966
 
3967
                        if (this.readyState === FileReader.LOADING) {
3968
                                return error(new x.DOMException(x.DOMException.INVALID_STATE_ERR));
3969
                        }
3970
 
3971
                        this.readyState = FileReader.LOADING;
3972
                        this.trigger('loadstart');
3973
 
3974
                        // if source is o.Blob/o.File
3975
                        if (blob instanceof Blob) {
3976
                                if (blob.isDetached()) {
3977
                                        var src = blob.getSource();
3978
                                        switch (op) {
3979
                                                case 'readAsText':
3980
                                                case 'readAsBinaryString':
3981
                                                        this.result = src;
3982
                                                        break;
3983
                                                case 'readAsDataURL':
3984
                                                        this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src);
3985
                                                        break;
3986
                                        }
3987
                                        this.readyState = FileReader.DONE;
3988
                                        this.trigger('load');
3989
                                        loadEnd();
3990
                                } else {
3991
                                        exec(_fr.connectRuntime(blob.ruid));
3992
                                }
3993
                        } else {
3994
                                error(new x.DOMException(x.DOMException.NOT_FOUND_ERR));
3995
                        }
3996
                }
3997
        }
3998
 
3999
        /**
4000
        Initial FileReader state
4001
 
4002
        @property EMPTY
4003
        @type {Number}
4004
        @final
4005
        @static
4006
        @default 0
4007
        */
4008
        FileReader.EMPTY = 0;
4009
 
4010
        /**
4011
        FileReader switches to this state when it is preloading the source
4012
 
4013
        @property LOADING
4014
        @type {Number}
4015
        @final
4016
        @static
4017
        @default 1
4018
        */
4019
        FileReader.LOADING = 1;
4020
 
4021
        /**
4022
        Preloading is complete, this is a final state
4023
 
4024
        @property DONE
4025
        @type {Number}
4026
        @final
4027
        @static
4028
        @default 2
4029
        */
4030
        FileReader.DONE = 2;
4031
 
4032
        FileReader.prototype = EventTarget.instance;
4033
 
4034
        return FileReader;
4035
});
4036
 
4037
// Included from: src/javascript/core/utils/Url.js
4038
 
4039
/**
4040
 * Url.js
4041
 *
4042
 * Copyright 2013, Moxiecode Systems AB
4043
 * Released under GPL License.
4044
 *
4045
 * License: http://www.plupload.com/license
4046
 * Contributing: http://www.plupload.com/contributing
4047
 */
4048
 
4049
define('moxie/core/utils/Url', [], function() {
4050
        /**
4051
        Parse url into separate components and fill in absent parts with parts from current url,
4052
        based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js
4053
 
4054
        @method parseUrl
4055
        @for Utils
4056
        @static
4057
        @param {String} url Url to parse (defaults to empty string if undefined)
4058
        @return {Object} Hash containing extracted uri components
4059
        */
4060
        var parseUrl = function(url, currentUrl) {
4061
                var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment']
4062
                , i = key.length
4063
                , ports = {
4064
                        http: 80,
4065
                        https: 443
4066
                }
4067
                , uri = {}
4068
                , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/
4069
                , m = regex.exec(url || '')
4070
                ;
4071
 
4072
                while (i--) {
4073
                        if (m[i]) {
4074
                                uri[key[i]] = m[i];
4075
                        }
4076
                }
4077
 
4078
                // when url is relative, we set the origin and the path ourselves
4079
                if (!uri.scheme) {
4080
                        // come up with defaults
4081
                        if (!currentUrl || typeof(currentUrl) === 'string') {
4082
                                currentUrl = parseUrl(currentUrl || document.location.href);
4083
                        }
4084
 
4085
                        uri.scheme = currentUrl.scheme;
4086
                        uri.host = currentUrl.host;
4087
                        uri.port = currentUrl.port;
4088
 
4089
                        var path = '';
4090
                        // for urls without trailing slash we need to figure out the path
4091
                        if (/^[^\/]/.test(uri.path)) {
4092
                                path = currentUrl.path;
4093
                                // if path ends with a filename, strip it
4094
                                if (!/(\/|\/[^\.]+)$/.test(path)) {
4095
                                        path = path.replace(/\/[^\/]+$/, '/');
4096
                                } else {
4097
                                        path += '/';
4098
                                }
4099
                        }
4100
                        uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir
4101
                }
4102
 
4103
                if (!uri.port) {
4104
                        uri.port = ports[uri.scheme] || 80;
4105
                }
4106
 
4107
                uri.port = parseInt(uri.port, 10);
4108
 
4109
                if (!uri.path) {
4110
                        uri.path = "/";
4111
                }
4112
 
4113
                delete uri.source;
4114
 
4115
                return uri;
4116
        };
4117
 
4118
        /**
4119
        Resolve url - among other things will turn relative url to absolute
4120
 
4121
        @method resolveUrl
4122
        @static
4123
        @param {String} url Either absolute or relative
4124
        @return {String} Resolved, absolute url
4125
        */
4126
        var resolveUrl = function(url) {
4127
                var ports = { // we ignore default ports
4128
                        http: 80,
4129
                        https: 443
4130
                }
4131
                , urlp = parseUrl(url)
4132
                ;
4133
 
4134
                return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : '');
4135
        };
4136
 
4137
        /**
4138
        Check if specified url has the same origin as the current document
4139
 
4140
        @method hasSameOrigin
4141
        @param {String|Object} url
4142
        @return {Boolean}
4143
        */
4144
        var hasSameOrigin = function(url) {
4145
                function origin(url) {
4146
                        return [url.scheme, url.host, url.port].join('/');
4147
                }
4148
 
4149
                if (typeof url === 'string') {
4150
                        url = parseUrl(url);
4151
                }      
4152
 
4153
                return origin(parseUrl()) === origin(url);
4154
        };
4155
 
4156
        return {
4157
                parseUrl: parseUrl,
4158
                resolveUrl: resolveUrl,
4159
                hasSameOrigin: hasSameOrigin
4160
        };
4161
});
4162
 
4163
// Included from: src/javascript/file/FileReaderSync.js
4164
 
4165
/**
4166
 * FileReaderSync.js
4167
 *
4168
 * Copyright 2013, Moxiecode Systems AB
4169
 * Released under GPL License.
4170
 *
4171
 * License: http://www.plupload.com/license
4172
 * Contributing: http://www.plupload.com/contributing
4173
 */
4174
 
4175
define('moxie/file/FileReaderSync', [
4176
        'moxie/core/utils/Basic',
4177
        'moxie/runtime/RuntimeClient',
4178
        'moxie/core/utils/Encode'
4179
], function(Basic, RuntimeClient, Encode) {
4180
        /**
4181
        Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here
4182
        it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be,
4183
        but probably < 1mb). Not meant to be used directly by user.
4184
 
4185
        @class FileReaderSync
4186
        @private
4187
        @constructor
4188
        */
4189
        return function() {
4190
                RuntimeClient.call(this);
4191
 
4192
                Basic.extend(this, {
4193
                        uid: Basic.guid('uid_'),
4194
 
4195
                        readAsBinaryString: function(blob) {
4196
                                return _read.call(this, 'readAsBinaryString', blob);
4197
                        },
4198
 
4199
                        readAsDataURL: function(blob) {
4200
                                return _read.call(this, 'readAsDataURL', blob);
4201
                        },
4202
 
4203
                        /*readAsArrayBuffer: function(blob) {
4204
                                return _read.call(this, 'readAsArrayBuffer', blob);
4205
                        },*/
4206
 
4207
                        readAsText: function(blob) {
4208
                                return _read.call(this, 'readAsText', blob);
4209
                        }
4210
                });
4211
 
4212
                function _read(op, blob) {
4213
                        if (blob.isDetached()) {
4214
                                var src = blob.getSource();
4215
                                switch (op) {
4216
                                        case 'readAsBinaryString':
4217
                                                return src;
4218
                                        case 'readAsDataURL':
4219
                                                return 'data:' + blob.type + ';base64,' + Encode.btoa(src);
4220
                                        case 'readAsText':
4221
                                                var txt = '';
4222
                                                for (var i = 0, length = src.length; i < length; i++) {
4223
                                                        txt += String.fromCharCode(src[i]);
4224
                                                }
4225
                                                return txt;
4226
                                }
4227
                        } else {
4228
                                var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob);
4229
                                this.disconnectRuntime();
4230
                                return result;
4231
                        }
4232
                }
4233
        };
4234
});
4235
 
4236
// Included from: src/javascript/xhr/FormData.js
4237
 
4238
/**
4239
 * FormData.js
4240
 *
4241
 * Copyright 2013, Moxiecode Systems AB
4242
 * Released under GPL License.
4243
 *
4244
 * License: http://www.plupload.com/license
4245
 * Contributing: http://www.plupload.com/contributing
4246
 */
4247
 
4248
define("moxie/xhr/FormData", [
4249
        "moxie/core/Exceptions",
4250
        "moxie/core/utils/Basic",
4251
        "moxie/file/Blob"
4252
], function(x, Basic, Blob) {
4253
        /**
4254
        FormData
4255
 
4256
        @class FormData
4257
        @constructor
4258
        */
4259
        function FormData() {
4260
                var _blob, _fields = [];
4261
 
4262
                Basic.extend(this, {
4263
                        /**
4264
                        Append another key-value pair to the FormData object
4265
 
4266
                        @method append
4267
                        @param {String} name Name for the new field
4268
                        @param {String|Blob|Array|Object} value Value for the field
4269
                        */
4270
                        append: function(name, value) {
4271
                                var self = this, valueType = Basic.typeOf(value);
4272
 
4273
                                // according to specs value might be either Blob or String
4274
                                if (value instanceof Blob) {
4275
                                        _blob = {
4276
                                                name: name,
4277
                                                value: value // unfortunately we can only send single Blob in one FormData
4278
                                        };
4279
                                } else if ('array' === valueType) {
4280
                                        name += '[]';
4281
 
4282
                                        Basic.each(value, function(value) {
4283
                                                self.append(name, value);
4284
                                        });
4285
                                } else if ('object' === valueType) {
4286
                                        Basic.each(value, function(value, key) {
4287
                                                self.append(name + '[' + key + ']', value);
4288
                                        });
4289
                                } else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) {
4290
                                        self.append(name, "false");
4291
                                } else {
4292
                                        _fields.push({
4293
                                                name: name,
4294
                                                value: value.toString()
4295
                                        });
4296
                                }
4297
                        },
4298
 
4299
                        /**
4300
                        Checks if FormData contains Blob.
4301
 
4302
                        @method hasBlob
4303
                        @return {Boolean}
4304
                        */
4305
                        hasBlob: function() {
4306
                                return !!this.getBlob();
4307
                        },
4308
 
4309
                        /**
4310
                        Retrieves blob.
4311
 
4312
                        @method getBlob
4313
                        @return {Object} Either Blob if found or null
4314
                        */
4315
                        getBlob: function() {
4316
                                return _blob && _blob.value || null;
4317
                        },
4318
 
4319
                        /**
4320
                        Retrieves blob field name.
4321
 
4322
                        @method getBlobName
4323
                        @return {String} Either Blob field name or null
4324
                        */
4325
                        getBlobName: function() {
4326
                                return _blob && _blob.name || null;
4327
                        },
4328
 
4329
                        /**
4330
                        Loop over the fields in FormData and invoke the callback for each of them.
4331
 
4332
                        @method each
4333
                        @param {Function} cb Callback to call for each field
4334
                        */
4335
                        each: function(cb) {
4336
                                Basic.each(_fields, function(field) {
4337
                                        cb(field.value, field.name);
4338
                                });
4339
 
4340
                                if (_blob) {
4341
                                        cb(_blob.value, _blob.name);
4342
                                }
4343
                        },
4344
 
4345
                        destroy: function() {
4346
                                _blob = null;
4347
                                _fields = [];
4348
                        }
4349
                });
4350
        }
4351
 
4352
        return FormData;
4353
});
4354
 
4355
// Included from: src/javascript/xhr/XMLHttpRequest.js
4356
 
4357
/**
4358
 * XMLHttpRequest.js
4359
 *
4360
 * Copyright 2013, Moxiecode Systems AB
4361
 * Released under GPL License.
4362
 *
4363
 * License: http://www.plupload.com/license
4364
 * Contributing: http://www.plupload.com/contributing
4365
 */
4366
 
4367
define("moxie/xhr/XMLHttpRequest", [
4368
        "moxie/core/utils/Basic",
4369
        "moxie/core/Exceptions",
4370
        "moxie/core/EventTarget",
4371
        "moxie/core/utils/Encode",
4372
        "moxie/core/utils/Url",
4373
        "moxie/runtime/Runtime",
4374
        "moxie/runtime/RuntimeTarget",
4375
        "moxie/file/Blob",
4376
        "moxie/file/FileReaderSync",
4377
        "moxie/xhr/FormData",
4378
        "moxie/core/utils/Env",
4379
        "moxie/core/utils/Mime"
4380
], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) {
4381
 
4382
        var httpCode = {
4383
                100: 'Continue',
4384
                101: 'Switching Protocols',
4385
                102: 'Processing',
4386
 
4387
                200: 'OK',
4388
                201: 'Created',
4389
                202: 'Accepted',
4390
                203: 'Non-Authoritative Information',
4391
                204: 'No Content',
4392
                205: 'Reset Content',
4393
                206: 'Partial Content',
4394
                207: 'Multi-Status',
4395
                226: 'IM Used',
4396
 
4397
                300: 'Multiple Choices',
4398
                301: 'Moved Permanently',
4399
                302: 'Found',
4400
                303: 'See Other',
4401
                304: 'Not Modified',
4402
                305: 'Use Proxy',
4403
                306: 'Reserved',
4404
                307: 'Temporary Redirect',
4405
 
4406
                400: 'Bad Request',
4407
                401: 'Unauthorized',
4408
                402: 'Payment Required',
4409
                403: 'Forbidden',
4410
                404: 'Not Found',
4411
                405: 'Method Not Allowed',
4412
                406: 'Not Acceptable',
4413
                407: 'Proxy Authentication Required',
4414
                408: 'Request Timeout',
4415
                409: 'Conflict',
4416
                410: 'Gone',
4417
                411: 'Length Required',
4418
                412: 'Precondition Failed',
4419
                413: 'Request Entity Too Large',
4420
                414: 'Request-URI Too Long',
4421
                415: 'Unsupported Media Type',
4422
                416: 'Requested Range Not Satisfiable',
4423
                417: 'Expectation Failed',
4424
                422: 'Unprocessable Entity',
4425
                423: 'Locked',
4426
                424: 'Failed Dependency',
4427
                426: 'Upgrade Required',
4428
 
4429
                500: 'Internal Server Error',
4430
                501: 'Not Implemented',
4431
                502: 'Bad Gateway',
4432
                503: 'Service Unavailable',
4433
                504: 'Gateway Timeout',
4434
                505: 'HTTP Version Not Supported',
4435
                506: 'Variant Also Negotiates',
4436
                507: 'Insufficient Storage',
4437
                510: 'Not Extended'
4438
        };
4439
 
4440
        function XMLHttpRequestUpload() {
4441
                this.uid = Basic.guid('uid_');
4442
        }
4443
 
4444
        XMLHttpRequestUpload.prototype = EventTarget.instance;
4445
 
4446
        /**
4447
        Implementation of XMLHttpRequest
4448
 
4449
        @class XMLHttpRequest
4450
        @constructor
4451
        @uses RuntimeClient
4452
        @extends EventTarget
4453
        */
4454
        var dispatches = ['loadstart', 'progress', 'abort', 'error', 'load', 'timeout', 'loadend']; // & readystatechange (for historical reasons)
4455
 
4456
        var NATIVE = 1, RUNTIME = 2;
4457
 
4458
        function XMLHttpRequest() {
4459
                var self = this,
4460
                        // this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible
4461
                        props = {
4462
                                /**
4463
                                The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout.
4464
 
4465
                                @property timeout
4466
                                @type Number
4467
                                @default 0
4468
                                */
4469
                                timeout: 0,
4470
 
4471
                                /**
4472
                                Current state, can take following values:
4473
                                UNSENT (numeric value 0)
4474
                                The object has been constructed.
4475
 
4476
                                OPENED (numeric value 1)
4477
                                The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method.
4478
 
4479
                                HEADERS_RECEIVED (numeric value 2)
4480
                                All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available.
4481
 
4482
                                LOADING (numeric value 3)
4483
                                The response entity body is being received.
4484
 
4485
                                DONE (numeric value 4)
4486
 
4487
                                @property readyState
4488
                                @type Number
4489
                                @default 0 (UNSENT)
4490
                                */
4491
                                readyState: XMLHttpRequest.UNSENT,
4492
 
4493
                                /**
4494
                                True when user credentials are to be included in a cross-origin request. False when they are to be excluded
4495
                                in a cross-origin request and when cookies are to be ignored in its response. Initially false.
4496
 
4497
                                @property withCredentials
4498
                                @type Boolean
4499
                                @default false
4500
                                */
4501
                                withCredentials: false,
4502
 
4503
                                /**
4504
                                Returns the HTTP status code.
4505
 
4506
                                @property status
4507
                                @type Number
4508
                                @default 0
4509
                                */
4510
                                status: 0,
4511
 
4512
                                /**
4513
                                Returns the HTTP status text.
4514
 
4515
                                @property statusText
4516
                                @type String
4517
                                */
4518
                                statusText: "",
4519
 
4520
                                /**
4521
                                Returns the response type. Can be set to change the response type. Values are:
4522
                                the empty string (default), "arraybuffer", "blob", "document", "json", and "text".
4523
 
4524
                                @property responseType
4525
                                @type String
4526
                                */
4527
                                responseType: "",
4528
 
4529
                                /**
4530
                                Returns the document response entity body.
4531
 
4532
                                Throws an "InvalidStateError" exception if responseType is not the empty string or "document".
4533
 
4534
                                @property responseXML
4535
                                @type Document
4536
                                */
4537
                                responseXML: null,
4538
 
4539
                                /**
4540
                                Returns the text response entity body.
4541
 
4542
                                Throws an "InvalidStateError" exception if responseType is not the empty string or "text".
4543
 
4544
                                @property responseText
4545
                                @type String
4546
                                */
4547
                                responseText: null,
4548
 
4549
                                /**
4550
                                Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body).
4551
                                Can become: ArrayBuffer, Blob, Document, JSON, Text
4552
 
4553
                                @property response
4554
                                @type Mixed
4555
                                */
4556
                                response: null
4557
                        },
4558
 
4559
                        _async = true,
4560
                        _url,
4561
                        _method,
4562
                        _headers = {},
4563
                        _user,
4564
                        _password,
4565
                        _encoding = null,
4566
                        _mimeType = null,
4567
 
4568
                        // flags
4569
                        _sync_flag = false,
4570
                        _send_flag = false,
4571
                        _upload_events_flag = false,
4572
                        _upload_complete_flag = false,
4573
                        _error_flag = false,
4574
                        _same_origin_flag = false,
4575
 
4576
                        // times
4577
                        _start_time,
4578
                        _timeoutset_time,
4579
 
4580
                        _finalMime = null,
4581
                        _finalCharset = null,
4582
 
4583
                        _options = {},
4584
                        _xhr,
4585
                        _responseHeaders = '',
4586
                        _responseHeadersBag
4587
                        ;
4588
 
4589
 
4590
                Basic.extend(this, props, {
4591
                        /**
4592
                        Unique id of the component
4593
 
4594
                        @property uid
4595
                        @type String
4596
                        */
4597
                        uid: Basic.guid('uid_'),
4598
 
4599
                        /**
4600
                        Target for Upload events
4601
 
4602
                        @property upload
4603
                        @type XMLHttpRequestUpload
4604
                        */
4605
                        upload: new XMLHttpRequestUpload(),
4606
 
4607
 
4608
                        /**
4609
                        Sets the request method, request URL, synchronous flag, request username, and request password.
4610
 
4611
                        Throws a "SyntaxError" exception if one of the following is true:
4612
 
4613
                        method is not a valid HTTP method.
4614
                        url cannot be resolved.
4615
                        url contains the "user:password" format in the userinfo production.
4616
                        Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK.
4617
 
4618
                        Throws an "InvalidAccessError" exception if one of the following is true:
4619
 
4620
                        Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin.
4621
                        There is an associated XMLHttpRequest document and either the timeout attribute is not zero,
4622
                        the withCredentials attribute is true, or the responseType attribute is not the empty string.
4623
 
4624
 
4625
                        @method open
4626
                        @param {String} method HTTP method to use on request
4627
                        @param {String} url URL to request
4628
                        @param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default.
4629
                        @param {String} [user] Username to use in HTTP authentication process on server-side
4630
                        @param {String} [password] Password to use in HTTP authentication process on server-side
4631
                        */
4632
                        open: function(method, url, async, user, password) {
4633
                                var urlp;
4634
 
4635
                                // first two arguments are required
4636
                                if (!method || !url) {
4637
                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4638
                                }
4639
 
4640
                                // 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method
4641
                                if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) {
4642
                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4643
                                }
4644
 
4645
                                // 3
4646
                                if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) {
4647
                                        _method = method.toUpperCase();
4648
                                }
4649
 
4650
 
4651
                                // 4 - allowing these methods poses a security risk
4652
                                if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) {
4653
                                        throw new x.DOMException(x.DOMException.SECURITY_ERR);
4654
                                }
4655
 
4656
                                // 5
4657
                                url = Encode.utf8_encode(url);
4658
 
4659
                                // 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError".
4660
                                urlp = Url.parseUrl(url);
4661
 
4662
                                _same_origin_flag = Url.hasSameOrigin(urlp);
4663
 
4664
                                // 7 - manually build up absolute url
4665
                                _url = Url.resolveUrl(url);
4666
 
4667
                                // 9-10, 12-13
4668
                                if ((user || password) && !_same_origin_flag) {
4669
                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
4670
                                }
4671
 
4672
                                _user = user || urlp.user;
4673
                                _password = password || urlp.pass;
4674
 
4675
                                // 11
4676
                                _async = async || true;
4677
 
4678
                                if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) {
4679
                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
4680
                                }
4681
 
4682
                                // 14 - terminate abort()
4683
 
4684
                                // 15 - terminate send()
4685
 
4686
                                // 18
4687
                                _sync_flag = !_async;
4688
                                _send_flag = false;
4689
                                _headers = {};
4690
                                _reset.call(this);
4691
 
4692
                                // 19
4693
                                _p('readyState', XMLHttpRequest.OPENED);
4694
 
4695
                                // 20
4696
                                this.convertEventPropsToHandlers(['readystatechange']); // unify event handlers
4697
                                this.dispatchEvent('readystatechange');
4698
                        },
4699
 
4700
                        /**
4701
                        Appends an header to the list of author request headers, or if header is already
4702
                        in the list of author request headers, combines its value with value.
4703
 
4704
                        Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
4705
                        Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value
4706
                        is not a valid HTTP header field value.
4707
 
4708
                        @method setRequestHeader
4709
                        @param {String} header
4710
                        @param {String|Number} value
4711
                        */
4712
                        setRequestHeader: function(header, value) {
4713
                                var uaHeaders = [ // these headers are controlled by the user agent
4714
                                                "accept-charset",
4715
                                                "accept-encoding",
4716
                                                "access-control-request-headers",
4717
                                                "access-control-request-method",
4718
                                                "connection",
4719
                                                "content-length",
4720
                                                "cookie",
4721
                                                "cookie2",
4722
                                                "content-transfer-encoding",
4723
                                                "date",
4724
                                                "expect",
4725
                                                "host",
4726
                                                "keep-alive",
4727
                                                "origin",
4728
                                                "referer",
4729
                                                "te",
4730
                                                "trailer",
4731
                                                "transfer-encoding",
4732
                                                "upgrade",
4733
                                                "user-agent",
4734
                                                "via"
4735
                                        ];
4736
 
4737
                                // 1-2
4738
                                if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) {
4739
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
4740
                                }
4741
 
4742
                                // 3
4743
                                if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) {
4744
                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4745
                                }
4746
 
4747
                                // 4
4748
                                /* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values
4749
                                if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) {
4750
                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4751
                                }*/
4752
 
4753
                                header = Basic.trim(header).toLowerCase();
4754
 
4755
                                // setting of proxy-* and sec-* headers is prohibited by spec
4756
                                if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) {
4757
                                        return false;
4758
                                }
4759
 
4760
                                // camelize
4761
                                // browsers lowercase header names (at least for custom ones)
4762
                                // header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); });
4763
 
4764
                                if (!_headers[header]) {
4765
                                        _headers[header] = value;
4766
                                } else {
4767
                                        // http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph)
4768
                                        _headers[header] += ', ' + value;
4769
                                }
4770
                                return true;
4771
                        },
4772
 
4773
                        /**
4774
                        Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2.
4775
 
4776
                        @method getAllResponseHeaders
4777
                        @return {String} reponse headers or empty string
4778
                        */
4779
                        getAllResponseHeaders: function() {
4780
                                return _responseHeaders || '';
4781
                        },
4782
 
4783
                        /**
4784
                        Returns the header field value from the response of which the field name matches header,
4785
                        unless the field name is Set-Cookie or Set-Cookie2.
4786
 
4787
                        @method getResponseHeader
4788
                        @param {String} header
4789
                        @return {String} value(s) for the specified header or null
4790
                        */
4791
                        getResponseHeader: function(header) {
4792
                                header = header.toLowerCase();
4793
 
4794
                                if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) {
4795
                                        return null;
4796
                                }
4797
 
4798
                                if (_responseHeaders && _responseHeaders !== '') {
4799
                                        // if we didn't parse response headers until now, do it and keep for later
4800
                                        if (!_responseHeadersBag) {
4801
                                                _responseHeadersBag = {};
4802
                                                Basic.each(_responseHeaders.split(/\r\n/), function(line) {
4803
                                                        var pair = line.split(/:\s+/);
4804
                                                        if (pair.length === 2) { // last line might be empty, omit
4805
                                                                pair[0] = Basic.trim(pair[0]); // just in case
4806
                                                                _responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form
4807
                                                                        header: pair[0],
4808
                                                                        value: Basic.trim(pair[1])
4809
                                                                };
4810
                                                        }
4811
                                                });
4812
                                        }
4813
                                        if (_responseHeadersBag.hasOwnProperty(header)) {
4814
                                                return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value;
4815
                                        }
4816
                                }
4817
                                return null;
4818
                        },
4819
 
4820
                        /**
4821
                        Sets the Content-Type header for the response to mime.
4822
                        Throws an "InvalidStateError" exception if the state is LOADING or DONE.
4823
                        Throws a "SyntaxError" exception if mime is not a valid media type.
4824
 
4825
                        @method overrideMimeType
4826
                        @param String mime Mime type to set
4827
                        */
4828
                        overrideMimeType: function(mime) {
4829
                                var matches, charset;
4830
 
4831
                                // 1
4832
                                if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
4833
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
4834
                                }
4835
 
4836
                                // 2
4837
                                mime = Basic.trim(mime.toLowerCase());
4838
 
4839
                                if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) {
4840
                                        mime = matches[1];
4841
                                        if (matches[2]) {
4842
                                                charset = matches[2];
4843
                                        }
4844
                                }
4845
 
4846
                                if (!Mime.mimes[mime]) {
4847
                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
4848
                                }
4849
 
4850
                                // 3-4
4851
                                _finalMime = mime;
4852
                                _finalCharset = charset;
4853
                        },
4854
 
4855
                        /**
4856
                        Initiates the request. The optional argument provides the request entity body.
4857
                        The argument is ignored if request method is GET or HEAD.
4858
 
4859
                        Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
4860
 
4861
                        @method send
4862
                        @param {Blob|Document|String|FormData} [data] Request entity body
4863
                        @param {Object} [options] Set of requirements and pre-requisities for runtime initialization
4864
                        */
4865
                        send: function(data, options) {                                
4866
                                if (Basic.typeOf(options) === 'string') {
4867
                                        _options = { ruid: options };
4868
                                } else if (!options) {
4869
                                        _options = {};
4870
                                } else {
4871
                                        _options = options;
4872
                                }
4873
 
4874
                                this.convertEventPropsToHandlers(dispatches);
4875
                                this.upload.convertEventPropsToHandlers(dispatches);
4876
 
4877
                                // 1-2
4878
                                if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) {
4879
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
4880
                                }
4881
 
4882
                                // 3                                   
4883
                                // sending Blob
4884
                                if (data instanceof Blob) {
4885
                                        _options.ruid = data.ruid;
4886
                                        _mimeType = data.type || 'application/octet-stream';
4887
                                }
4888
 
4889
                                // FormData
4890
                                else if (data instanceof FormData) {
4891
                                        if (data.hasBlob()) {
4892
                                                var blob = data.getBlob();
4893
                                                _options.ruid = blob.ruid;
4894
                                                _mimeType = blob.type || 'application/octet-stream';
4895
                                        }
4896
                                }
4897
 
4898
                                // DOMString
4899
                                else if (typeof data === 'string') {
4900
                                        _encoding = 'UTF-8';
4901
                                        _mimeType = 'text/plain;charset=UTF-8';
4902
 
4903
                                        // data should be converted to Unicode and encoded as UTF-8
4904
                                        data = Encode.utf8_encode(data);
4905
                                }
4906
 
4907
                                // if withCredentials not set, but requested, set it automatically
4908
                                if (!this.withCredentials) {
4909
                                        this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag;
4910
                                }
4911
 
4912
                                // 4 - storage mutex
4913
                                // 5
4914
                                _upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP
4915
                                // 6
4916
                                _error_flag = false;
4917
                                // 7
4918
                                _upload_complete_flag = !data;
4919
                                // 8 - Asynchronous steps
4920
                                if (!_sync_flag) {
4921
                                        // 8.1
4922
                                        _send_flag = true;
4923
                                        // 8.2
4924
                                        // this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr
4925
                                        // 8.3
4926
                                        //if (!_upload_complete_flag) {
4927
                                                // this.upload.dispatchEvent('loadstart');      // will be dispatched either by native or runtime xhr
4928
                                        //}
4929
                                }
4930
                                // 8.5 - Return the send() method call, but continue running the steps in this algorithm.
4931
                                _doXHR.call(this, data);
4932
                        },
4933
 
4934
                        /**
4935
                        Cancels any network activity.
4936
 
4937
                        @method abort
4938
                        */
4939
                        abort: function() {
4940
                                _error_flag = true;
4941
                                _sync_flag = false;
4942
 
4943
                                if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) {
4944
                                        _p('readyState', XMLHttpRequest.DONE);
4945
                                        _send_flag = false;
4946
 
4947
                                        if (_xhr) {
4948
                                                _xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag);
4949
                                        } else {
4950
                                                throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
4951
                                        }
4952
 
4953
                                        _upload_complete_flag = true;
4954
                                } else {
4955
                                        _p('readyState', XMLHttpRequest.UNSENT);
4956
                                }
4957
                        },
4958
 
4959
                        destroy: function() {
4960
                                if (_xhr) {
4961
                                        if (Basic.typeOf(_xhr.destroy) === 'function') {
4962
                                                _xhr.destroy();
4963
                                        }
4964
                                        _xhr = null;
4965
                                }
4966
 
4967
                                this.unbindAll();
4968
 
4969
                                if (this.upload) {
4970
                                        this.upload.unbindAll();
4971
                                        this.upload = null;
4972
                                }
4973
                        }
4974
                });
4975
 
4976
                /* this is nice, but maybe too lengthy
4977
 
4978
                // if supported by JS version, set getters/setters for specific properties
4979
                o.defineProperty(this, 'readyState', {
4980
                        configurable: false,
4981
 
4982
                        get: function() {
4983
                                return _p('readyState');
4984
                        }
4985
                });
4986
 
4987
                o.defineProperty(this, 'timeout', {
4988
                        configurable: false,
4989
 
4990
                        get: function() {
4991
                                return _p('timeout');
4992
                        },
4993
 
4994
                        set: function(value) {
4995
 
4996
                                if (_sync_flag) {
4997
                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
4998
                                }
4999
 
5000
                                // timeout still should be measured relative to the start time of request
5001
                                _timeoutset_time = (new Date).getTime();
5002
 
5003
                                _p('timeout', value);
5004
                        }
5005
                });
5006
 
5007
                // the withCredentials attribute has no effect when fetching same-origin resources
5008
                o.defineProperty(this, 'withCredentials', {
5009
                        configurable: false,
5010
 
5011
                        get: function() {
5012
                                return _p('withCredentials');
5013
                        },
5014
 
5015
                        set: function(value) {
5016
                                // 1-2
5017
                                if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) {
5018
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5019
                                }
5020
 
5021
                                // 3-4
5022
                                if (_anonymous_flag || _sync_flag) {
5023
                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
5024
                                }
5025
 
5026
                                // 5
5027
                                _p('withCredentials', value);
5028
                        }
5029
                });
5030
 
5031
                o.defineProperty(this, 'status', {
5032
                        configurable: false,
5033
 
5034
                        get: function() {
5035
                                return _p('status');
5036
                        }
5037
                });
5038
 
5039
                o.defineProperty(this, 'statusText', {
5040
                        configurable: false,
5041
 
5042
                        get: function() {
5043
                                return _p('statusText');
5044
                        }
5045
                });
5046
 
5047
                o.defineProperty(this, 'responseType', {
5048
                        configurable: false,
5049
 
5050
                        get: function() {
5051
                                return _p('responseType');
5052
                        },
5053
 
5054
                        set: function(value) {
5055
                                // 1
5056
                                if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
5057
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5058
                                }
5059
 
5060
                                // 2
5061
                                if (_sync_flag) {
5062
                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
5063
                                }
5064
 
5065
                                // 3
5066
                                _p('responseType', value.toLowerCase());
5067
                        }
5068
                });
5069
 
5070
                o.defineProperty(this, 'responseText', {
5071
                        configurable: false,
5072
 
5073
                        get: function() {
5074
                                // 1
5075
                                if (!~o.inArray(_p('responseType'), ['', 'text'])) {
5076
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5077
                                }
5078
 
5079
                                // 2-3
5080
                                if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) {
5081
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5082
                                }
5083
 
5084
                                return _p('responseText');
5085
                        }
5086
                });
5087
 
5088
                o.defineProperty(this, 'responseXML', {
5089
                        configurable: false,
5090
 
5091
                        get: function() {
5092
                                // 1
5093
                                if (!~o.inArray(_p('responseType'), ['', 'document'])) {
5094
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5095
                                }
5096
 
5097
                                // 2-3
5098
                                if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) {
5099
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5100
                                }
5101
 
5102
                                return _p('responseXML');
5103
                        }
5104
                });
5105
 
5106
                o.defineProperty(this, 'response', {
5107
                        configurable: false,
5108
 
5109
                        get: function() {
5110
                                if (!!~o.inArray(_p('responseType'), ['', 'text'])) {
5111
                                        if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) {
5112
                                                return '';
5113
                                        }
5114
                                }
5115
 
5116
                                if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) {
5117
                                        return null;
5118
                                }
5119
 
5120
                                return _p('response');
5121
                        }
5122
                });
5123
 
5124
                */
5125
 
5126
                function _p(prop, value) {
5127
                        if (!props.hasOwnProperty(prop)) {
5128
                                return;
5129
                        }
5130
                        if (arguments.length === 1) { // get
5131
                                return Env.can('define_property') ? props[prop] : self[prop];
5132
                        } else { // set
5133
                                if (Env.can('define_property')) {
5134
                                        props[prop] = value;
5135
                                } else {
5136
                                        self[prop] = value;
5137
                                }
5138
                        }
5139
                }
5140
 
5141
                /*
5142
                function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) {
5143
                        // TODO: http://tools.ietf.org/html/rfc3490#section-4.1
5144
                        return str.toLowerCase();
5145
                }
5146
                */
5147
 
5148
 
5149
                function _doXHR(data) {
5150
                        var self = this;
5151
 
5152
                        _start_time = new Date().getTime();
5153
 
5154
                        _xhr = new RuntimeTarget();
5155
 
5156
                        function loadEnd() {
5157
                                if (_xhr) { // it could have been destroyed by now
5158
                                        _xhr.destroy();
5159
                                        _xhr = null;
5160
                                }
5161
                                self.dispatchEvent('loadend');
5162
                                self = null;
5163
                        }
5164
 
5165
                        function exec(runtime) {
5166
                                _xhr.bind('LoadStart', function(e) {
5167
                                        _p('readyState', XMLHttpRequest.LOADING);
5168
                                        self.dispatchEvent('readystatechange');
5169
 
5170
                                        self.dispatchEvent(e);
5171
 
5172
                                        if (_upload_events_flag) {
5173
                                                self.upload.dispatchEvent(e);
5174
                                        }
5175
                                });
5176
 
5177
                                _xhr.bind('Progress', function(e) {
5178
                                        if (_p('readyState') !== XMLHttpRequest.LOADING) {
5179
                                                _p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example)
5180
                                                self.dispatchEvent('readystatechange');
5181
                                        }
5182
                                        self.dispatchEvent(e);
5183
                                });
5184
 
5185
                                _xhr.bind('UploadProgress', function(e) {
5186
                                        if (_upload_events_flag) {
5187
                                                self.upload.dispatchEvent({
5188
                                                        type: 'progress',
5189
                                                        lengthComputable: false,
5190
                                                        total: e.total,
5191
                                                        loaded: e.loaded
5192
                                                });
5193
                                        }
5194
                                });
5195
 
5196
                                _xhr.bind('Load', function(e) {
5197
                                        _p('readyState', XMLHttpRequest.DONE);
5198
                                        _p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0));
5199
                                        _p('statusText', httpCode[_p('status')] || "");
5200
 
5201
                                        _p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType')));
5202
 
5203
                                        if (!!~Basic.inArray(_p('responseType'), ['text', ''])) {
5204
                                                _p('responseText', _p('response'));
5205
                                        } else if (_p('responseType') === 'document') {
5206
                                                _p('responseXML', _p('response'));
5207
                                        }
5208
 
5209
                                        _responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders');
5210
 
5211
                                        self.dispatchEvent('readystatechange');
5212
 
5213
                                        if (_p('status') > 0) { // status 0 usually means that server is unreachable
5214
                                                if (_upload_events_flag) {
5215
                                                        self.upload.dispatchEvent(e);
5216
                                                }
5217
                                                self.dispatchEvent(e);
5218
                                        } else {
5219
                                                _error_flag = true;
5220
                                                self.dispatchEvent('error');
5221
                                        }
5222
                                        loadEnd();
5223
                                });
5224
 
5225
                                _xhr.bind('Abort', function(e) {
5226
                                        self.dispatchEvent(e);
5227
                                        loadEnd();
5228
                                });
5229
 
5230
                                _xhr.bind('Error', function(e) {
5231
                                        _error_flag = true;
5232
                                        _p('readyState', XMLHttpRequest.DONE);
5233
                                        self.dispatchEvent('readystatechange');
5234
                                        _upload_complete_flag = true;
5235
                                        self.dispatchEvent(e);
5236
                                        loadEnd();
5237
                                });
5238
 
5239
                                runtime.exec.call(_xhr, 'XMLHttpRequest', 'send', {
5240
                                        url: _url,
5241
                                        method: _method,
5242
                                        async: _async,
5243
                                        user: _user,
5244
                                        password: _password,
5245
                                        headers: _headers,
5246
                                        mimeType: _mimeType,
5247
                                        encoding: _encoding,
5248
                                        responseType: self.responseType,
5249
                                        withCredentials: self.withCredentials,
5250
                                        options: _options
5251
                                }, data);
5252
                        }
5253
 
5254
                        // clarify our requirements
5255
                        if (typeof(_options.required_caps) === 'string') {
5256
                                _options.required_caps = Runtime.parseCaps(_options.required_caps);
5257
                        }
5258
 
5259
                        _options.required_caps = Basic.extend({}, _options.required_caps, {
5260
                                return_response_type: self.responseType
5261
                        });
5262
 
5263
                        if (data instanceof FormData) {
5264
                                _options.required_caps.send_multipart = true;
5265
                        }
5266
 
5267
                        if (!_same_origin_flag) {
5268
                                _options.required_caps.do_cors = true;
5269
                        }
5270
 
5271
 
5272
                        if (_options.ruid) { // we do not need to wait if we can connect directly
5273
                                exec(_xhr.connectRuntime(_options));
5274
                        } else {
5275
                                _xhr.bind('RuntimeInit', function(e, runtime) {
5276
                                        exec(runtime);
5277
                                });
5278
                                _xhr.bind('RuntimeError', function(e, err) {
5279
                                        self.dispatchEvent('RuntimeError', err);
5280
                                });
5281
                                _xhr.connectRuntime(_options);
5282
                        }
5283
                }
5284
 
5285
 
5286
                function _reset() {
5287
                        _p('responseText', "");
5288
                        _p('responseXML', null);
5289
                        _p('response', null);
5290
                        _p('status', 0);
5291
                        _p('statusText', "");
5292
                        _start_time = _timeoutset_time = null;
5293
                }
5294
        }
5295
 
5296
        XMLHttpRequest.UNSENT = 0;
5297
        XMLHttpRequest.OPENED = 1;
5298
        XMLHttpRequest.HEADERS_RECEIVED = 2;
5299
        XMLHttpRequest.LOADING = 3;
5300
        XMLHttpRequest.DONE = 4;
5301
 
5302
        XMLHttpRequest.prototype = EventTarget.instance;
5303
 
5304
        return XMLHttpRequest;
5305
});
5306
 
5307
// Included from: src/javascript/runtime/Transporter.js
5308
 
5309
/**
5310
 * Transporter.js
5311
 *
5312
 * Copyright 2013, Moxiecode Systems AB
5313
 * Released under GPL License.
5314
 *
5315
 * License: http://www.plupload.com/license
5316
 * Contributing: http://www.plupload.com/contributing
5317
 */
5318
 
5319
define("moxie/runtime/Transporter", [
5320
        "moxie/core/utils/Basic",
5321
        "moxie/core/utils/Encode",
5322
        "moxie/runtime/RuntimeClient",
5323
        "moxie/core/EventTarget"
5324
], function(Basic, Encode, RuntimeClient, EventTarget) {
5325
        function Transporter() {
5326
                var mod, _runtime, _data, _size, _pos, _chunk_size;
5327
 
5328
                RuntimeClient.call(this);
5329
 
5330
                Basic.extend(this, {
5331
                        uid: Basic.guid('uid_'),
5332
 
5333
                        state: Transporter.IDLE,
5334
 
5335
                        result: null,
5336
 
5337
                        transport: function(data, type, options) {
5338
                                var self = this;
5339
 
5340
                                options = Basic.extend({
5341
                                        chunk_size: 204798
5342
                                }, options);
5343
 
5344
                                // should divide by three, base64 requires this
5345
                                if ((mod = options.chunk_size % 3)) {
5346
                                        options.chunk_size += 3 - mod;
5347
                                }
5348
 
5349
                                _chunk_size = options.chunk_size;
5350
 
5351
                                _reset.call(this);
5352
                                _data = data;
5353
                                _size = data.length;
5354
 
5355
                                if (Basic.typeOf(options) === 'string' || options.ruid) {
5356
                                        _run.call(self, type, this.connectRuntime(options));
5357
                                } else {
5358
                                        // we require this to run only once
5359
                                        var cb = function(e, runtime) {
5360
                                                self.unbind("RuntimeInit", cb);
5361
                                                _run.call(self, type, runtime);
5362
                                        };
5363
                                        this.bind("RuntimeInit", cb);
5364
                                        this.connectRuntime(options);
5365
                                }
5366
                        },
5367
 
5368
                        abort: function() {
5369
                                var self = this;
5370
 
5371
                                self.state = Transporter.IDLE;
5372
                                if (_runtime) {
5373
                                        _runtime.exec.call(self, 'Transporter', 'clear');
5374
                                        self.trigger("TransportingAborted");
5375
                                }
5376
 
5377
                                _reset.call(self);
5378
                        },
5379
 
5380
 
5381
                        destroy: function() {
5382
                                this.unbindAll();
5383
                                _runtime = null;
5384
                                this.disconnectRuntime();
5385
                                _reset.call(this);
5386
                        }
5387
                });
5388
 
5389
                function _reset() {
5390
                        _size = _pos = 0;
5391
                        _data = this.result = null;
5392
                }
5393
 
5394
                function _run(type, runtime) {
5395
                        var self = this;
5396
 
5397
                        _runtime = runtime;
5398
 
5399
                        //self.unbind("RuntimeInit");
5400
 
5401
                        self.bind("TransportingProgress", function(e) {
5402
                                _pos = e.loaded;
5403
 
5404
                                if (_pos < _size && Basic.inArray(self.state, [Transporter.IDLE, Transporter.DONE]) === -1) {
5405
                                        _transport.call(self);
5406
                                }
5407
                        }, 999);
5408
 
5409
                        self.bind("TransportingComplete", function() {
5410
                                _pos = _size;
5411
                                self.state = Transporter.DONE;
5412
                                _data = null; // clean a bit
5413
                                self.result = _runtime.exec.call(self, 'Transporter', 'getAsBlob', type || '');
5414
                        }, 999);
5415
 
5416
                        self.state = Transporter.BUSY;
5417
                        self.trigger("TransportingStarted");
5418
                        _transport.call(self);
5419
                }
5420
 
5421
                function _transport() {
5422
                        var self = this,
5423
                                chunk,
5424
                                bytesLeft = _size - _pos;
5425
 
5426
                        if (_chunk_size > bytesLeft) {
5427
                                _chunk_size = bytesLeft;
5428
                        }
5429
 
5430
                        chunk = Encode.btoa(_data.substr(_pos, _chunk_size));
5431
                        _runtime.exec.call(self, 'Transporter', 'receive', chunk, _size);
5432
                }
5433
        }
5434
 
5435
        Transporter.IDLE = 0;
5436
        Transporter.BUSY = 1;
5437
        Transporter.DONE = 2;
5438
 
5439
        Transporter.prototype = EventTarget.instance;
5440
 
5441
        return Transporter;
5442
});
5443
 
5444
// Included from: src/javascript/image/Image.js
5445
 
5446
/**
5447
 * Image.js
5448
 *
5449
 * Copyright 2013, Moxiecode Systems AB
5450
 * Released under GPL License.
5451
 *
5452
 * License: http://www.plupload.com/license
5453
 * Contributing: http://www.plupload.com/contributing
5454
 */
5455
 
5456
define("moxie/image/Image", [
5457
        "moxie/core/utils/Basic",
5458
        "moxie/core/utils/Dom",
5459
        "moxie/core/Exceptions",
5460
        "moxie/file/FileReaderSync",
5461
        "moxie/xhr/XMLHttpRequest",
5462
        "moxie/runtime/Runtime",
5463
        "moxie/runtime/RuntimeClient",
5464
        "moxie/runtime/Transporter",
5465
        "moxie/core/utils/Env",
5466
        "moxie/core/EventTarget",
5467
        "moxie/file/Blob",
5468
        "moxie/file/File",
5469
        "moxie/core/utils/Encode"
5470
], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) {
5471
        /**
5472
        Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data.
5473
 
5474
        @class Image
5475
        @constructor
5476
        @extends EventTarget
5477
        */
5478
        var dispatches = [
5479
                'progress',
5480
 
5481
                /**
5482
                Dispatched when loading is complete.
5483
 
5484
                @event load
5485
                @param {Object} event
5486
                */
5487
                'load',
5488
 
5489
                'error',
5490
 
5491
                /**
5492
                Dispatched when resize operation is complete.
5493
 
5494
                @event resize
5495
                @param {Object} event
5496
                */
5497
                'resize',
5498
 
5499
                /**
5500
                Dispatched when visual representation of the image is successfully embedded
5501
                into the corresponsing container.
5502
 
5503
                @event embedded
5504
                @param {Object} event
5505
                */
5506
                'embedded'
5507
        ];
5508
 
5509
        function Image() {
5510
                RuntimeClient.call(this);
5511
 
5512
                Basic.extend(this, {
5513
                        /**
5514
                        Unique id of the component
5515
 
5516
                        @property uid
5517
                        @type {String}
5518
                        */
5519
                        uid: Basic.guid('uid_'),
5520
 
5521
                        /**
5522
                        Unique id of the connected runtime, if any.
5523
 
5524
                        @property ruid
5525
                        @type {String}
5526
                        */
5527
                        ruid: null,
5528
 
5529
                        /**
5530
                        Name of the file, that was used to create an image, if available. If not equals to empty string.
5531
 
5532
                        @property name
5533
                        @type {String}
5534
                        @default ""
5535
                        */
5536
                        name: "",
5537
 
5538
                        /**
5539
                        Size of the image in bytes. Actual value is set only after image is preloaded.
5540
 
5541
                        @property size
5542
                        @type {Number}
5543
                        @default 0
5544
                        */
5545
                        size: 0,
5546
 
5547
                        /**
5548
                        Width of the image. Actual value is set only after image is preloaded.
5549
 
5550
                        @property width
5551
                        @type {Number}
5552
                        @default 0
5553
                        */
5554
                        width: 0,
5555
 
5556
                        /**
5557
                        Height of the image. Actual value is set only after image is preloaded.
5558
 
5559
                        @property height
5560
                        @type {Number}
5561
                        @default 0
5562
                        */
5563
                        height: 0,
5564
 
5565
                        /**
5566
                        Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded.
5567
 
5568
                        @property type
5569
                        @type {String}
5570
                        @default ""
5571
                        */
5572
                        type: "",
5573
 
5574
                        /**
5575
                        Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded.
5576
 
5577
                        @property meta
5578
                        @type {Object}
5579
                        @default {}
5580
                        */
5581
                        meta: {},
5582
 
5583
                        /**
5584
                        Alias for load method, that takes another mOxie.Image object as a source (see load).
5585
 
5586
                        @method clone
5587
                        @param {Image} src Source for the image
5588
                        @param {Boolean} [exact=false] Whether to activate in-depth clone mode
5589
                        */
5590
                        clone: function() {
5591
                                this.load.apply(this, arguments);
5592
                        },
5593
 
5594
                        /**
5595
                        Loads image from various sources. Currently the source for new image can be: mOxie.Image, mOxie.Blob/mOxie.File,
5596
                        native Blob/File, dataUrl or URL. Depending on the type of the source, arguments - differ. When source is URL,
5597
                        Image will be downloaded from remote destination and loaded in memory.
5598
 
5599
                        @example
5600
                                var img = new mOxie.Image();
5601
                                img.onload = function() {
5602
                                        var blob = img.getAsBlob();
5603
 
5604
                                        var formData = new mOxie.FormData();
5605
                                        formData.append('file', blob);
5606
 
5607
                                        var xhr = new mOxie.XMLHttpRequest();
5608
                                        xhr.onload = function() {
5609
                                                // upload complete
5610
                                        };
5611
                                        xhr.open('post', 'upload.php');
5612
                                        xhr.send(formData);
5613
                                };
5614
                                img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg)
5615
 
5616
 
5617
                        @method load
5618
                        @param {Image|Blob|File|String} src Source for the image
5619
                        @param {Boolean|Object} [mixed]
5620
                        */
5621
                        load: function() {
5622
                                // this is here because to bind properly we need an uid first, which is created above
5623
                                this.bind('Load Resize', function() {
5624
                                        _updateInfo.call(this);
5625
                                }, 999);
5626
 
5627
                                this.convertEventPropsToHandlers(dispatches);
5628
 
5629
                                _load.apply(this, arguments);
5630
                        },
5631
 
5632
                        /**
5633
                        Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions.
5634
 
5635
                        @method downsize
5636
                        @param {Number} width Resulting width
5637
                        @param {Number} [height=width] Resulting height (optional, if not supplied will default to width)
5638
                        @param {Boolean} [crop=false] Whether to crop the image to exact dimensions
5639
                        @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
5640
                        */
5641
                        downsize: function(opts) {
5642
                                var defaults = {
5643
                                        width: this.width,
5644
                                        height: this.height,
5645
                                        crop: false,
5646
                                        preserveHeaders: true
5647
                                };
5648
 
5649
                                if (typeof(opts) === 'object') {
5650
                                        opts = Basic.extend(defaults, opts);
5651
                                } else {
5652
                                        opts = Basic.extend(defaults, {
5653
                                                width: arguments[0],
5654
                                                height: arguments[1],
5655
                                                crop: arguments[2],
5656
                                                preserveHeaders: arguments[3]
5657
                                        });
5658
                                }
5659
 
5660
                                try {
5661
                                        if (!this.size) { // only preloaded image objects can be used as source
5662
                                                throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5663
                                        }
5664
 
5665
                                        // no way to reliably intercept the crash due to high resolution, so we simply avoid it
5666
                                        if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
5667
                                                throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
5668
                                        }
5669
 
5670
                                        this.getRuntime().exec.call(this, 'Image', 'downsize', opts.width, opts.height, opts.crop, opts.preserveHeaders);
5671
                                } catch(ex) {
5672
                                        // for now simply trigger error event
5673
                                        this.trigger('error', ex.code);
5674
                                }
5675
                        },
5676
 
5677
                        /**
5678
                        Alias for downsize(width, height, true). (see downsize)
5679
 
5680
                        @method crop
5681
                        @param {Number} width Resulting width
5682
                        @param {Number} [height=width] Resulting height (optional, if not supplied will default to width)
5683
                        @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
5684
                        */
5685
                        crop: function(width, height, preserveHeaders) {
5686
                                this.downsize(width, height, true, preserveHeaders);
5687
                        },
5688
 
5689
                        getAsCanvas: function() {
5690
                                if (!Env.can('create_canvas')) {
5691
                                        throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
5692
                                }
5693
 
5694
                                var runtime = this.connectRuntime(this.ruid);
5695
                                return runtime.exec.call(this, 'Image', 'getAsCanvas');
5696
                        },
5697
 
5698
                        /**
5699
                        Retrieves image in it's current state as mOxie.Blob object. Cannot be run on empty or image in progress (throws
5700
                        DOMException.INVALID_STATE_ERR).
5701
 
5702
                        @method getAsBlob
5703
                        @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
5704
                        @param {Number} [quality=90] Applicable only together with mime type image/jpeg
5705
                        @return {Blob} Image as Blob
5706
                        */
5707
                        getAsBlob: function(type, quality) {
5708
                                if (!this.size) {
5709
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5710
                                }
5711
 
5712
                                if (!type) {
5713
                                        type = 'image/jpeg';
5714
                                }
5715
 
5716
                                if (type === 'image/jpeg' && !quality) {
5717
                                        quality = 90;
5718
                                }
5719
 
5720
                                return this.getRuntime().exec.call(this, 'Image', 'getAsBlob', type, quality);
5721
                        },
5722
 
5723
                        /**
5724
                        Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws
5725
                        DOMException.INVALID_STATE_ERR).
5726
 
5727
                        @method getAsDataURL
5728
                        @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
5729
                        @param {Number} [quality=90] Applicable only together with mime type image/jpeg
5730
                        @return {String} Image as dataURL string
5731
                        */
5732
                        getAsDataURL: function(type, quality) {
5733
                                if (!this.size) {
5734
                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5735
                                }
5736
                                return this.getRuntime().exec.call(this, 'Image', 'getAsDataURL', type, quality);
5737
                        },
5738
 
5739
                        /**
5740
                        Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws
5741
                        DOMException.INVALID_STATE_ERR).
5742
 
5743
                        @method getAsBinaryString
5744
                        @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
5745
                        @param {Number} [quality=90] Applicable only together with mime type image/jpeg
5746
                        @return {String} Image as binary string
5747
                        */
5748
                        getAsBinaryString: function(type, quality) {
5749
                                var dataUrl = this.getAsDataURL(type, quality);
5750
                                return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7));
5751
                        },
5752
 
5753
                        /**
5754
                        Embeds a visual representation of the image into the specified node. Depending on the runtime,
5755
                        it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare,
5756
                        can be used in legacy browsers that do not have canvas or proper dataURI support).
5757
 
5758
                        @method embed
5759
                        @param {DOMElement} el DOM element to insert the image object into
5760
                        @param {Object} [options]
5761
                                @param {Number} [options.width] The width of an embed (defaults to the image width)
5762
                                @param {Number} [options.height] The height of an embed (defaults to the image height)
5763
                                @param {String} [type="image/jpeg"] Mime type
5764
                                @param {Number} [quality=90] Quality of an embed, if mime type is image/jpeg
5765
                                @param {Boolean} [crop=false] Whether to crop an embed to the specified dimensions
5766
                        */
5767
                        embed: function(el) {
5768
                                var self = this
5769
                                , imgCopy
5770
                                , type, quality, crop
5771
                                , options = arguments[1] || {}
5772
                                , width = this.width
5773
                                , height = this.height
5774
                                , runtime // this has to be outside of all the closures to contain proper runtime
5775
                                ;
5776
 
5777
                                function onResize() {
5778
                                        // if possible, embed a canvas element directly
5779
                                        if (Env.can('create_canvas')) {
5780
                                                var canvas = imgCopy.getAsCanvas();
5781
                                                if (canvas) {
5782
                                                        el.appendChild(canvas);
5783
                                                        canvas = null;
5784
                                                        imgCopy.destroy();
5785
                                                        self.trigger('embedded');
5786
                                                        return;
5787
                                                }
5788
                                        }
5789
 
5790
                                        var dataUrl = imgCopy.getAsDataURL(type, quality);
5791
                                        if (!dataUrl) {
5792
                                                throw new x.ImageError(x.ImageError.WRONG_FORMAT);
5793
                                        }
5794
 
5795
                                        if (Env.can('use_data_uri_of', dataUrl.length)) {
5796
                                                el.innerHTML = '<img src="' + dataUrl + '" width="' + imgCopy.width + '" height="' + imgCopy.height + '" />';
5797
                                                imgCopy.destroy();
5798
                                                self.trigger('embedded');
5799
                                        } else {
5800
                                                var tr = new Transporter();
5801
 
5802
                                                tr.bind("TransportingComplete", function() {
5803
                                                        runtime = self.connectRuntime(this.result.ruid);
5804
 
5805
                                                        self.bind("Embedded", function() {
5806
                                                                // position and size properly
5807
                                                                Basic.extend(runtime.getShimContainer().style, {
5808
                                                                        //position: 'relative',
5809
                                                                        top: '0px',
5810
                                                                        left: '0px',
5811
                                                                        width: imgCopy.width + 'px',
5812
                                                                        height: imgCopy.height + 'px'
5813
                                                                });
5814
 
5815
                                                                // some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's
5816
                                                                // position type changes (in Gecko), but since we basically need this only in IEs 6/7 and
5817
                                                                // sometimes 8 and they do not have this problem, we can comment this for now
5818
                                                                /*tr.bind("RuntimeInit", function(e, runtime) {
5819
                                                                        tr.destroy();
5820
                                                                        runtime.destroy();
5821
                                                                        onResize.call(self); // re-feed our image data
5822
                                                                });*/
5823
 
5824
                                                                runtime = null;
5825
                                                        }, 999);
5826
 
5827
                                                        runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height);
5828
                                                        imgCopy.destroy();
5829
                                                });
5830
 
5831
                                                tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, Basic.extend({}, options, {
5832
                                                        required_caps: {
5833
                                                                display_media: true
5834
                                                        },
5835
                                                        runtime_order: 'flash,silverlight',
5836
                                                        container: el
5837
                                                }));
5838
                                        }
5839
                                }
5840
 
5841
                                try {
5842
                                        if (!(el = Dom.get(el))) {
5843
                                                throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR);
5844
                                        }
5845
 
5846
                                        if (!this.size) { // only preloaded image objects can be used as source
5847
                                                throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5848
                                        }
5849
 
5850
                                        if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
5851
                                                throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
5852
                                        }
5853
 
5854
                                        type = options.type || this.type || 'image/jpeg';
5855
                                        quality = options.quality || 90;
5856
                                        crop = Basic.typeOf(options.crop) !== 'undefined' ? options.crop : false;
5857
 
5858
                                        // figure out dimensions for the thumb
5859
                                        if (options.width) {
5860
                                                width = options.width;
5861
                                                height = options.height || width;
5862
                                        } else {
5863
                                                // if container element has measurable dimensions, use them
5864
                                                var dimensions = Dom.getSize(el);
5865
                                                if (dimensions.w && dimensions.h) { // both should be > 0
5866
                                                        width = dimensions.w;
5867
                                                        height = dimensions.h;
5868
                                                }
5869
                                        }
5870
 
5871
                                        imgCopy = new Image();
5872
 
5873
                                        imgCopy.bind("Resize", function() {
5874
                                                onResize.call(self);
5875
                                        });
5876
 
5877
                                        imgCopy.bind("Load", function() {
5878
                                                imgCopy.downsize(width, height, crop, false);
5879
                                        });
5880
 
5881
                                        imgCopy.clone(this, false);
5882
 
5883
                                        return imgCopy;
5884
                                } catch(ex) {
5885
                                        // for now simply trigger error event
5886
                                        this.trigger('error', ex.code);
5887
                                }
5888
                        },
5889
 
5890
                        /**
5891
                        Properly destroys the image and frees resources in use. If any. Recommended way to dispose mOxie.Image object.
5892
 
5893
                        @method destroy
5894
                        */
5895
                        destroy: function() {
5896
                                if (this.ruid) {
5897
                                        this.getRuntime().exec.call(this, 'Image', 'destroy');
5898
                                        this.disconnectRuntime();
5899
                                }
5900
                                this.unbindAll();
5901
                        }
5902
                });
5903
 
5904
 
5905
                function _updateInfo(info) {
5906
                        if (!info) {
5907
                                info = this.getRuntime().exec.call(this, 'Image', 'getInfo');
5908
                        }
5909
 
5910
                        this.size = info.size;
5911
                        this.width = info.width;
5912
                        this.height = info.height;
5913
                        this.type = info.type;
5914
                        this.meta = info.meta;
5915
 
5916
                        // update file name, only if empty
5917
                        if (this.name === '') {
5918
                                this.name = info.name;
5919
                        }
5920
                }
5921
 
5922
 
5923
                function _load(src) {
5924
                        var srcType = Basic.typeOf(src);
5925
 
5926
                        try {
5927
                                // if source is Image
5928
                                if (src instanceof Image) {
5929
                                        if (!src.size) { // only preloaded image objects can be used as source
5930
                                                throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5931
                                        }
5932
                                        _loadFromImage.apply(this, arguments);
5933
                                }
5934
                                // if source is o.Blob/o.File
5935
                                else if (src instanceof Blob) {
5936
                                        if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) {
5937
                                                throw new x.ImageError(x.ImageError.WRONG_FORMAT);
5938
                                        }
5939
                                        _loadFromBlob.apply(this, arguments);
5940
                                }
5941
                                // if native blob/file
5942
                                else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) {
5943
                                        _load.call(this, new File(null, src), arguments[1]);
5944
                                }
5945
                                // if String
5946
                                else if (srcType === 'string') {
5947
                                        // if dataUrl String
5948
                                        if (/^data:[^;]*;base64,/.test(src)) {
5949
                                                _load.call(this, new Blob(null, { data: src }), arguments[1]);
5950
                                        }
5951
                                        // else assume Url, either relative or absolute
5952
                                        else {
5953
                                                _loadFromUrl.apply(this, arguments);
5954
                                        }
5955
                                }
5956
                                // if source seems to be an img node
5957
                                else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') {
5958
                                        _load.call(this, src.src, arguments[1]);
5959
                                }
5960
                                else {
5961
                                        throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR);
5962
                                }
5963
                        } catch(ex) {
5964
                                // for now simply trigger error event
5965
                                this.trigger('error', ex.code);
5966
                        }
5967
                }
5968
 
5969
 
5970
                function _loadFromImage(img, exact) {
5971
                        var runtime = this.connectRuntime(img.ruid);
5972
                        this.ruid = runtime.uid;
5973
                        runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact));
5974
                }
5975
 
5976
 
5977
                function _loadFromBlob(blob, options) {
5978
                        var self = this;
5979
 
5980
                        self.name = blob.name || '';
5981
 
5982
                        function exec(runtime) {
5983
                                self.ruid = runtime.uid;
5984
                                runtime.exec.call(self, 'Image', 'loadFromBlob', blob);
5985
                        }
5986
 
5987
                        if (blob.isDetached()) {
5988
                                this.bind('RuntimeInit', function(e, runtime) {
5989
                                        exec(runtime);
5990
                                });
5991
 
5992
                                // convert to object representation
5993
                                if (options && typeof(options.required_caps) === 'string') {
5994
                                        options.required_caps = Runtime.parseCaps(options.required_caps);
5995
                                }
5996
 
5997
                                this.connectRuntime(Basic.extend({
5998
                                        required_caps: {
5999
                                                access_image_binary: true,
6000
                                                resize_image: true
6001
                                        }
6002
                                }, options));
6003
                        } else {
6004
                                exec(this.connectRuntime(blob.ruid));
6005
                        }
6006
                }
6007
 
6008
 
6009
                function _loadFromUrl(url, options) {
6010
                        var self = this, xhr;
6011
 
6012
                        xhr = new XMLHttpRequest();
6013
 
6014
                        xhr.open('get', url);
6015
                        xhr.responseType = 'blob';
6016
 
6017
                        xhr.onprogress = function(e) {
6018
                                self.trigger(e);
6019
                        };
6020
 
6021
                        xhr.onload = function() {
6022
                                _loadFromBlob.call(self, xhr.response, true);
6023
                        };
6024
 
6025
                        xhr.onerror = function(e) {
6026
                                self.trigger(e);
6027
                        };
6028
 
6029
                        xhr.onloadend = function() {
6030
                                xhr.destroy();
6031
                        };
6032
 
6033
                        xhr.bind('RuntimeError', function(e, err) {
6034
                                self.trigger('RuntimeError', err);
6035
                        });
6036
 
6037
                        xhr.send(null, options);
6038
                }
6039
        }
6040
 
6041
        // virtual world will crash on you if image has a resolution higher than this:
6042
        Image.MAX_RESIZE_WIDTH = 6500;
6043
        Image.MAX_RESIZE_HEIGHT = 6500;
6044
 
6045
        Image.prototype = EventTarget.instance;
6046
 
6047
        return Image;
6048
});
6049
 
6050
// Included from: src/javascript/runtime/html5/Runtime.js
6051
 
6052
/**
6053
 * Runtime.js
6054
 *
6055
 * Copyright 2013, Moxiecode Systems AB
6056
 * Released under GPL License.
6057
 *
6058
 * License: http://www.plupload.com/license
6059
 * Contributing: http://www.plupload.com/contributing
6060
 */
6061
 
6062
/*global File:true */
6063
 
6064
/**
6065
Defines constructor for HTML5 runtime.
6066
 
6067
@class moxie/runtime/html5/Runtime
6068
@private
6069
*/
6070
define("moxie/runtime/html5/Runtime", [
6071
        "moxie/core/utils/Basic",
6072
        "moxie/core/Exceptions",
6073
        "moxie/runtime/Runtime",
6074
        "moxie/core/utils/Env"
6075
], function(Basic, x, Runtime, Env) {
6076
 
6077
        var type = "html5", extensions = {};
6078
 
6079
        function Html5Runtime(options) {
6080
                var I = this
6081
                , Test = Runtime.capTest
6082
                , True = Runtime.capTrue
6083
                ;
6084
 
6085
                var caps = Basic.extend({
6086
                                access_binary: Test(window.FileReader || window.File && window.File.getAsDataURL),
6087
                                access_image_binary: function() {
6088
                                        return I.can('access_binary') && !!extensions.Image;
6089
                                },
6090
                                display_media: Test(Env.can('create_canvas') || Env.can('use_data_uri_over32kb')),
6091
                                do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()),
6092
                                drag_and_drop: Test(function() {
6093
                                        // this comes directly from Modernizr: http://www.modernizr.com/
6094
                                        var div = document.createElement('div');
6095
                                        // IE has support for drag and drop since version 5, but doesn't support dropping files from desktop
6096
                                        return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && (Env.browser !== 'IE' || Env.version > 9);
6097
                                }()),
6098
                                filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest
6099
                                        return (Env.browser === 'Chrome' && Env.version >= 28) || (Env.browser === 'IE' && Env.version >= 10);
6100
                                }()),
6101
                                return_response_headers: True,
6102
                                return_response_type: function(responseType) {
6103
                                        if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported
6104
                                                return true;
6105
                                        }
6106
                                        return Env.can('return_response_type', responseType);
6107
                                },
6108
                                return_status_code: True,
6109
                                report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload),
6110
                                resize_image: function() {
6111
                                        return I.can('access_binary') && Env.can('create_canvas');
6112
                                },
6113
                                select_file: function() {
6114
                                        return Env.can('use_fileinput') && window.File;
6115
                                },
6116
                                select_folder: function() {
6117
                                        return I.can('select_file') && Env.browser === 'Chrome' && Env.version >= 21;
6118
                                },
6119
                                select_multiple: function() {
6120
                                        // it is buggy on Safari Windows and iOS
6121
                                        return I.can('select_file') &&
6122
                                                !(Env.browser === 'Safari' && Env.os === 'Windows') &&
6123
                                                !(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.4", '<'));
6124
                                },
6125
                                send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))),
6126
                                send_custom_headers: Test(window.XMLHttpRequest),
6127
                                send_multipart: function() {
6128
                                        return !!(window.XMLHttpRequest && new XMLHttpRequest().upload && window.FormData) || I.can('send_binary_string');
6129
                                },
6130
                                slice_blob: Test(window.File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice)),
6131
                                stream_upload: function(){
6132
                                        return I.can('slice_blob') && I.can('send_multipart');
6133
                                },
6134
                                summon_file_dialog: Test(function() { // yeah... some dirty sniffing here...
6135
                                        return (Env.browser === 'Firefox' && Env.version >= 4) ||
6136
                                                (Env.browser === 'Opera' && Env.version >= 12) ||
6137
                                                (Env.browser === 'IE' && Env.version >= 10) ||
6138
                                                !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']);
6139
                                }()),
6140
                                upload_filesize: True
6141
                        },
6142
                        arguments[2]
6143
                );
6144
 
6145
                Runtime.call(this, options, (arguments[1] || type), caps);
6146
 
6147
 
6148
                Basic.extend(this, {
6149
 
6150
                        init : function() {
6151
                                this.trigger("Init");
6152
                        },
6153
 
6154
                        destroy: (function(destroy) { // extend default destroy method
6155
                                return function() {
6156
                                        destroy.call(I);
6157
                                        destroy = I = null;
6158
                                };
6159
                        }(this.destroy))
6160
                });
6161
 
6162
                Basic.extend(this.getShim(), extensions);
6163
        }
6164
 
6165
        Runtime.addConstructor(type, Html5Runtime);
6166
 
6167
        return extensions;
6168
});
6169
 
6170
// Included from: src/javascript/runtime/html5/file/Blob.js
6171
 
6172
/**
6173
 * Blob.js
6174
 *
6175
 * Copyright 2013, Moxiecode Systems AB
6176
 * Released under GPL License.
6177
 *
6178
 * License: http://www.plupload.com/license
6179
 * Contributing: http://www.plupload.com/contributing
6180
 */
6181
 
6182
/**
6183
@class moxie/runtime/html5/file/Blob
6184
@private
6185
*/
6186
define("moxie/runtime/html5/file/Blob", [
6187
        "moxie/runtime/html5/Runtime",
6188
        "moxie/file/Blob"
6189
], function(extensions, Blob) {
6190
 
6191
        function HTML5Blob() {
6192
                function w3cBlobSlice(blob, start, end) {
6193
                        var blobSlice;
6194
 
6195
                        if (window.File.prototype.slice) {
6196
                                try {
6197
                                        blob.slice();   // depricated version will throw WRONG_ARGUMENTS_ERR exception
6198
                                        return blob.slice(start, end);
6199
                                } catch (e) {
6200
                                        // depricated slice method
6201
                                        return blob.slice(start, end - start);
6202
                                }
6203
                        // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672
6204
                        } else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) {
6205
                                return blobSlice.call(blob, start, end);
6206
                        } else {
6207
                                return null; // or throw some exception
6208
                        }
6209
                }
6210
 
6211
                this.slice = function() {
6212
                        return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments));
6213
                };
6214
        }
6215
 
6216
        return (extensions.Blob = HTML5Blob);
6217
});
6218
 
6219
// Included from: src/javascript/core/utils/Events.js
6220
 
6221
/**
6222
 * Events.js
6223
 *
6224
 * Copyright 2013, Moxiecode Systems AB
6225
 * Released under GPL License.
6226
 *
6227
 * License: http://www.plupload.com/license
6228
 * Contributing: http://www.plupload.com/contributing
6229
 */
6230
 
6231
define('moxie/core/utils/Events', [
6232
        'moxie/core/utils/Basic'
6233
], function(Basic) {
6234
        var eventhash = {}, uid = 'moxie_' + Basic.guid();
6235
 
6236
        // IE W3C like event funcs
6237
        function preventDefault() {
6238
                this.returnValue = false;
6239
        }
6240
 
6241
        function stopPropagation() {
6242
                this.cancelBubble = true;
6243
        }
6244
 
6245
        /**
6246
        Adds an event handler to the specified object and store reference to the handler
6247
        in objects internal Plupload registry (@see removeEvent).
6248
 
6249
        @method addEvent
6250
        @for Utils
6251
        @static
6252
        @param {Object} obj DOM element like object to add handler to.
6253
        @param {String} name Name to add event listener to.
6254
        @param {Function} callback Function to call when event occurs.
6255
        @param {String} [key] that might be used to add specifity to the event record.
6256
        */
6257
        var addEvent = function(obj, name, callback, key) {
6258
                var func, events;
6259
 
6260
                name = name.toLowerCase();
6261
 
6262
                // Add event listener
6263
                if (obj.addEventListener) {
6264
                        func = callback;
6265
 
6266
                        obj.addEventListener(name, func, false);
6267
                } else if (obj.attachEvent) {
6268
                        func = function() {
6269
                                var evt = window.event;
6270
 
6271
                                if (!evt.target) {
6272
                                        evt.target = evt.srcElement;
6273
                                }
6274
 
6275
                                evt.preventDefault = preventDefault;
6276
                                evt.stopPropagation = stopPropagation;
6277
 
6278
                                callback(evt);
6279
                        };
6280
 
6281
                        obj.attachEvent('on' + name, func);
6282
                }
6283
 
6284
                // Log event handler to objects internal mOxie registry
6285
                if (!obj[uid]) {
6286
                        obj[uid] = Basic.guid();
6287
                }
6288
 
6289
                if (!eventhash.hasOwnProperty(obj[uid])) {
6290
                        eventhash[obj[uid]] = {};
6291
                }
6292
 
6293
                events = eventhash[obj[uid]];
6294
 
6295
                if (!events.hasOwnProperty(name)) {
6296
                        events[name] = [];
6297
                }
6298
 
6299
                events[name].push({
6300
                        func: func,
6301
                        orig: callback, // store original callback for IE
6302
                        key: key
6303
                });
6304
        };
6305
 
6306
 
6307
        /**
6308
        Remove event handler from the specified object. If third argument (callback)
6309
        is not specified remove all events with the specified name.
6310
 
6311
        @method removeEvent
6312
        @static
6313
        @param {Object} obj DOM element to remove event listener(s) from.
6314
        @param {String} name Name of event listener to remove.
6315
        @param {Function|String} [callback] might be a callback or unique key to match.
6316
        */
6317
        var removeEvent = function(obj, name, callback) {
6318
                var type, undef;
6319
 
6320
                name = name.toLowerCase();
6321
 
6322
                if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) {
6323
                        type = eventhash[obj[uid]][name];
6324
                } else {
6325
                        return;
6326
                }
6327
 
6328
                for (var i = type.length - 1; i >= 0; i--) {
6329
                        // undefined or not, key should match
6330
                        if (type[i].orig === callback || type[i].key === callback) {
6331
                                if (obj.removeEventListener) {
6332
                                        obj.removeEventListener(name, type[i].func, false);
6333
                                } else if (obj.detachEvent) {
6334
                                        obj.detachEvent('on'+name, type[i].func);
6335
                                }
6336
 
6337
                                type[i].orig = null;
6338
                                type[i].func = null;
6339
                                type.splice(i, 1);
6340
 
6341
                                // If callback was passed we are done here, otherwise proceed
6342
                                if (callback !== undef) {
6343
                                        break;
6344
                                }
6345
                        }
6346
                }
6347
 
6348
                // If event array got empty, remove it
6349
                if (!type.length) {
6350
                        delete eventhash[obj[uid]][name];
6351
                }
6352
 
6353
                // If mOxie registry has become empty, remove it
6354
                if (Basic.isEmptyObj(eventhash[obj[uid]])) {
6355
                        delete eventhash[obj[uid]];
6356
 
6357
                        // IE doesn't let you remove DOM object property with - delete
6358
                        try {
6359
                                delete obj[uid];
6360
                        } catch(e) {
6361
                                obj[uid] = undef;
6362
                        }
6363
                }
6364
        };
6365
 
6366
 
6367
        /**
6368
        Remove all kind of events from the specified object
6369
 
6370
        @method removeAllEvents
6371
        @static
6372
        @param {Object} obj DOM element to remove event listeners from.
6373
        @param {String} [key] unique key to match, when removing events.
6374
        */
6375
        var removeAllEvents = function(obj, key) {             
6376
                if (!obj || !obj[uid]) {
6377
                        return;
6378
                }
6379
 
6380
                Basic.each(eventhash[obj[uid]], function(events, name) {
6381
                        removeEvent(obj, name, key);
6382
                });
6383
        };
6384
 
6385
        return {
6386
                addEvent: addEvent,
6387
                removeEvent: removeEvent,
6388
                removeAllEvents: removeAllEvents
6389
        };
6390
});
6391
 
6392
// Included from: src/javascript/runtime/html5/file/FileInput.js
6393
 
6394
/**
6395
 * FileInput.js
6396
 *
6397
 * Copyright 2013, Moxiecode Systems AB
6398
 * Released under GPL License.
6399
 *
6400
 * License: http://www.plupload.com/license
6401
 * Contributing: http://www.plupload.com/contributing
6402
 */
6403
 
6404
/**
6405
@class moxie/runtime/html5/file/FileInput
6406
@private
6407
*/
6408
define("moxie/runtime/html5/file/FileInput", [
6409
        "moxie/runtime/html5/Runtime",
6410
        "moxie/core/utils/Basic",
6411
        "moxie/core/utils/Dom",
6412
        "moxie/core/utils/Events",
6413
        "moxie/core/utils/Mime",
6414
        "moxie/core/utils/Env"
6415
], function(extensions, Basic, Dom, Events, Mime, Env) {
6416
 
6417
        function FileInput() {
6418
                var _files = [], _options;
6419
 
6420
                Basic.extend(this, {
6421
                        init: function(options) {
6422
                                var comp = this, I = comp.getRuntime(), input, shimContainer, mimes, browseButton, zIndex, top;
6423
 
6424
                                _options = options;
6425
                                _files = [];
6426
 
6427
                                // figure out accept string
6428
                                mimes = _options.accept.mimes || Mime.extList2mimes(_options.accept, I.can('filter_by_extension'));
6429
 
6430
                                shimContainer = I.getShimContainer();
6431
 
6432
                                shimContainer.innerHTML = '<input id="' + I.uid +'" type="file" style="font-size:999px;opacity:0;"' +
6433
                                        (_options.multiple && I.can('select_multiple') ? 'multiple' : '') +
6434
                                        (_options.directory && I.can('select_folder') ? 'webkitdirectory directory' : '') + // Chrome 11+
6435
                                        (mimes ? ' accept="' + mimes.join(',') + '"' : '') + ' />';
6436
 
6437
                                input = Dom.get(I.uid);
6438
 
6439
                                // prepare file input to be placed underneath the browse_button element
6440
                                Basic.extend(input.style, {
6441
                                        position: 'absolute',
6442
                                        top: 0,
6443
                                        left: 0,
6444
                                        width: '100%',
6445
                                        height: '100%'
6446
                                });
6447
 
6448
 
6449
                                browseButton = Dom.get(_options.browse_button);
6450
 
6451
                                // Route click event to the input[type=file] element for browsers that support such behavior
6452
                                if (I.can('summon_file_dialog')) {
6453
                                        if (Dom.getStyle(browseButton, 'position') === 'static') {
6454
                                                browseButton.style.position = 'relative';
6455
                                        }
6456
 
6457
                                        zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1;
6458
 
6459
                                        browseButton.style.zIndex = zIndex;
6460
                                        shimContainer.style.zIndex = zIndex - 1;
6461
 
6462
                                        Events.addEvent(browseButton, 'click', function(e) {
6463
                                                var input = Dom.get(I.uid);
6464
                                                if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
6465
                                                        input.click();
6466
                                                }
6467
                                                e.preventDefault();
6468
                                        }, comp.uid);
6469
                                }
6470
 
6471
                                /* Since we have to place input[type=file] on top of the browse_button for some browsers,
6472
                                browse_button loses interactivity, so we restore it here */
6473
                                top = I.can('summon_file_dialog') ? browseButton : shimContainer;
6474
 
6475
                                Events.addEvent(top, 'mouseover', function() {
6476
                                        comp.trigger('mouseenter');
6477
                                }, comp.uid);
6478
 
6479
                                Events.addEvent(top, 'mouseout', function() {
6480
                                        comp.trigger('mouseleave');
6481
                                }, comp.uid);
6482
 
6483
                                Events.addEvent(top, 'mousedown', function() {
6484
                                        comp.trigger('mousedown');
6485
                                }, comp.uid);
6486
 
6487
                                Events.addEvent(Dom.get(_options.container), 'mouseup', function() {
6488
                                        comp.trigger('mouseup');
6489
                                }, comp.uid);
6490
 
6491
 
6492
                                input.onchange = function onChange() { // there should be only one handler for this
6493
                                        _files = [];
6494
 
6495
                                        if (_options.directory) {
6496
                                                // folders are represented by dots, filter them out (Chrome 11+)
6497
                                                Basic.each(this.files, function(file) {
6498
                                                        if (file.name !== ".") { // if it doesn't looks like a folder
6499
                                                                _files.push(file);
6500
                                                        }
6501
                                                });
6502
                                        } else {
6503
                                                _files = [].slice.call(this.files);
6504
                                        }
6505
 
6506
                                        // clearing the value enables the user to select the same file again if they want to
6507
                                        if (Env.browser !== 'IE' && Env.browser !== 'IEMobile') {
6508
                                                this.value = '';
6509
                                        } else {
6510
                                                // in IE input[type="file"] is read-only so the only way to reset it is to re-insert it
6511
                                                var clone = this.cloneNode(true);
6512
                                                this.parentNode.replaceChild(clone, this);
6513
                                                clone.onchange = onChange;
6514
                                        }
6515
                                        comp.trigger('change');
6516
                                };
6517
 
6518
                                // ready event is perfectly asynchronous
6519
                                comp.trigger({
6520
                                        type: 'ready',
6521
                                        async: true
6522
                                });
6523
 
6524
                                shimContainer = null;
6525
                        },
6526
 
6527
                        getFiles: function() {
6528
                                return _files;
6529
                        },
6530
 
6531
                        disable: function(state) {
6532
                                var I = this.getRuntime(), input;
6533
 
6534
                                if ((input = Dom.get(I.uid))) {
6535
                                        input.disabled = !!state;
6536
                                }
6537
                        },
6538
 
6539
                        destroy: function() {
6540
                                var I = this.getRuntime()
6541
                                , shim = I.getShim()
6542
                                , shimContainer = I.getShimContainer()
6543
                                ;
6544
 
6545
                                Events.removeAllEvents(shimContainer, this.uid);
6546
                                Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
6547
                                Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid);
6548
 
6549
                                if (shimContainer) {
6550
                                        shimContainer.innerHTML = '';
6551
                                }
6552
 
6553
                                shim.removeInstance(this.uid);
6554
 
6555
                                _files = _options = shimContainer = shim = null;
6556
                        }
6557
                });
6558
        }
6559
 
6560
        return (extensions.FileInput = FileInput);
6561
});
6562
 
6563
// Included from: src/javascript/runtime/html5/file/FileDrop.js
6564
 
6565
/**
6566
 * FileDrop.js
6567
 *
6568
 * Copyright 2013, Moxiecode Systems AB
6569
 * Released under GPL License.
6570
 *
6571
 * License: http://www.plupload.com/license
6572
 * Contributing: http://www.plupload.com/contributing
6573
 */
6574
 
6575
/**
6576
@class moxie/runtime/html5/file/FileDrop
6577
@private
6578
*/
6579
define("moxie/runtime/html5/file/FileDrop", [
6580
        "moxie/runtime/html5/Runtime",
6581
        "moxie/core/utils/Basic",
6582
        "moxie/core/utils/Dom",
6583
        "moxie/core/utils/Events",
6584
        "moxie/core/utils/Mime"
6585
], function(extensions, Basic, Dom, Events, Mime) {
6586
 
6587
        function FileDrop() {
6588
                var _files = [], _allowedExts = [], _options;
6589
 
6590
                Basic.extend(this, {
6591
                        init: function(options) {
6592
                                var comp = this, dropZone;
6593
 
6594
                                _options = options;
6595
                                _allowedExts = _extractExts(_options.accept);
6596
                                dropZone = _options.container;
6597
 
6598
                                Events.addEvent(dropZone, 'dragover', function(e) {
6599
                                        if (!_hasFiles(e)) {
6600
                                                return;
6601
                                        }
6602
                                        e.preventDefault();
6603
                                        e.dataTransfer.dropEffect = 'copy';
6604
                                }, comp.uid);
6605
 
6606
                                Events.addEvent(dropZone, 'drop', function(e) {
6607
                                        if (!_hasFiles(e)) {
6608
                                                return;
6609
                                        }
6610
                                        e.preventDefault();
6611
 
6612
                                        _files = [];
6613
 
6614
                                        // Chrome 21+ accepts folders via Drag'n'Drop
6615
                                        if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) {
6616
                                                _readItems(e.dataTransfer.items, function() {
6617
                                                        comp.trigger("drop");
6618
                                                });
6619
                                        } else {
6620
                                                Basic.each(e.dataTransfer.files, function(file) {
6621
                                                        if (_isAcceptable(file)) {
6622
                                                                _files.push(file);
6623
                                                        }
6624
                                                });
6625
                                                comp.trigger("drop");
6626
                                        }
6627
                                }, comp.uid);
6628
 
6629
                                Events.addEvent(dropZone, 'dragenter', function(e) {
6630
                                        comp.trigger("dragenter");
6631
                                }, comp.uid);
6632
 
6633
                                Events.addEvent(dropZone, 'dragleave', function(e) {
6634
                                        comp.trigger("dragleave");
6635
                                }, comp.uid);
6636
                        },
6637
 
6638
                        getFiles: function() {
6639
                                return _files;
6640
                        },
6641
 
6642
                        destroy: function() {
6643
                                Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
6644
                                _files = _allowedExts = _options = null;
6645
                        }
6646
                });
6647
 
6648
 
6649
                function _hasFiles(e) {
6650
                        if (!e.dataTransfer || !e.dataTransfer.types) { // e.dataTransfer.files is not available in Gecko during dragover
6651
                                return false;
6652
                        }
6653
 
6654
                        var types = Basic.toArray(e.dataTransfer.types || []);
6655
 
6656
                        return Basic.inArray("Files", types) !== -1 ||
6657
                                Basic.inArray("public.file-url", types) !== -1 || // Safari < 5
6658
                                Basic.inArray("application/x-moz-file", types) !== -1 // Gecko < 1.9.2 (< Firefox 3.6)
6659
                                ;
6660
                }
6661
 
6662
 
6663
                function _extractExts(accept) {
6664
                        var exts = [];
6665
                        for (var i = 0; i < accept.length; i++) {
6666
                                [].push.apply(exts, accept[i].extensions.split(/\s*,\s*/));
6667
                        }
6668
                        return Basic.inArray('*', exts) === -1 ? exts : [];
6669
                }
6670
 
6671
 
6672
                function _isAcceptable(file) {
6673
                        if (!_allowedExts.length) {
6674
                                return true;
6675
                        }
6676
                        var ext = Mime.getFileExtension(file.name);
6677
                        return !ext || Basic.inArray(ext, _allowedExts) !== -1;
6678
                }
6679
 
6680
 
6681
                function _readItems(items, cb) {
6682
                        var entries = [];
6683
                        Basic.each(items, function(item) {
6684
                                var entry = item.webkitGetAsEntry();
6685
                                // Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579)
6686
                                if (entry) {
6687
                                        // file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61
6688
                                        if (entry.isFile) {
6689
                                                var file = item.getAsFile();
6690
                                                if (_isAcceptable(file)) {
6691
                                                        _files.push(file);
6692
                                                }
6693
                                        } else {
6694
                                                entries.push(entry);
6695
                                        }
6696
                                }
6697
                        });
6698
 
6699
                        if (entries.length) {
6700
                                _readEntries(entries, cb);
6701
                        } else {
6702
                                cb();
6703
                        }
6704
                }
6705
 
6706
 
6707
                function _readEntries(entries, cb) {
6708
                        var queue = [];
6709
                        Basic.each(entries, function(entry) {
6710
                                queue.push(function(cbcb) {
6711
                                        _readEntry(entry, cbcb);
6712
                                });
6713
                        });
6714
                        Basic.inSeries(queue, function() {
6715
                                cb();
6716
                        });
6717
                }
6718
 
6719
 
6720
                function _readEntry(entry, cb) {
6721
                        if (entry.isFile) {
6722
                                entry.file(function(file) {
6723
                                        if (_isAcceptable(file)) {
6724
                                                _files.push(file);
6725
                                        }
6726
                                        cb();
6727
                                }, function() {
6728
                                        // fire an error event maybe
6729
                                        cb();
6730
                                });
6731
                        } else if (entry.isDirectory) {
6732
                                _readDirEntry(entry, cb);
6733
                        } else {
6734
                                cb(); // not file, not directory? what then?..
6735
                        }
6736
                }
6737
 
6738
 
6739
                function _readDirEntry(dirEntry, cb) {
6740
                        var entries = [], dirReader = dirEntry.createReader();
6741
 
6742
                        // keep quering recursively till no more entries
6743
                        function getEntries(cbcb) {
6744
                                dirReader.readEntries(function(moreEntries) {
6745
                                        if (moreEntries.length) {
6746
                                                [].push.apply(entries, moreEntries);
6747
                                                getEntries(cbcb);
6748
                                        } else {
6749
                                                cbcb();
6750
                                        }
6751
                                }, cbcb);
6752
                        }
6753
 
6754
                        // ...and you thought FileReader was crazy...
6755
                        getEntries(function() {
6756
                                _readEntries(entries, cb);
6757
                        });
6758
                }
6759
        }
6760
 
6761
        return (extensions.FileDrop = FileDrop);
6762
});
6763
 
6764
// Included from: src/javascript/runtime/html5/file/FileReader.js
6765
 
6766
/**
6767
 * FileReader.js
6768
 *
6769
 * Copyright 2013, Moxiecode Systems AB
6770
 * Released under GPL License.
6771
 *
6772
 * License: http://www.plupload.com/license
6773
 * Contributing: http://www.plupload.com/contributing
6774
 */
6775
 
6776
/**
6777
@class moxie/runtime/html5/file/FileReader
6778
@private
6779
*/
6780
define("moxie/runtime/html5/file/FileReader", [
6781
        "moxie/runtime/html5/Runtime",
6782
        "moxie/core/utils/Encode",
6783
        "moxie/core/utils/Basic"
6784
], function(extensions, Encode, Basic) {
6785
 
6786
        function FileReader() {
6787
                var _fr, _convertToBinary = false;
6788
 
6789
                Basic.extend(this, {
6790
 
6791
                        read: function(op, blob) {
6792
                                var target = this;
6793
 
6794
                                _fr = new window.FileReader();
6795
 
6796
                                _fr.addEventListener('progress', function(e) {
6797
                                        target.trigger(e);
6798
                                });
6799
 
6800
                                _fr.addEventListener('load', function(e) {
6801
                                        target.trigger(e);
6802
                                });
6803
 
6804
                                _fr.addEventListener('error', function(e) {
6805
                                        target.trigger(e, _fr.error);
6806
                                });
6807
 
6808
                                _fr.addEventListener('loadend', function() {
6809
                                        _fr = null;
6810
                                });
6811
 
6812
                                if (Basic.typeOf(_fr[op]) === 'function') {
6813
                                        _convertToBinary = false;
6814
                                        _fr[op](blob.getSource());
6815
                                } else if (op === 'readAsBinaryString') { // readAsBinaryString is depricated in general and never existed in IE10+
6816
                                        _convertToBinary = true;
6817
                                        _fr.readAsDataURL(blob.getSource());
6818
                                }
6819
                        },
6820
 
6821
                        getResult: function() {
6822
                                return _fr && _fr.result ? (_convertToBinary ? _toBinary(_fr.result) : _fr.result) : null;
6823
                        },
6824
 
6825
                        abort: function() {
6826
                                if (_fr) {
6827
                                        _fr.abort();
6828
                                }
6829
                        },
6830
 
6831
                        destroy: function() {
6832
                                _fr = null;
6833
                        }
6834
                });
6835
 
6836
                function _toBinary(str) {
6837
                        return Encode.atob(str.substring(str.indexOf('base64,') + 7));
6838
                }
6839
        }
6840
 
6841
        return (extensions.FileReader = FileReader);
6842
});
6843
 
6844
// Included from: src/javascript/runtime/html5/xhr/XMLHttpRequest.js
6845
 
6846
/**
6847
 * XMLHttpRequest.js
6848
 *
6849
 * Copyright 2013, Moxiecode Systems AB
6850
 * Released under GPL License.
6851
 *
6852
 * License: http://www.plupload.com/license
6853
 * Contributing: http://www.plupload.com/contributing
6854
 */
6855
 
6856
/*global ActiveXObject:true */
6857
 
6858
/**
6859
@class moxie/runtime/html5/xhr/XMLHttpRequest
6860
@private
6861
*/
6862
define("moxie/runtime/html5/xhr/XMLHttpRequest", [
6863
        "moxie/runtime/html5/Runtime",
6864
        "moxie/core/utils/Basic",
6865
        "moxie/core/utils/Mime",
6866
        "moxie/core/utils/Url",
6867
        "moxie/file/File",
6868
        "moxie/file/Blob",
6869
        "moxie/xhr/FormData",
6870
        "moxie/core/Exceptions",
6871
        "moxie/core/utils/Env"
6872
], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) {
6873
 
6874
        function XMLHttpRequest() {
6875
                var self = this
6876
                , _xhr
6877
                , _filename
6878
                ;
6879
 
6880
                Basic.extend(this, {
6881
                        send: function(meta, data) {
6882
                                var target = this
6883
                                , isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.version >= 4 && Env.version < 7)
6884
                                , isAndroidBrowser = Env.browser === 'Android Browser'
6885
                                , mustSendAsBinary = false
6886
                                ;
6887
 
6888
                                // extract file name
6889
                                _filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase();
6890
 
6891
                                _xhr = _getNativeXHR();
6892
                                _xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password);
6893
 
6894
 
6895
                                // prepare data to be sent
6896
                                if (data instanceof Blob) {
6897
                                        if (data.isDetached()) {
6898
                                                mustSendAsBinary = true;
6899
                                        }
6900
                                        data = data.getSource();
6901
                                } else if (data instanceof FormData) {
6902
 
6903
                                        if (data.hasBlob()) {
6904
                                                if (data.getBlob().isDetached()) {
6905
                                                        data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state
6906
                                                        mustSendAsBinary = true;
6907
                                                } else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) {
6908
                                                        // Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150
6909
                                                        // Android browsers (default one and Dolphin) seem to have the same issue, see: #613
6910
                                                        _preloadAndSend.call(target, meta, data);
6911
                                                        return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D
6912
                                                }      
6913
                                        }
6914
 
6915
                                        // transfer fields to real FormData
6916
                                        if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart()
6917
                                                var fd = new window.FormData();
6918
                                                data.each(function(value, name) {
6919
                                                        if (value instanceof Blob) {
6920
                                                                fd.append(name, value.getSource());
6921
                                                        } else {
6922
                                                                fd.append(name, value);
6923
                                                        }
6924
                                                });
6925
                                                data = fd;
6926
                                        }
6927
                                }
6928
 
6929
 
6930
                                // if XHR L2
6931
                                if (_xhr.upload) {
6932
                                        if (meta.withCredentials) {
6933
                                                _xhr.withCredentials = true;
6934
                                        }
6935
 
6936
                                        _xhr.addEventListener('load', function(e) {
6937
                                                target.trigger(e);
6938
                                        });
6939
 
6940
                                        _xhr.addEventListener('error', function(e) {
6941
                                                target.trigger(e);
6942
                                        });
6943
 
6944
                                        // additionally listen to progress events
6945
                                        _xhr.addEventListener('progress', function(e) {
6946
                                                target.trigger(e);
6947
                                        });
6948
 
6949
                                        _xhr.upload.addEventListener('progress', function(e) {
6950
                                                target.trigger({
6951
                                                        type: 'UploadProgress',
6952
                                                        loaded: e.loaded,
6953
                                                        total: e.total
6954
                                                });
6955
                                        });
6956
                                // ... otherwise simulate XHR L2
6957
                                } else {
6958
                                        _xhr.onreadystatechange = function onReadyStateChange() {
6959
 
6960
                                                // fake Level 2 events
6961
                                                switch (_xhr.readyState) {
6962
 
6963
                                                        case 1: // XMLHttpRequest.OPENED
6964
                                                                // readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu
6965
                                                                break;
6966
 
6967
                                                        // looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu
6968
                                                        case 2: // XMLHttpRequest.HEADERS_RECEIVED
6969
                                                                break;
6970
 
6971
                                                        case 3: // XMLHttpRequest.LOADING
6972
                                                                // try to fire progress event for not XHR L2
6973
                                                                var total, loaded;
6974
 
6975
                                                                try {
6976
                                                                        if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers
6977
                                                                                total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here
6978
                                                                        }
6979
 
6980
                                                                        if (_xhr.responseText) { // responseText was introduced in IE7
6981
                                                                                loaded = _xhr.responseText.length;
6982
                                                                        }
6983
                                                                } catch(ex) {
6984
                                                                        total = loaded = 0;
6985
                                                                }
6986
 
6987
                                                                target.trigger({
6988
                                                                        type: 'progress',
6989
                                                                        lengthComputable: !!total,
6990
                                                                        total: parseInt(total, 10),
6991
                                                                        loaded: loaded
6992
                                                                });
6993
                                                                break;
6994
 
6995
                                                        case 4: // XMLHttpRequest.DONE
6996
                                                                // release readystatechange handler (mostly for IE)
6997
                                                                _xhr.onreadystatechange = function() {};
6998
 
6999
                                                                // usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout
7000
                                                                if (_xhr.status === 0) {
7001
                                                                        target.trigger('error');
7002
                                                                } else {
7003
                                                                        target.trigger('load');
7004
                                                                }                                                      
7005
                                                                break;
7006
                                                }
7007
                                        };
7008
                                }
7009
 
7010
 
7011
                                // set request headers
7012
                                if (!Basic.isEmptyObj(meta.headers)) {
7013
                                        Basic.each(meta.headers, function(value, header) {
7014
                                                _xhr.setRequestHeader(header, value);
7015
                                        });
7016
                                }
7017
 
7018
                                // request response type
7019
                                if ("" !== meta.responseType && 'responseType' in _xhr) {
7020
                                        if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one
7021
                                                _xhr.responseType = 'text';
7022
                                        } else {
7023
                                                _xhr.responseType = meta.responseType;
7024
                                        }
7025
                                }
7026
 
7027
                                // send ...
7028
                                if (!mustSendAsBinary) {
7029
                                        _xhr.send(data);
7030
                                } else {
7031
                                        if (_xhr.sendAsBinary) { // Gecko
7032
                                                _xhr.sendAsBinary(data);
7033
                                        } else { // other browsers having support for typed arrays
7034
                                                (function() {
7035
                                                        // mimic Gecko's sendAsBinary
7036
                                                        var ui8a = new Uint8Array(data.length);
7037
                                                        for (var i = 0; i < data.length; i++) {
7038
                                                                ui8a[i] = (data.charCodeAt(i) & 0xff);
7039
                                                        }
7040
                                                        _xhr.send(ui8a.buffer);
7041
                                                }());
7042
                                        }
7043
                                }
7044
 
7045
                                target.trigger('loadstart');
7046
                        },
7047
 
7048
                        getStatus: function() {
7049
                                // according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception
7050
                                try {
7051
                                        if (_xhr) {
7052
                                                return _xhr.status;
7053
                                        }
7054
                                } catch(ex) {}
7055
                                return 0;
7056
                        },
7057
 
7058
                        getResponse: function(responseType) {
7059
                                var I = this.getRuntime();
7060
 
7061
                                try {
7062
                                        switch (responseType) {
7063
                                                case 'blob':
7064
                                                        var file = new File(I.uid, _xhr.response);
7065
 
7066
                                                        // try to extract file name from content-disposition if possible (might be - not, if CORS for example) 
7067
                                                        var disposition = _xhr.getResponseHeader('Content-Disposition');
7068
                                                        if (disposition) {
7069
                                                                // extract filename from response header if available
7070
                                                                var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/);
7071
                                                                if (match) {
7072
                                                                        _filename = match[2];
7073
                                                                }
7074
                                                        }
7075
                                                        file.name = _filename;
7076
 
7077
                                                        // pre-webkit Opera doesn't set type property on the blob response
7078
                                                        if (!file.type) {
7079
                                                                file.type = Mime.getFileMime(_filename);
7080
                                                        }
7081
                                                        return file;
7082
 
7083
                                                case 'json':
7084
                                                        if (!Env.can('return_response_type', 'json')) {
7085
                                                                return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null;
7086
                                                        }
7087
                                                        return _xhr.response;
7088
 
7089
                                                case 'document':
7090
                                                        return _getDocument(_xhr);
7091
 
7092
                                                default:
7093
                                                        return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes
7094
                                        }
7095
                                } catch(ex) {
7096
                                        return null;
7097
                                }                              
7098
                        },
7099
 
7100
                        getAllResponseHeaders: function() {
7101
                                try {
7102
                                        return _xhr.getAllResponseHeaders();
7103
                                } catch(ex) {}
7104
                                return '';
7105
                        },
7106
 
7107
                        abort: function() {
7108
                                if (_xhr) {
7109
                                        _xhr.abort();
7110
                                }
7111
                        },
7112
 
7113
                        destroy: function() {
7114
                                self = _filename = null;
7115
                        }
7116
                });
7117
 
7118
 
7119
                // here we go... ugly fix for ugly bug
7120
                function _preloadAndSend(meta, data) {
7121
                        var target = this, blob, fr;
7122
 
7123
                        // get original blob
7124
                        blob = data.getBlob().getSource();
7125
 
7126
                        // preload blob in memory to be sent as binary string
7127
                        fr = new window.FileReader();
7128
                        fr.onload = function() {
7129
                                // overwrite original blob
7130
                                data.append(data.getBlobName(), new Blob(null, {
7131
                                        type: blob.type,
7132
                                        data: fr.result
7133
                                }));
7134
                                // invoke send operation again
7135
                                self.send.call(target, meta, data);
7136
                        };
7137
                        fr.readAsBinaryString(blob);
7138
                }
7139
 
7140
 
7141
                function _getNativeXHR() {
7142
                        if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.version < 8)) { // IE7 has native XHR but it's buggy
7143
                                return new window.XMLHttpRequest();
7144
                        } else {
7145
                                return (function() {
7146
                                        var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0
7147
                                        for (var i = 0; i < progIDs.length; i++) {
7148
                                                try {
7149
                                                        return new ActiveXObject(progIDs[i]);
7150
                                                } catch (ex) {}
7151
                                        }
7152
                                })();
7153
                        }
7154
                }
7155
 
7156
                // @credits Sergey Ilinsky      (http://www.ilinsky.com/)
7157
                function _getDocument(xhr) {
7158
                        var rXML = xhr.responseXML;
7159
                        var rText = xhr.responseText;
7160
 
7161
                        // Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type)
7162
                        if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) {
7163
                                rXML = new window.ActiveXObject("Microsoft.XMLDOM");
7164
                                rXML.async = false;
7165
                                rXML.validateOnParse = false;
7166
                                rXML.loadXML(rText);
7167
                        }
7168
 
7169
                        // Check if there is no error in document
7170
                        if (rXML) {
7171
                                if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") {
7172
                                        return null;
7173
                                }
7174
                        }
7175
                        return rXML;
7176
                }
7177
 
7178
 
7179
                function _prepareMultipart(fd) {
7180
                        var boundary = '----moxieboundary' + new Date().getTime()
7181
                        , dashdash = '--'
7182
                        , crlf = '\r\n'
7183
                        , multipart = ''
7184
                        , I = this.getRuntime()
7185
                        ;
7186
 
7187
                        if (!I.can('send_binary_string')) {
7188
                                throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
7189
                        }
7190
 
7191
                        _xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
7192
 
7193
                        // append multipart parameters
7194
                        fd.each(function(value, name) {
7195
                                // Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(),
7196
                                // so we try it here ourselves with: unescape(encodeURIComponent(value))
7197
                                if (value instanceof Blob) {
7198
                                        // Build RFC2388 blob
7199
                                        multipart += dashdash + boundary + crlf +
7200
                                                'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf +
7201
                                                'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf +
7202
                                                value.getSource() + crlf;
7203
                                } else {
7204
                                        multipart += dashdash + boundary + crlf +
7205
                                                'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf +
7206
                                                unescape(encodeURIComponent(value)) + crlf;
7207
                                }
7208
                        });
7209
 
7210
                        multipart += dashdash + boundary + dashdash + crlf;
7211
 
7212
                        return multipart;
7213
                }
7214
        }
7215
 
7216
        return (extensions.XMLHttpRequest = XMLHttpRequest);
7217
});
7218
 
7219
// Included from: src/javascript/runtime/html5/utils/BinaryReader.js
7220
 
7221
/**
7222
 * BinaryReader.js
7223
 *
7224
 * Copyright 2013, Moxiecode Systems AB
7225
 * Released under GPL License.
7226
 *
7227
 * License: http://www.plupload.com/license
7228
 * Contributing: http://www.plupload.com/contributing
7229
 */
7230
 
7231
/**
7232
@class moxie/runtime/html5/utils/BinaryReader
7233
@private
7234
*/
7235
define("moxie/runtime/html5/utils/BinaryReader", [], function() {
7236
        return function() {
7237
                var II = false, bin;
7238
 
7239
                // Private functions
7240
                function read(idx, size) {
7241
                        var mv = II ? 0 : -8 * (size - 1), sum = 0, i;
7242
 
7243
                        for (i = 0; i < size; i++) {
7244
                                sum |= (bin.charCodeAt(idx + i) << Math.abs(mv + i*8));
7245
                        }
7246
 
7247
                        return sum;
7248
                }
7249
 
7250
                function putstr(segment, idx, length) {
7251
                        length = arguments.length === 3 ? length : bin.length - idx - 1;
7252
                        bin = bin.substr(0, idx) + segment + bin.substr(length + idx);
7253
                }
7254
 
7255
                function write(idx, num, size) {
7256
                        var str = '', mv = II ? 0 : -8 * (size - 1), i;
7257
 
7258
                        for (i = 0; i < size; i++) {
7259
                                str += String.fromCharCode((num >> Math.abs(mv + i*8)) & 255);
7260
                        }
7261
 
7262
                        putstr(str, idx, size);
7263
                }
7264
 
7265
                // Public functions
7266
                return {
7267
                        II: function(order) {
7268
                                if (order === undefined) {
7269
                                        return II;
7270
                                } else {
7271
                                        II = order;
7272
                                }
7273
                        },
7274
 
7275
                        init: function(binData) {
7276
                                II = false;
7277
                                bin = binData;
7278
                        },
7279
 
7280
                        SEGMENT: function(idx, length, segment) {
7281
                                switch (arguments.length) {
7282
                                        case 1:
7283
                                                return bin.substr(idx, bin.length - idx - 1);
7284
                                        case 2:
7285
                                                return bin.substr(idx, length);
7286
                                        case 3:
7287
                                                putstr(segment, idx, length);
7288
                                                break;
7289
                                        default: return bin;
7290
                                }
7291
                        },
7292
 
7293
                        BYTE: function(idx) {
7294
                                return read(idx, 1);
7295
                        },
7296
 
7297
                        SHORT: function(idx) {
7298
                                return read(idx, 2);
7299
                        },
7300
 
7301
                        LONG: function(idx, num) {
7302
                                if (num === undefined) {
7303
                                        return read(idx, 4);
7304
                                } else {
7305
                                        write(idx, num, 4);
7306
                                }
7307
                        },
7308
 
7309
                        SLONG: function(idx) { // 2's complement notation
7310
                                var num = read(idx, 4);
7311
 
7312
                                return (num > 2147483647 ? num - 4294967296 : num);
7313
                        },
7314
 
7315
                        STRING: function(idx, size) {
7316
                                var str = '';
7317
 
7318
                                for (size += idx; idx < size; idx++) {
7319
                                        str += String.fromCharCode(read(idx, 1));
7320
                                }
7321
 
7322
                                return str;
7323
                        }
7324
                };
7325
        };
7326
});
7327
 
7328
// Included from: src/javascript/runtime/html5/image/JPEGHeaders.js
7329
 
7330
/**
7331
 * JPEGHeaders.js
7332
 *
7333
 * Copyright 2013, Moxiecode Systems AB
7334
 * Released under GPL License.
7335
 *
7336
 * License: http://www.plupload.com/license
7337
 * Contributing: http://www.plupload.com/contributing
7338
 */
7339
 
7340
/**
7341
@class moxie/runtime/html5/image/JPEGHeaders
7342
@private
7343
*/
7344
define("moxie/runtime/html5/image/JPEGHeaders", [
7345
        "moxie/runtime/html5/utils/BinaryReader"
7346
], function(BinaryReader) {
7347
 
7348
        return function JPEGHeaders(data) {
7349
                var headers = [], read, idx, marker, length = 0;
7350
 
7351
                read = new BinaryReader();
7352
                read.init(data);
7353
 
7354
                // Check if data is jpeg
7355
                if (read.SHORT(0) !== 0xFFD8) {
7356
                        return;
7357
                }
7358
 
7359
                idx = 2;
7360
 
7361
                while (idx <= data.length) {
7362
                        marker = read.SHORT(idx);
7363
 
7364
                        // omit RST (restart) markers
7365
                        if (marker >= 0xFFD0 && marker <= 0xFFD7) {
7366
                                idx += 2;
7367
                                continue;
7368
                        }
7369
 
7370
                        // no headers allowed after SOS marker
7371
                        if (marker === 0xFFDA || marker === 0xFFD9) {
7372
                                break;
7373
                        }
7374
 
7375
                        length = read.SHORT(idx + 2) + 2;
7376
 
7377
                        // APPn marker detected
7378
                        if (marker >= 0xFFE1 && marker <= 0xFFEF) {
7379
                                headers.push({
7380
                                        hex: marker,
7381
                                        name: 'APP' + (marker & 0x000F),
7382
                                        start: idx,
7383
                                        length: length,
7384
                                        segment: read.SEGMENT(idx, length)
7385
                                });
7386
                        }
7387
 
7388
                        idx += length;
7389
                }
7390
 
7391
                read.init(null); // free memory
7392
 
7393
                return {
7394
                        headers: headers,
7395
 
7396
                        restore: function(data) {
7397
                                var max, i;
7398
 
7399
                                read.init(data);
7400
 
7401
                                idx = read.SHORT(2) == 0xFFE0 ? 4 + read.SHORT(4) : 2;
7402
 
7403
                                for (i = 0, max = headers.length; i < max; i++) {
7404
                                        read.SEGMENT(idx, 0, headers[i].segment);
7405
                                        idx += headers[i].length;
7406
                                }
7407
 
7408
                                data = read.SEGMENT();
7409
                                read.init(null);
7410
                                return data;
7411
                        },
7412
 
7413
                        strip: function(data) {
7414
                                var headers, jpegHeaders, i;
7415
 
7416
                                jpegHeaders = new JPEGHeaders(data);
7417
                                headers = jpegHeaders.headers;
7418
                                jpegHeaders.purge();
7419
 
7420
                                read.init(data);
7421
 
7422
                                i = headers.length;
7423
                                while (i--) {
7424
                                        read.SEGMENT(headers[i].start, headers[i].length, '');
7425
                                }
7426
 
7427
                                data = read.SEGMENT();
7428
                                read.init(null);
7429
                                return data;
7430
                        },
7431
 
7432
                        get: function(name) {
7433
                                var array = [];
7434
 
7435
                                for (var i = 0, max = headers.length; i < max; i++) {
7436
                                        if (headers[i].name === name.toUpperCase()) {
7437
                                                array.push(headers[i].segment);
7438
                                        }
7439
                                }
7440
                                return array;
7441
                        },
7442
 
7443
                        set: function(name, segment) {
7444
                                var array = [], i, ii, max;
7445
 
7446
                                if (typeof(segment) === 'string') {
7447
                                        array.push(segment);
7448
                                } else {
7449
                                        array = segment;
7450
                                }
7451
 
7452
                                for (i = ii = 0, max = headers.length; i < max; i++) {
7453
                                        if (headers[i].name === name.toUpperCase()) {
7454
                                                headers[i].segment = array[ii];
7455
                                                headers[i].length = array[ii].length;
7456
                                                ii++;
7457
                                        }
7458
                                        if (ii >= array.length) {
7459
                                                break;
7460
                                        }
7461
                                }
7462
                        },
7463
 
7464
                        purge: function() {
7465
                                headers = [];
7466
                                read.init(null);
7467
                                read = null;
7468
                        }
7469
                };
7470
        };
7471
});
7472
 
7473
// Included from: src/javascript/runtime/html5/image/ExifParser.js
7474
 
7475
/**
7476
 * ExifParser.js
7477
 *
7478
 * Copyright 2013, Moxiecode Systems AB
7479
 * Released under GPL License.
7480
 *
7481
 * License: http://www.plupload.com/license
7482
 * Contributing: http://www.plupload.com/contributing
7483
 */
7484
 
7485
/**
7486
@class moxie/runtime/html5/image/ExifParser
7487
@private
7488
*/
7489
define("moxie/runtime/html5/image/ExifParser", [
7490
        "moxie/core/utils/Basic",
7491
        "moxie/runtime/html5/utils/BinaryReader"
7492
], function(Basic, BinaryReader) {
7493
 
7494
        return function ExifParser() {
7495
                // Private ExifParser fields
7496
                var data, tags, Tiff, offsets = {}, tagDescs;
7497
 
7498
                data = new BinaryReader();
7499
 
7500
                tags = {
7501
                        tiff : {
7502
                                /*
7503
                                The image orientation viewed in terms of rows and columns.
7504
 
7505
                                1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
7506
                                2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
7507
                                3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
7508
                                4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
7509
                                5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
7510
                                6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
7511
                                7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
7512
                                8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
7513
                                */
7514
                                0x0112: 'Orientation',
7515
                                0x010E: 'ImageDescription',
7516
                                0x010F: 'Make',
7517
                                0x0110: 'Model',
7518
                                0x0131: 'Software',
7519
                                0x8769: 'ExifIFDPointer',
7520
                                0x8825: 'GPSInfoIFDPointer'
7521
                        },
7522
                        exif : {
7523
                                0x9000: 'ExifVersion',
7524
                                0xA001: 'ColorSpace',
7525
                                0xA002: 'PixelXDimension',
7526
                                0xA003: 'PixelYDimension',
7527
                                0x9003: 'DateTimeOriginal',
7528
                                0x829A: 'ExposureTime',
7529
                                0x829D: 'FNumber',
7530
                                0x8827: 'ISOSpeedRatings',
7531
                                0x9201: 'ShutterSpeedValue',
7532
                                0x9202: 'ApertureValue' ,
7533
                                0x9207: 'MeteringMode',
7534
                                0x9208: 'LightSource',
7535
                                0x9209: 'Flash',
7536
                                0x920A: 'FocalLength',
7537
                                0xA402: 'ExposureMode',
7538
                                0xA403: 'WhiteBalance',
7539
                                0xA406: 'SceneCaptureType',
7540
                                0xA404: 'DigitalZoomRatio',
7541
                                0xA408: 'Contrast',
7542
                                0xA409: 'Saturation',
7543
                                0xA40A: 'Sharpness'
7544
                        },
7545
                        gps : {
7546
                                0x0000: 'GPSVersionID',
7547
                                0x0001: 'GPSLatitudeRef',
7548
                                0x0002: 'GPSLatitude',
7549
                                0x0003: 'GPSLongitudeRef',
7550
                                0x0004: 'GPSLongitude'
7551
                        }
7552
                };
7553
 
7554
                tagDescs = {
7555
                        'ColorSpace': {
7556
                                1: 'sRGB',
7557
                                0: 'Uncalibrated'
7558
                        },
7559
 
7560
                        'MeteringMode': {
7561
                                0: 'Unknown',
7562
                                1: 'Average',
7563
                                2: 'CenterWeightedAverage',
7564
                                3: 'Spot',
7565
                                4: 'MultiSpot',
7566
                                5: 'Pattern',
7567
                                6: 'Partial',
7568
                                255: 'Other'
7569
                        },
7570
 
7571
                        'LightSource': {
7572
                                1: 'Daylight',
7573
                                2: 'Fliorescent',
7574
                                3: 'Tungsten',
7575
                                4: 'Flash',
7576
                                9: 'Fine weather',
7577
                                10: 'Cloudy weather',
7578
                                11: 'Shade',
7579
                                12: 'Daylight fluorescent (D 5700 - 7100K)',
7580
                                13: 'Day white fluorescent (N 4600 -5400K)',
7581
                                14: 'Cool white fluorescent (W 3900 - 4500K)',
7582
                                15: 'White fluorescent (WW 3200 - 3700K)',
7583
                                17: 'Standard light A',
7584
                                18: 'Standard light B',
7585
                                19: 'Standard light C',
7586
                                20: 'D55',
7587
                                21: 'D65',
7588
                                22: 'D75',
7589
                                23: 'D50',
7590
                                24: 'ISO studio tungsten',
7591
                                255: 'Other'
7592
                        },
7593
 
7594
                        'Flash': {
7595
                                0x0000: 'Flash did not fire.',
7596
                                0x0001: 'Flash fired.',
7597
                                0x0005: 'Strobe return light not detected.',
7598
                                0x0007: 'Strobe return light detected.',
7599
                                0x0009: 'Flash fired, compulsory flash mode',
7600
                                0x000D: 'Flash fired, compulsory flash mode, return light not detected',
7601
                                0x000F: 'Flash fired, compulsory flash mode, return light detected',
7602
                                0x0010: 'Flash did not fire, compulsory flash mode',
7603
                                0x0018: 'Flash did not fire, auto mode',
7604
                                0x0019: 'Flash fired, auto mode',
7605
                                0x001D: 'Flash fired, auto mode, return light not detected',
7606
                                0x001F: 'Flash fired, auto mode, return light detected',
7607
                                0x0020: 'No flash function',
7608
                                0x0041: 'Flash fired, red-eye reduction mode',
7609
                                0x0045: 'Flash fired, red-eye reduction mode, return light not detected',
7610
                                0x0047: 'Flash fired, red-eye reduction mode, return light detected',
7611
                                0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode',
7612
                                0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected',
7613
                                0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected',
7614
                                0x0059: 'Flash fired, auto mode, red-eye reduction mode',
7615
                                0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode',
7616
                                0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode'
7617
                        },
7618
 
7619
                        'ExposureMode': {
7620
                                0: 'Auto exposure',
7621
                                1: 'Manual exposure',
7622
                                2: 'Auto bracket'
7623
                        },
7624
 
7625
                        'WhiteBalance': {
7626
                                0: 'Auto white balance',
7627
                                1: 'Manual white balance'
7628
                        },
7629
 
7630
                        'SceneCaptureType': {
7631
                                0: 'Standard',
7632
                                1: 'Landscape',
7633
                                2: 'Portrait',
7634
                                3: 'Night scene'
7635
                        },
7636
 
7637
                        'Contrast': {
7638
                                0: 'Normal',
7639
                                1: 'Soft',
7640
                                2: 'Hard'
7641
                        },
7642
 
7643
                        'Saturation': {
7644
                                0: 'Normal',
7645
                                1: 'Low saturation',
7646
                                2: 'High saturation'
7647
                        },
7648
 
7649
                        'Sharpness': {
7650
                                0: 'Normal',
7651
                                1: 'Soft',
7652
                                2: 'Hard'
7653
                        },
7654
 
7655
                        // GPS related
7656
                        'GPSLatitudeRef': {
7657
                                N: 'North latitude',
7658
                                S: 'South latitude'
7659
                        },
7660
 
7661
                        'GPSLongitudeRef': {
7662
                                E: 'East longitude',
7663
                                W: 'West longitude'
7664
                        }
7665
                };
7666
 
7667
                function extractTags(IFD_offset, tags2extract) {
7668
                        var length = data.SHORT(IFD_offset), i, ii,
7669
                                tag, type, count, tagOffset, offset, value, values = [], hash = {};
7670
 
7671
                        for (i = 0; i < length; i++) {
7672
                                // Set binary reader pointer to beginning of the next tag
7673
                                offset = tagOffset = IFD_offset + 12 * i + 2;
7674
 
7675
                                tag = tags2extract[data.SHORT(offset)];
7676
 
7677
                                if (tag === undefined) {
7678
                                        continue; // Not the tag we requested
7679
                                }
7680
 
7681
                                type = data.SHORT(offset+=2);
7682
                                count = data.LONG(offset+=2);
7683
 
7684
                                offset += 4;
7685
                                values = [];
7686
 
7687
                                switch (type) {
7688
                                        case 1: // BYTE
7689
                                        case 7: // UNDEFINED
7690
                                                if (count > 4) {
7691
                                                        offset = data.LONG(offset) + offsets.tiffHeader;
7692
                                                }
7693
 
7694
                                                for (ii = 0; ii < count; ii++) {
7695
                                                        values[ii] = data.BYTE(offset + ii);
7696
                                                }
7697
 
7698
                                                break;
7699
 
7700
                                        case 2: // STRING
7701
                                                if (count > 4) {
7702
                                                        offset = data.LONG(offset) + offsets.tiffHeader;
7703
                                                }
7704
 
7705
                                                hash[tag] = data.STRING(offset, count - 1);
7706
 
7707
                                                continue;
7708
 
7709
                                        case 3: // SHORT
7710
                                                if (count > 2) {
7711
                                                        offset = data.LONG(offset) + offsets.tiffHeader;
7712
                                                }
7713
 
7714
                                                for (ii = 0; ii < count; ii++) {
7715
                                                        values[ii] = data.SHORT(offset + ii*2);
7716
                                                }
7717
 
7718
                                                break;
7719
 
7720
                                        case 4: // LONG
7721
                                                if (count > 1) {
7722
                                                        offset = data.LONG(offset) + offsets.tiffHeader;
7723
                                                }
7724
 
7725
                                                for (ii = 0; ii < count; ii++) {
7726
                                                        values[ii] = data.LONG(offset + ii*4);
7727
                                                }
7728
 
7729
                                                break;
7730
 
7731
                                        case 5: // RATIONAL
7732
                                                offset = data.LONG(offset) + offsets.tiffHeader;
7733
 
7734
                                                for (ii = 0; ii < count; ii++) {
7735
                                                        values[ii] = data.LONG(offset + ii*4) / data.LONG(offset + ii*4 + 4);
7736
                                                }
7737
 
7738
                                                break;
7739
 
7740
                                        case 9: // SLONG
7741
                                                offset = data.LONG(offset) + offsets.tiffHeader;
7742
 
7743
                                                for (ii = 0; ii < count; ii++) {
7744
                                                        values[ii] = data.SLONG(offset + ii*4);
7745
                                                }
7746
 
7747
                                                break;
7748
 
7749
                                        case 10: // SRATIONAL
7750
                                                offset = data.LONG(offset) + offsets.tiffHeader;
7751
 
7752
                                                for (ii = 0; ii < count; ii++) {
7753
                                                        values[ii] = data.SLONG(offset + ii*4) / data.SLONG(offset + ii*4 + 4);
7754
                                                }
7755
 
7756
                                                break;
7757
 
7758
                                        default:
7759
                                                continue;
7760
                                }
7761
 
7762
                                value = (count == 1 ? values[0] : values);
7763
 
7764
                                if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') {
7765
                                        hash[tag] = tagDescs[tag][value];
7766
                                } else {
7767
                                        hash[tag] = value;
7768
                                }
7769
                        }
7770
 
7771
                        return hash;
7772
                }
7773
 
7774
                function getIFDOffsets() {
7775
                        var idx = offsets.tiffHeader;
7776
 
7777
                        // Set read order of multi-byte data
7778
                        data.II(data.SHORT(idx) == 0x4949);
7779
 
7780
                        // Check if always present bytes are indeed present
7781
                        if (data.SHORT(idx+=2) !== 0x002A) {
7782
                                return false;
7783
                        }
7784
 
7785
                        offsets.IFD0 = offsets.tiffHeader + data.LONG(idx += 2);
7786
                        Tiff = extractTags(offsets.IFD0, tags.tiff);
7787
 
7788
                        if ('ExifIFDPointer' in Tiff) {
7789
                                offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer;
7790
                                delete Tiff.ExifIFDPointer;
7791
                        }
7792
 
7793
                        if ('GPSInfoIFDPointer' in Tiff) {
7794
                                offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer;
7795
                                delete Tiff.GPSInfoIFDPointer;
7796
                        }
7797
                        return true;
7798
                }
7799
 
7800
                // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported
7801
                function setTag(ifd, tag, value) {
7802
                        var offset, length, tagOffset, valueOffset = 0;
7803
 
7804
                        // If tag name passed translate into hex key
7805
                        if (typeof(tag) === 'string') {
7806
                                var tmpTags = tags[ifd.toLowerCase()];
7807
                                for (var hex in tmpTags) {
7808
                                        if (tmpTags[hex] === tag) {
7809
                                                tag = hex;
7810
                                                break;
7811
                                        }
7812
                                }
7813
                        }
7814
                        offset = offsets[ifd.toLowerCase() + 'IFD'];
7815
                        length = data.SHORT(offset);
7816
 
7817
                        for (var i = 0; i < length; i++) {
7818
                                tagOffset = offset + 12 * i + 2;
7819
 
7820
                                if (data.SHORT(tagOffset) == tag) {
7821
                                        valueOffset = tagOffset + 8;
7822
                                        break;
7823
                                }
7824
                        }
7825
 
7826
                        if (!valueOffset) {
7827
                                return false;
7828
                        }
7829
 
7830
                        data.LONG(valueOffset, value);
7831
                        return true;
7832
                }
7833
 
7834
 
7835
                // Public functions
7836
                return {
7837
                        init: function(segment) {
7838
                                // Reset internal data
7839
                                offsets = {
7840
                                        tiffHeader: 10
7841
                                };
7842
 
7843
                                if (segment === undefined || !segment.length) {
7844
                                        return false;
7845
                                }
7846
 
7847
                                data.init(segment);
7848
 
7849
                                // Check if that's APP1 and that it has EXIF
7850
                                if (data.SHORT(0) === 0xFFE1 && data.STRING(4, 5).toUpperCase() === "EXIF\0") {
7851
                                        return getIFDOffsets();
7852
                                }
7853
                                return false;
7854
                        },
7855
 
7856
                        TIFF: function() {
7857
                                return Tiff;
7858
                        },
7859
 
7860
                        EXIF: function() {
7861
                                var Exif;
7862
 
7863
                                // Populate EXIF hash
7864
                                Exif = extractTags(offsets.exifIFD, tags.exif);
7865
 
7866
                                // Fix formatting of some tags
7867
                                if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') {
7868
                                        for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) {
7869
                                                exifVersion += String.fromCharCode(Exif.ExifVersion[i]);
7870
                                        }
7871
                                        Exif.ExifVersion = exifVersion;
7872
                                }
7873
 
7874
                                return Exif;
7875
                        },
7876
 
7877
                        GPS: function() {
7878
                                var GPS;
7879
 
7880
                                GPS = extractTags(offsets.gpsIFD, tags.gps);
7881
 
7882
                                // iOS devices (and probably some others) do not put in GPSVersionID tag (why?..)
7883
                                if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') {
7884
                                        GPS.GPSVersionID = GPS.GPSVersionID.join('.');
7885
                                }
7886
 
7887
                                return GPS;
7888
                        },
7889
 
7890
                        setExif: function(tag, value) {
7891
                                // Right now only setting of width/height is possible
7892
                                if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') {return false;}
7893
 
7894
                                return setTag('exif', tag, value);
7895
                        },
7896
 
7897
 
7898
                        getBinary: function() {
7899
                                return data.SEGMENT();
7900
                        },
7901
 
7902
                        purge: function() {
7903
                                data.init(null);
7904
                                data = Tiff = null;
7905
                                offsets = {};
7906
                        }
7907
                };
7908
        };
7909
});
7910
 
7911
// Included from: src/javascript/runtime/html5/image/JPEG.js
7912
 
7913
/**
7914
 * JPEG.js
7915
 *
7916
 * Copyright 2013, Moxiecode Systems AB
7917
 * Released under GPL License.
7918
 *
7919
 * License: http://www.plupload.com/license
7920
 * Contributing: http://www.plupload.com/contributing
7921
 */
7922
 
7923
/**
7924
@class moxie/runtime/html5/image/JPEG
7925
@private
7926
*/
7927
define("moxie/runtime/html5/image/JPEG", [
7928
        "moxie/core/utils/Basic",
7929
        "moxie/core/Exceptions",
7930
        "moxie/runtime/html5/image/JPEGHeaders",
7931
        "moxie/runtime/html5/utils/BinaryReader",
7932
        "moxie/runtime/html5/image/ExifParser"
7933
], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) {
7934
 
7935
        function JPEG(binstr) {
7936
                var _binstr, _br, _hm, _ep, _info, hasExif;
7937
 
7938
                function _getDimensions() {
7939
                        var idx = 0, marker, length;
7940
 
7941
                        // examine all through the end, since some images might have very large APP segments
7942
                        while (idx <= _binstr.length) {
7943
                                marker = _br.SHORT(idx += 2);
7944
 
7945
                                if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn
7946
                                        idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte)
7947
                                        return {
7948
                                                height: _br.SHORT(idx),
7949
                                                width: _br.SHORT(idx += 2)
7950
                                        };
7951
                                }
7952
                                length = _br.SHORT(idx += 2);
7953
                                idx += length - 2;
7954
                        }
7955
                        return null;
7956
                }
7957
 
7958
                _binstr = binstr;
7959
 
7960
                _br = new BinaryReader();
7961
                _br.init(_binstr);
7962
 
7963
                // check if it is jpeg
7964
                if (_br.SHORT(0) !== 0xFFD8) {
7965
                        throw new x.ImageError(x.ImageError.WRONG_FORMAT);
7966
                }
7967
 
7968
                // backup headers
7969
                _hm = new JPEGHeaders(binstr);
7970
 
7971
                // extract exif info
7972
                _ep = new ExifParser();
7973
                hasExif = !!_ep.init(_hm.get('app1')[0]);
7974
 
7975
                // get dimensions
7976
                _info = _getDimensions.call(this);
7977
 
7978
                Basic.extend(this, {
7979
                        type: 'image/jpeg',
7980
 
7981
                        size: _binstr.length,
7982
 
7983
                        width: _info && _info.width || 0,
7984
 
7985
                        height: _info && _info.height || 0,
7986
 
7987
                        setExif: function(tag, value) {
7988
                                if (!hasExif) {
7989
                                        return false; // or throw an exception
7990
                                }
7991
 
7992
                                if (Basic.typeOf(tag) === 'object') {
7993
                                        Basic.each(tag, function(value, tag) {
7994
                                                _ep.setExif(tag, value);
7995
                                        });
7996
                                } else {
7997
                                        _ep.setExif(tag, value);
7998
                                }
7999
 
8000
                                // update internal headers
8001
                                _hm.set('app1', _ep.getBinary());
8002
                        },
8003
 
8004
                        writeHeaders: function() {
8005
                                if (!arguments.length) {
8006
                                        // if no arguments passed, update headers internally
8007
                                        return (_binstr = _hm.restore(_binstr));
8008
                                }
8009
                                return _hm.restore(arguments[0]);
8010
                        },
8011
 
8012
                        stripHeaders: function(binstr) {
8013
                                return _hm.strip(binstr);
8014
                        },
8015
 
8016
                        purge: function() {
8017
                                _purge.call(this);
8018
                        }
8019
                });
8020
 
8021
                if (hasExif) {
8022
                        this.meta = {
8023
                                tiff: _ep.TIFF(),
8024
                                exif: _ep.EXIF(),
8025
                                gps: _ep.GPS()
8026
                        };
8027
                }
8028
 
8029
                function _purge() {
8030
                        if (!_ep || !_hm || !_br) {
8031
                                return; // ignore any repeating purge requests
8032
                        }
8033
                        _ep.purge();
8034
                        _hm.purge();
8035
                        _br.init(null);
8036
                        _binstr = _info = _hm = _ep = _br = null;
8037
                }
8038
        }
8039
 
8040
        return JPEG;
8041
});
8042
 
8043
// Included from: src/javascript/runtime/html5/image/PNG.js
8044
 
8045
/**
8046
 * PNG.js
8047
 *
8048
 * Copyright 2013, Moxiecode Systems AB
8049
 * Released under GPL License.
8050
 *
8051
 * License: http://www.plupload.com/license
8052
 * Contributing: http://www.plupload.com/contributing
8053
 */
8054
 
8055
/**
8056
@class moxie/runtime/html5/image/PNG
8057
@private
8058
*/
8059
define("moxie/runtime/html5/image/PNG", [
8060
        "moxie/core/Exceptions",
8061
        "moxie/core/utils/Basic",
8062
        "moxie/runtime/html5/utils/BinaryReader"
8063
], function(x, Basic, BinaryReader) {
8064
 
8065
        function PNG(binstr) {
8066
                var _binstr, _br, _hm, _ep, _info;
8067
 
8068
                _binstr = binstr;
8069
 
8070
                _br = new BinaryReader();
8071
                _br.init(_binstr);
8072
 
8073
                // check if it's png
8074
                (function() {
8075
                        var idx = 0, i = 0
8076
                        , signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A]
8077
                        ;
8078
 
8079
                        for (i = 0; i < signature.length; i++, idx += 2) {
8080
                                if (signature[i] != _br.SHORT(idx)) {
8081
                                        throw new x.ImageError(x.ImageError.WRONG_FORMAT);
8082
                                }
8083
                        }
8084
                }());
8085
 
8086
                function _getDimensions() {
8087
                        var chunk, idx;
8088
 
8089
                        chunk = _getChunkAt.call(this, 8);
8090
 
8091
                        if (chunk.type == 'IHDR') {
8092
                                idx = chunk.start;
8093
                                return {
8094
                                        width: _br.LONG(idx),
8095
                                        height: _br.LONG(idx += 4)
8096
                                };
8097
                        }
8098
                        return null;
8099
                }
8100
 
8101
                function _purge() {
8102
                        if (!_br) {
8103
                                return; // ignore any repeating purge requests
8104
                        }
8105
                        _br.init(null);
8106
                        _binstr = _info = _hm = _ep = _br = null;
8107
                }
8108
 
8109
                _info = _getDimensions.call(this);
8110
 
8111
                Basic.extend(this, {
8112
                        type: 'image/png',
8113
 
8114
                        size: _binstr.length,
8115
 
8116
                        width: _info.width,
8117
 
8118
                        height: _info.height,
8119
 
8120
                        purge: function() {
8121
                                _purge.call(this);
8122
                        }
8123
                });
8124
 
8125
                // for PNG we can safely trigger purge automatically, as we do not keep any data for later
8126
                _purge.call(this);
8127
 
8128
                function _getChunkAt(idx) {
8129
                        var length, type, start, CRC;
8130
 
8131
                        length = _br.LONG(idx);
8132
                        type = _br.STRING(idx += 4, 4);
8133
                        start = idx += 4;
8134
                        CRC = _br.LONG(idx + length);
8135
 
8136
                        return {
8137
                                length: length,
8138
                                type: type,
8139
                                start: start,
8140
                                CRC: CRC
8141
                        };
8142
                }
8143
        }
8144
 
8145
        return PNG;
8146
});
8147
 
8148
// Included from: src/javascript/runtime/html5/image/ImageInfo.js
8149
 
8150
/**
8151
 * ImageInfo.js
8152
 *
8153
 * Copyright 2013, Moxiecode Systems AB
8154
 * Released under GPL License.
8155
 *
8156
 * License: http://www.plupload.com/license
8157
 * Contributing: http://www.plupload.com/contributing
8158
 */
8159
 
8160
/**
8161
@class moxie/runtime/html5/image/ImageInfo
8162
@private
8163
*/
8164
define("moxie/runtime/html5/image/ImageInfo", [
8165
        "moxie/core/utils/Basic",
8166
        "moxie/core/Exceptions",
8167
        "moxie/runtime/html5/image/JPEG",
8168
        "moxie/runtime/html5/image/PNG"
8169
], function(Basic, x, JPEG, PNG) {
8170
        /**
8171
        Optional image investigation tool for HTML5 runtime. Provides the following features:
8172
        - ability to distinguish image type (JPEG or PNG) by signature
8173
        - ability to extract image width/height directly from it's internals, without preloading in memory (fast)
8174
        - ability to extract APP headers from JPEGs (Exif, GPS, etc)
8175
        - ability to replace width/height tags in extracted JPEG headers
8176
        - ability to restore APP headers, that were for example stripped during image manipulation
8177
 
8178
        @class ImageInfo
8179
        @constructor
8180
        @param {String} binstr Image source as binary string
8181
        */
8182
        return function(binstr) {
8183
                var _cs = [JPEG, PNG], _img;
8184
 
8185
                // figure out the format, throw: ImageError.WRONG_FORMAT if not supported
8186
                _img = (function() {
8187
                        for (var i = 0; i < _cs.length; i++) {
8188
                                try {
8189
                                        return new _cs[i](binstr);
8190
                                } catch (ex) {
8191
                                        // console.info(ex);
8192
                                }
8193
                        }
8194
                        throw new x.ImageError(x.ImageError.WRONG_FORMAT);
8195
                }());
8196
 
8197
                Basic.extend(this, {
8198
                        /**
8199
                        Image Mime Type extracted from it's depths
8200
 
8201
                        @property type
8202
                        @type {String}
8203
                        @default ''
8204
                        */
8205
                        type: '',
8206
 
8207
                        /**
8208
                        Image size in bytes
8209
 
8210
                        @property size
8211
                        @type {Number}
8212
                        @default 0
8213
                        */
8214
                        size: 0,
8215
 
8216
                        /**
8217
                        Image width extracted from image source
8218
 
8219
                        @property width
8220
                        @type {Number}
8221
                        @default 0
8222
                        */
8223
                        width: 0,
8224
 
8225
                        /**
8226
                        Image height extracted from image source
8227
 
8228
                        @property height
8229
                        @type {Number}
8230
                        @default 0
8231
                        */
8232
                        height: 0,
8233
 
8234
                        /**
8235
                        Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs.
8236
 
8237
                        @method setExif
8238
                        @param {String} tag Tag to set
8239
                        @param {Mixed} value Value to assign to the tag
8240
                        */
8241
                        setExif: function() {},
8242
 
8243
                        /**
8244
                        Restores headers to the source.
8245
 
8246
                        @method writeHeaders
8247
                        @param {String} data Image source as binary string
8248
                        @return {String} Updated binary string
8249
                        */
8250
                        writeHeaders: function(data) {
8251
                                return data;
8252
                        },
8253
 
8254
                        /**
8255
                        Strip all headers from the source.
8256
 
8257
                        @method stripHeaders
8258
                        @param {String} data Image source as binary string
8259
                        @return {String} Updated binary string
8260
                        */
8261
                        stripHeaders: function(data) {
8262
                                return data;
8263
                        },
8264
 
8265
                        /**
8266
                        Dispose resources.
8267
 
8268
                        @method purge
8269
                        */
8270
                        purge: function() {}
8271
                });
8272
 
8273
                Basic.extend(this, _img);
8274
 
8275
                this.purge = function() {
8276
                        _img.purge();
8277
                        _img = null;
8278
                };
8279
        };
8280
});
8281
 
8282
// Included from: src/javascript/runtime/html5/image/MegaPixel.js
8283
 
8284
/**
8285
(The MIT License)
8286
 
8287
Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com>;
8288
 
8289
Permission is hereby granted, free of charge, to any person obtaining
8290
a copy of this software and associated documentation files (the
8291
'Software'), to deal in the Software without restriction, including
8292
without limitation the rights to use, copy, modify, merge, publish,
8293
distribute, sublicense, and/or sell copies of the Software, and to
8294
permit persons to whom the Software is furnished to do so, subject to
8295
the following conditions:
8296
 
8297
The above copyright notice and this permission notice shall be
8298
included in all copies or substantial portions of the Software.
8299
 
8300
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
8301
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
8302
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
8303
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
8304
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
8305
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
8306
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8307
*/
8308
 
8309
/**
8310
 * Mega pixel image rendering library for iOS6 Safari
8311
 *
8312
 * Fixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel),
8313
 * which causes unexpected subsampling when drawing it in canvas.
8314
 * By using this library, you can safely render the image with proper stretching.
8315
 *
8316
 * Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com>
8317
 * Released under the MIT license
8318
 */
8319
 
8320
/**
8321
@class moxie/runtime/html5/image/MegaPixel
8322
@private
8323
*/
8324
define("moxie/runtime/html5/image/MegaPixel", [], function() {
8325
 
8326
        /**
8327
         * Rendering image element (with resizing) into the canvas element
8328
         */
8329
        function renderImageToCanvas(img, canvas, options) {
8330
                var iw = img.naturalWidth, ih = img.naturalHeight;
8331
                var width = options.width, height = options.height;
8332
                var x = options.x || 0, y = options.y || 0;
8333
                var ctx = canvas.getContext('2d');
8334
                if (detectSubsampling(img)) {
8335
                        iw /= 2;
8336
                        ih /= 2;
8337
                }
8338
                var d = 1024; // size of tiling canvas
8339
                var tmpCanvas = document.createElement('canvas');
8340
                tmpCanvas.width = tmpCanvas.height = d;
8341
                var tmpCtx = tmpCanvas.getContext('2d');
8342
                var vertSquashRatio = detectVerticalSquash(img, iw, ih);
8343
                var sy = 0;
8344
                while (sy < ih) {
8345
                        var sh = sy + d > ih ? ih - sy : d;
8346
                        var sx = 0;
8347
                        while (sx < iw) {
8348
                                var sw = sx + d > iw ? iw - sx : d;
8349
                                tmpCtx.clearRect(0, 0, d, d);
8350
                                tmpCtx.drawImage(img, -sx, -sy);
8351
                                var dx = (sx * width / iw + x) << 0;
8352
                                var dw = Math.ceil(sw * width / iw);
8353
                                var dy = (sy * height / ih / vertSquashRatio + y) << 0;
8354
                                var dh = Math.ceil(sh * height / ih / vertSquashRatio);
8355
                                ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh);
8356
                                sx += d;
8357
                        }
8358
                        sy += d;
8359
                }
8360
                tmpCanvas = tmpCtx = null;
8361
        }
8362
 
8363
        /**
8364
         * Detect subsampling in loaded image.
8365
         * In iOS, larger images than 2M pixels may be subsampled in rendering.
8366
         */
8367
        function detectSubsampling(img) {
8368
                var iw = img.naturalWidth, ih = img.naturalHeight;
8369
                if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image
8370
                        var canvas = document.createElement('canvas');
8371
                        canvas.width = canvas.height = 1;
8372
                        var ctx = canvas.getContext('2d');
8373
                        ctx.drawImage(img, -iw + 1, 0);
8374
                        // subsampled image becomes half smaller in rendering size.
8375
                        // check alpha channel value to confirm image is covering edge pixel or not.
8376
                        // if alpha value is 0 image is not covering, hence subsampled.
8377
                        return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
8378
                } else {
8379
                        return false;
8380
                }
8381
        }
8382
 
8383
 
8384
        /**
8385
         * Detecting vertical squash in loaded image.
8386
         * Fixes a bug which squash image vertically while drawing into canvas for some images.
8387
         */
8388
        function detectVerticalSquash(img, iw, ih) {
8389
                var canvas = document.createElement('canvas');
8390
                canvas.width = 1;
8391
                canvas.height = ih;
8392
                var ctx = canvas.getContext('2d');
8393
                ctx.drawImage(img, 0, 0);
8394
                var data = ctx.getImageData(0, 0, 1, ih).data;
8395
                // search image edge pixel position in case it is squashed vertically.
8396
                var sy = 0;
8397
                var ey = ih;
8398
                var py = ih;
8399
                while (py > sy) {
8400
                        var alpha = data[(py - 1) * 4 + 3];
8401
                        if (alpha === 0) {
8402
                                ey = py;
8403
                        } else {
8404
                        sy = py;
8405
                        }
8406
                        py = (ey + sy) >> 1;
8407
                }
8408
                canvas = null;
8409
                var ratio = (py / ih);
8410
                return (ratio === 0) ? 1 : ratio;
8411
        }
8412
 
8413
        return {
8414
                isSubsampled: detectSubsampling,
8415
                renderTo: renderImageToCanvas
8416
        };
8417
});
8418
 
8419
// Included from: src/javascript/runtime/html5/image/Image.js
8420
 
8421
/**
8422
 * Image.js
8423
 *
8424
 * Copyright 2013, Moxiecode Systems AB
8425
 * Released under GPL License.
8426
 *
8427
 * License: http://www.plupload.com/license
8428
 * Contributing: http://www.plupload.com/contributing
8429
 */
8430
 
8431
/**
8432
@class moxie/runtime/html5/image/Image
8433
@private
8434
*/
8435
define("moxie/runtime/html5/image/Image", [
8436
        "moxie/runtime/html5/Runtime",
8437
        "moxie/core/utils/Basic",
8438
        "moxie/core/Exceptions",
8439
        "moxie/core/utils/Encode",
8440
        "moxie/file/File",
8441
        "moxie/runtime/html5/image/ImageInfo",
8442
        "moxie/runtime/html5/image/MegaPixel",
8443
        "moxie/core/utils/Mime",
8444
        "moxie/core/utils/Env"
8445
], function(extensions, Basic, x, Encode, File, ImageInfo, MegaPixel, Mime, Env) {
8446
 
8447
        function HTML5Image() {
8448
                var me = this
8449
                , _img, _imgInfo, _canvas, _binStr, _blob
8450
                , _modified = false // is set true whenever image is modified
8451
                , _preserveHeaders = true
8452
                ;
8453
 
8454
                Basic.extend(this, {
8455
                        loadFromBlob: function(blob) {
8456
                                var comp = this, I = comp.getRuntime()
8457
                                , asBinary = arguments.length > 1 ? arguments[1] : true
8458
                                ;
8459
 
8460
                                if (!I.can('access_binary')) {
8461
                                        throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
8462
                                }
8463
 
8464
                                _blob = blob;
8465
 
8466
                                if (blob.isDetached()) {
8467
                                        _binStr = blob.getSource();
8468
                                        _preload.call(this, _binStr);
8469
                                        return;
8470
                                } else {
8471
                                        _readAsDataUrl.call(this, blob.getSource(), function(dataUrl) {
8472
                                                if (asBinary) {
8473
                                                        _binStr = _toBinary(dataUrl);
8474
                                                }
8475
                                                _preload.call(comp, dataUrl);
8476
                                        });
8477
                                }
8478
                        },
8479
 
8480
                        loadFromImage: function(img, exact) {
8481
                                this.meta = img.meta;
8482
 
8483
                                _blob = new File(null, {
8484
                                        name: img.name,
8485
                                        size: img.size,
8486
                                        type: img.type
8487
                                });
8488
 
8489
                                _preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
8490
                        },
8491
 
8492
                        getInfo: function() {
8493
                                var I = this.getRuntime(), info;
8494
 
8495
                                if (!_imgInfo && _binStr && I.can('access_image_binary')) {
8496
                                        _imgInfo = new ImageInfo(_binStr);
8497
                                }
8498
 
8499
                                info = {
8500
                                        width: _getImg().width || 0,
8501
                                        height: _getImg().height || 0,
8502
                                        type: _blob.type || Mime.getFileMime(_blob.name),
8503
                                        size: _binStr && _binStr.length || _blob.size || 0,
8504
                                        name: _blob.name || '',
8505
                                        meta: _imgInfo && _imgInfo.meta || this.meta || {}
8506
                                };
8507
 
8508
                                return info;
8509
                        },
8510
 
8511
                        downsize: function() {
8512
                                _downsize.apply(this, arguments);
8513
                        },
8514
 
8515
                        getAsCanvas: function() {
8516
                                if (_canvas) {
8517
                                        _canvas.id = this.uid + '_canvas';
8518
                                }
8519
                                return _canvas;
8520
                        },
8521
 
8522
                        getAsBlob: function(type, quality) {
8523
                                if (type !== this.type) {
8524
                                        // if different mime type requested prepare image for conversion
8525
                                        _downsize.call(this, this.width, this.height, false);
8526
                                }
8527
                                return new File(null, {
8528
                                        name: _blob.name || '',
8529
                                        type: type,
8530
                                        data: me.getAsBinaryString.call(this, type, quality)
8531
                                });
8532
                        },
8533
 
8534
                        getAsDataURL: function(type) {
8535
                                var quality = arguments[1] || 90;
8536
 
8537
                                // if image has not been modified, return the source right away
8538
                                if (!_modified) {
8539
                                        return _img.src;
8540
                                }
8541
 
8542
                                if ('image/jpeg' !== type) {
8543
                                        return _canvas.toDataURL('image/png');
8544
                                } else {
8545
                                        try {
8546
                                                // older Geckos used to result in an exception on quality argument
8547
                                                return _canvas.toDataURL('image/jpeg', quality/100);
8548
                                        } catch (ex) {
8549
                                                return _canvas.toDataURL('image/jpeg');
8550
                                        }
8551
                                }
8552
                        },
8553
 
8554
                        getAsBinaryString: function(type, quality) {
8555
                                // if image has not been modified, return the source right away
8556
                                if (!_modified) {
8557
                                        // if image was not loaded from binary string
8558
                                        if (!_binStr) {
8559
                                                _binStr = _toBinary(me.getAsDataURL(type, quality));
8560
                                        }
8561
                                        return _binStr;
8562
                                }
8563
 
8564
                                if ('image/jpeg' !== type) {
8565
                                        _binStr = _toBinary(me.getAsDataURL(type, quality));
8566
                                } else {
8567
                                        var dataUrl;
8568
 
8569
                                        // if jpeg
8570
                                        if (!quality) {
8571
                                                quality = 90;
8572
                                        }
8573
 
8574
                                        try {
8575
                                                // older Geckos used to result in an exception on quality argument
8576
                                                dataUrl = _canvas.toDataURL('image/jpeg', quality/100);
8577
                                        } catch (ex) {
8578
                                                dataUrl = _canvas.toDataURL('image/jpeg');
8579
                                        }
8580
 
8581
                                        _binStr = _toBinary(dataUrl);
8582
 
8583
                                        if (_imgInfo) {
8584
                                                _binStr = _imgInfo.stripHeaders(_binStr);
8585
 
8586
                                                if (_preserveHeaders) {
8587
                                                        // update dimensions info in exif
8588
                                                        if (_imgInfo.meta && _imgInfo.meta.exif) {
8589
                                                                _imgInfo.setExif({
8590
                                                                        PixelXDimension: this.width,
8591
                                                                        PixelYDimension: this.height
8592
                                                                });
8593
                                                        }
8594
 
8595
                                                        // re-inject the headers
8596
                                                        _binStr = _imgInfo.writeHeaders(_binStr);
8597
                                                }
8598
 
8599
                                                // will be re-created from fresh on next getInfo call
8600
                                                _imgInfo.purge();
8601
                                                _imgInfo = null;
8602
                                        }
8603
                                }
8604
 
8605
                                _modified = false;
8606
 
8607
                                return _binStr;
8608
                        },
8609
 
8610
                        destroy: function() {
8611
                                me = null;
8612
                                _purge.call(this);
8613
                                this.getRuntime().getShim().removeInstance(this.uid);
8614
                        }
8615
                });
8616
 
8617
 
8618
                function _getImg() {
8619
                        if (!_canvas && !_img) {
8620
                                throw new x.ImageError(x.DOMException.INVALID_STATE_ERR);
8621
                        }
8622
                        return _canvas || _img;
8623
                }
8624
 
8625
 
8626
                function _toBinary(str) {
8627
                        return Encode.atob(str.substring(str.indexOf('base64,') + 7));
8628
                }
8629
 
8630
 
8631
                function _toDataUrl(str, type) {
8632
                        return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
8633
                }
8634
 
8635
 
8636
                function _preload(str) {
8637
                        var comp = this;
8638
 
8639
                        _img = new Image();
8640
                        _img.onerror = function() {
8641
                                _purge.call(this);
8642
                                comp.trigger('error', x.ImageError.WRONG_FORMAT);
8643
                        };
8644
                        _img.onload = function() {
8645
                                comp.trigger('load');
8646
                        };
8647
 
8648
                        _img.src = /^data:[^;]*;base64,/.test(str) ? str : _toDataUrl(str, _blob.type);
8649
                }
8650
 
8651
 
8652
                function _readAsDataUrl(file, callback) {
8653
                        var comp = this, fr;
8654
 
8655
                        // use FileReader if it's available
8656
                        if (window.FileReader) {
8657
                                fr = new FileReader();
8658
                                fr.onload = function() {
8659
                                        callback(this.result);
8660
                                };
8661
                                fr.onerror = function() {
8662
                                        comp.trigger('error', x.ImageError.WRONG_FORMAT);
8663
                                };
8664
                                fr.readAsDataURL(file);
8665
                        } else {
8666
                                return callback(file.getAsDataURL());
8667
                        }
8668
                }
8669
 
8670
                function _downsize(width, height, crop, preserveHeaders) {
8671
                        var self = this
8672
                        , scale
8673
                        , mathFn
8674
                        , x = 0
8675
                        , y = 0
8676
                        , img
8677
                        , destWidth
8678
                        , destHeight
8679
                        , orientation
8680
                        ;
8681
 
8682
                        _preserveHeaders = preserveHeaders; // we will need to check this on export (see getAsBinaryString())
8683
 
8684
                        // take into account orientation tag
8685
                        orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
8686
 
8687
                        if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation
8688
                                // swap dimensions
8689
                                var tmp = width;
8690
                                width = height;
8691
                                height = tmp;
8692
                        }
8693
 
8694
                        img = _getImg();
8695
 
8696
                        // unify dimensions
8697
                        if (!crop) {
8698
                                scale = Math.min(width/img.width, height/img.height);
8699
                        } else {
8700
                                // one of the dimensions may exceed the actual image dimensions - we need to take the smallest value
8701
                                width = Math.min(width, img.width);
8702
                                height = Math.min(height, img.height);
8703
 
8704
                                scale = Math.max(width/img.width, height/img.height);
8705
                        }
8706
 
8707
                        // we only downsize here
8708
                        if (scale > 1 && !crop && preserveHeaders) {
8709
                                this.trigger('Resize');
8710
                                return;
8711
                        }
8712
 
8713
                        // prepare canvas if necessary
8714
                        if (!_canvas) {
8715
                                _canvas = document.createElement("canvas");
8716
                        }
8717
 
8718
                        // calculate dimensions of proportionally resized image
8719
                        destWidth = Math.round(img.width * scale);     
8720
                        destHeight = Math.round(img.height * scale);
8721
 
8722
                        // scale image and canvas
8723
                        if (crop) {
8724
                                _canvas.width = width;
8725
                                _canvas.height = height;
8726
 
8727
                                // if dimensions of the resulting image still larger than canvas, center it
8728
                                if (destWidth > width) {
8729
                                        x = Math.round((destWidth - width) / 2);
8730
                                }
8731
 
8732
                                if (destHeight > height) {
8733
                                        y = Math.round((destHeight - height) / 2);
8734
                                }
8735
                        } else {
8736
                                _canvas.width = destWidth;
8737
                                _canvas.height = destHeight;
8738
                        }
8739
 
8740
                        // rotate if required, according to orientation tag
8741
                        if (!_preserveHeaders) {
8742
                                _rotateToOrientaion(_canvas.width, _canvas.height, orientation);
8743
                        }
8744
 
8745
                        _drawToCanvas.call(this, img, _canvas, -x, -y, destWidth, destHeight);
8746
 
8747
                        this.width = _canvas.width;
8748
                        this.height = _canvas.height;
8749
 
8750
                        _modified = true;
8751
                        self.trigger('Resize');
8752
                }
8753
 
8754
 
8755
                function _drawToCanvas(img, canvas, x, y, w, h) {
8756
                        if (Env.OS === 'iOS') {
8757
                                // avoid squish bug in iOS6
8758
                                MegaPixel.renderTo(img, canvas, { width: w, height: h, x: x, y: y });
8759
                        } else {
8760
                                var ctx = canvas.getContext('2d');
8761
                                ctx.drawImage(img, x, y, w, h);
8762
                        }
8763
                }
8764
 
8765
 
8766
                /**
8767
                * Transform canvas coordination according to specified frame size and orientation
8768
                * Orientation value is from EXIF tag
8769
                * @author Shinichi Tomita <shinichi.tomita@gmail.com>
8770
                */
8771
                function _rotateToOrientaion(width, height, orientation) {
8772
                        switch (orientation) {
8773
                                case 5:
8774
                                case 6:
8775
                                case 7:
8776
                                case 8:
8777
                                        _canvas.width = height;
8778
                                        _canvas.height = width;
8779
                                        break;
8780
                                default:
8781
                                        _canvas.width = width;
8782
                                        _canvas.height = height;
8783
                        }
8784
 
8785
                        /**
8786
                        1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
8787
                        2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
8788
                        3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
8789
                        4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
8790
                        5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
8791
                        6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
8792
                        7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
8793
                        8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
8794
                        */
8795
 
8796
                        var ctx = _canvas.getContext('2d');
8797
                        switch (orientation) {
8798
                                case 2:
8799
                                        // horizontal flip
8800
                                        ctx.translate(width, 0);
8801
                                        ctx.scale(-1, 1);
8802
                                        break;
8803
                                case 3:
8804
                                        // 180 rotate left
8805
                                        ctx.translate(width, height);
8806
                                        ctx.rotate(Math.PI);
8807
                                        break;
8808
                                case 4:
8809
                                        // vertical flip
8810
                                        ctx.translate(0, height);
8811
                                        ctx.scale(1, -1);
8812
                                        break;
8813
                                case 5:
8814
                                        // vertical flip + 90 rotate right
8815
                                        ctx.rotate(0.5 * Math.PI);
8816
                                        ctx.scale(1, -1);
8817
                                        break;
8818
                                case 6:
8819
                                        // 90 rotate right
8820
                                        ctx.rotate(0.5 * Math.PI);
8821
                                        ctx.translate(0, -height);
8822
                                        break;
8823
                                case 7:
8824
                                        // horizontal flip + 90 rotate right
8825
                                        ctx.rotate(0.5 * Math.PI);
8826
                                        ctx.translate(width, -height);
8827
                                        ctx.scale(-1, 1);
8828
                                        break;
8829
                                case 8:
8830
                                        // 90 rotate left
8831
                                        ctx.rotate(-0.5 * Math.PI);
8832
                                        ctx.translate(-width, 0);
8833
                                        break;
8834
                        }
8835
                }
8836
 
8837
 
8838
                function _purge() {
8839
                        if (_imgInfo) {
8840
                                _imgInfo.purge();
8841
                                _imgInfo = null;
8842
                        }
8843
                        _binStr = _img = _canvas = _blob = null;
8844
                        _modified = false;
8845
                }
8846
        }
8847
 
8848
        return (extensions.Image = HTML5Image);
8849
});
8850
 
8851
// Included from: src/javascript/runtime/flash/Runtime.js
8852
 
8853
/**
8854
 * Runtime.js
8855
 *
8856
 * Copyright 2013, Moxiecode Systems AB
8857
 * Released under GPL License.
8858
 *
8859
 * License: http://www.plupload.com/license
8860
 * Contributing: http://www.plupload.com/contributing
8861
 */
8862
 
8863
/*global ActiveXObject:true */
8864
 
8865
/**
8866
Defines constructor for Flash runtime.
8867
 
8868
@class moxie/runtime/flash/Runtime
8869
@private
8870
*/
8871
define("moxie/runtime/flash/Runtime", [
8872
        "moxie/core/utils/Basic",
8873
        "moxie/core/utils/Env",
8874
        "moxie/core/utils/Dom",
8875
        "moxie/core/Exceptions",
8876
        "moxie/runtime/Runtime"
8877
], function(Basic, Env, Dom, x, Runtime) {
8878
 
8879
        var type = 'flash', extensions = {};
8880
 
8881
        /**
8882
        Get the version of the Flash Player
8883
 
8884
        @method getShimVersion
8885
        @private
8886
        @return {Number} Flash Player version
8887
        */
8888
        function getShimVersion() {
8889
                var version;
8890
 
8891
                try {
8892
                        version = navigator.plugins['Shockwave Flash'];
8893
                        version = version.description;
8894
                } catch (e1) {
8895
                        try {
8896
                                version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
8897
                        } catch (e2) {
8898
                                version = '0.0';
8899
                        }
8900
                }
8901
                version = version.match(/\d+/g);
8902
                return parseFloat(version[0] + '.' + version[1]);
8903
        }
8904
 
8905
        /**
8906
        Constructor for the Flash Runtime
8907
 
8908
        @class FlashRuntime
8909
        @extends Runtime
8910
        */
8911
        function FlashRuntime(options) {
8912
                var I = this, initTimer;
8913
 
8914
                options = Basic.extend({ swf_url: Env.swf_url }, options);
8915
 
8916
                Runtime.call(this, options, type, {
8917
                        access_binary: function(value) {
8918
                                return value && I.mode === 'browser';
8919
                        },
8920
                        access_image_binary: function(value) {
8921
                                return value && I.mode === 'browser';
8922
                        },
8923
                        display_media: Runtime.capTrue,
8924
                        do_cors: Runtime.capTrue,
8925
                        drag_and_drop: false,
8926
                        report_upload_progress: function() {
8927
                                return I.mode === 'client';
8928
                        },
8929
                        resize_image: Runtime.capTrue,
8930
                        return_response_headers: false,
8931
                        return_response_type: function(responseType) {
8932
                                if (responseType === 'json' && !!window.JSON) {
8933
                                        return true;
8934
                                }
8935
                                return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser';
8936
                        },
8937
                        return_status_code: function(code) {
8938
                                return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]);
8939
                        },
8940
                        select_file: Runtime.capTrue,
8941
                        select_multiple: Runtime.capTrue,
8942
                        send_binary_string: function(value) {
8943
                                return value && I.mode === 'browser';
8944
                        },
8945
                        send_browser_cookies: function(value) {
8946
                                return value && I.mode === 'browser';
8947
                        },
8948
                        send_custom_headers: function(value) {
8949
                                return value && I.mode === 'browser';
8950
                        },
8951
                        send_multipart: Runtime.capTrue,
8952
                        slice_blob: function(value) {
8953
                                return value && I.mode === 'browser';
8954
                        },
8955
                        stream_upload: function(value) {
8956
                                return value && I.mode === 'browser';
8957
                        },
8958
                        summon_file_dialog: false,
8959
                        upload_filesize: function(size) {
8960
                                return Basic.parseSizeStr(size) <= 2097152 || I.mode === 'client';
8961
                        },
8962
                        use_http_method: function(methods) {
8963
                                return !Basic.arrayDiff(methods, ['GET', 'POST']);
8964
                        }
8965
                }, {
8966
                        // capabilities that require specific mode
8967
                        access_binary: function(value) {
8968
                                return value ? 'browser' : 'client';
8969
                        },
8970
                        access_image_binary: function(value) {
8971
                                return value ? 'browser' : 'client';
8972
                        },
8973
                        report_upload_progress: function(value) {
8974
                                return value ? 'browser' : 'client';
8975
                        },
8976
                        return_response_type: function(responseType) {
8977
                                return Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) ? 'browser' : ['client', 'browser'];
8978
                        },
8979
                        return_status_code: function(code) {
8980
                                return Basic.arrayDiff(code, [200, 404]) ? 'browser' : ['client', 'browser'];
8981
                        },
8982
                        send_binary_string: function(value) {
8983
                                return value ? 'browser' : 'client';
8984
                        },
8985
                        send_browser_cookies: function(value) {
8986
                                return value ? 'browser' : 'client';
8987
                        },
8988
                        send_custom_headers: function(value) {
8989
                                return value ? 'browser' : 'client';
8990
                        },
8991
                        stream_upload: function(value) {
8992
                                return value ? 'client' : 'browser';
8993
                        },
8994
                        upload_filesize: function(size) {
8995
                                return Basic.parseSizeStr(size) >= 2097152 ? 'client' : 'browser';
8996
                        }
8997
                }, 'client');
8998
 
8999
 
9000
                // minimal requirement for Flash Player version
9001
                if (getShimVersion() < 10) {
9002
                        this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before
9003
                }
9004
 
9005
 
9006
                Basic.extend(this, {
9007
 
9008
                        getShim: function() {
9009
                                return Dom.get(this.uid);
9010
                        },
9011
 
9012
                        shimExec: function(component, action) {
9013
                                var args = [].slice.call(arguments, 2);
9014
                                return I.getShim().exec(this.uid, component, action, args);
9015
                        },
9016
 
9017
                        init: function() {
9018
                                var html, el, container;
9019
 
9020
                                container = this.getShimContainer();
9021
 
9022
                                // if not the minimal height, shims are not initialized in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc)
9023
                                Basic.extend(container.style, {
9024
                                        position: 'absolute',
9025
                                        top: '-8px',
9026
                                        left: '-8px',
9027
                                        width: '9px',
9028
                                        height: '9px',
9029
                                        overflow: 'hidden'
9030
                                });
9031
 
9032
                                // insert flash object
9033
                                html = '<object id="' + this.uid + '" type="application/x-shockwave-flash" data="' +  options.swf_url + '" ';
9034
 
9035
                                if (Env.browser === 'IE') {
9036
                                        html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
9037
                                }
9038
 
9039
                                html += 'width="100%" height="100%" style="outline:0">'  +
9040
                                        '<param name="movie" value="' + options.swf_url + '" />' +
9041
                                        '<param name="flashvars" value="uid=' + escape(this.uid) + '&target=' + Env.global_event_dispatcher + '" />' +
9042
                                        '<param name="wmode" value="transparent" />' +
9043
                                        '<param name="allowscriptaccess" value="always" />' +
9044
                                '</object>';
9045
 
9046
                                if (Env.browser === 'IE') {
9047
                                        el = document.createElement('div');
9048
                                        container.appendChild(el);
9049
                                        el.outerHTML = html;
9050
                                        el = container = null; // just in case
9051
                                } else {
9052
                                        container.innerHTML = html;
9053
                                }
9054
 
9055
                                // Init is dispatched by the shim
9056
                                initTimer = setTimeout(function() {
9057
                                        if (I && !I.initialized) { // runtime might be already destroyed by this moment
9058
                                                I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
9059
                                        }
9060
                                }, 5000);
9061
                        },
9062
 
9063
                        destroy: (function(destroy) { // extend default destroy method
9064
                                return function() {
9065
                                        destroy.call(I);
9066
                                        clearTimeout(initTimer); // initialization check might be still onwait
9067
                                        options = initTimer = destroy = I = null;
9068
                                };
9069
                        }(this.destroy))
9070
 
9071
                }, extensions);
9072
        }
9073
 
9074
        Runtime.addConstructor(type, FlashRuntime);
9075
 
9076
        return extensions;
9077
});
9078
 
9079
// Included from: src/javascript/runtime/flash/file/Blob.js
9080
 
9081
/**
9082
 * Blob.js
9083
 *
9084
 * Copyright 2013, Moxiecode Systems AB
9085
 * Released under GPL License.
9086
 *
9087
 * License: http://www.plupload.com/license
9088
 * Contributing: http://www.plupload.com/contributing
9089
 */
9090
 
9091
/**
9092
@class moxie/runtime/flash/file/Blob
9093
@private
9094
*/
9095
define("moxie/runtime/flash/file/Blob", [
9096
        "moxie/runtime/flash/Runtime",
9097
        "moxie/file/Blob"
9098
], function(extensions, Blob) {
9099
 
9100
        var FlashBlob = {
9101
                slice: function(blob, start, end, type) {
9102
                        var self = this.getRuntime();
9103
 
9104
                        if (start < 0) {
9105
                                start = Math.max(blob.size + start, 0);
9106
                        } else if (start > 0) {
9107
                                start = Math.min(start, blob.size);
9108
                        }
9109
 
9110
                        if (end < 0) {
9111
                                end = Math.max(blob.size + end, 0);
9112
                        } else if (end > 0) {
9113
                                end = Math.min(end, blob.size);
9114
                        }
9115
 
9116
                        blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || '');
9117
 
9118
                        if (blob) {
9119
                                blob = new Blob(self.uid, blob);
9120
                        }
9121
                        return blob;
9122
                }
9123
        };
9124
 
9125
        return (extensions.Blob = FlashBlob);
9126
});
9127
 
9128
// Included from: src/javascript/runtime/flash/file/FileInput.js
9129
 
9130
/**
9131
 * FileInput.js
9132
 *
9133
 * Copyright 2013, Moxiecode Systems AB
9134
 * Released under GPL License.
9135
 *
9136
 * License: http://www.plupload.com/license
9137
 * Contributing: http://www.plupload.com/contributing
9138
 */
9139
 
9140
/**
9141
@class moxie/runtime/flash/file/FileInput
9142
@private
9143
*/
9144
define("moxie/runtime/flash/file/FileInput", [
9145
        "moxie/runtime/flash/Runtime"
9146
], function(extensions) {
9147
 
9148
        var FileInput = {              
9149
                init: function(options) {
9150
                        this.getRuntime().shimExec.call(this, 'FileInput', 'init', {
9151
                                name: options.name,
9152
                                accept: options.accept,
9153
                                multiple: options.multiple
9154
                        });
9155
                        this.trigger('ready');
9156
                }
9157
        };
9158
 
9159
        return (extensions.FileInput = FileInput);
9160
});
9161
 
9162
// Included from: src/javascript/runtime/flash/file/FileReader.js
9163
 
9164
/**
9165
 * FileReader.js
9166
 *
9167
 * Copyright 2013, Moxiecode Systems AB
9168
 * Released under GPL License.
9169
 *
9170
 * License: http://www.plupload.com/license
9171
 * Contributing: http://www.plupload.com/contributing
9172
 */
9173
 
9174
/**
9175
@class moxie/runtime/flash/file/FileReader
9176
@private
9177
*/
9178
define("moxie/runtime/flash/file/FileReader", [
9179
        "moxie/runtime/flash/Runtime",
9180
        "moxie/core/utils/Encode"
9181
], function(extensions, Encode) {
9182
 
9183
        var _result = '';
9184
 
9185
        function _formatData(data, op) {
9186
                switch (op) {
9187
                        case 'readAsText':
9188
                                return Encode.atob(data, 'utf8');
9189
                        case 'readAsBinaryString':
9190
                                return Encode.atob(data);
9191
                        case 'readAsDataURL':
9192
                                return data;
9193
                }
9194
                return null;
9195
        }
9196
 
9197
        var FileReader = {
9198
                read: function(op, blob) {
9199
                        var target = this, self = target.getRuntime();
9200
 
9201
                        // special prefix for DataURL read mode
9202
                        if (op === 'readAsDataURL') {
9203
                                _result = 'data:' + (blob.type || '') + ';base64,';
9204
                        }
9205
 
9206
                        target.bind('Progress', function(e, data) {
9207
                                if (data) {
9208
                                        _result += _formatData(data, op);
9209
                                }
9210
                        });
9211
 
9212
                        return self.shimExec.call(this, 'FileReader', 'readAsBase64', blob.uid);
9213
                },
9214
 
9215
                getResult: function() {
9216
                        return _result;
9217
                },
9218
 
9219
                destroy: function() {
9220
                        _result = null;
9221
                }
9222
        };
9223
 
9224
        return (extensions.FileReader = FileReader);
9225
});
9226
 
9227
// Included from: src/javascript/runtime/flash/file/FileReaderSync.js
9228
 
9229
/**
9230
 * FileReaderSync.js
9231
 *
9232
 * Copyright 2013, Moxiecode Systems AB
9233
 * Released under GPL License.
9234
 *
9235
 * License: http://www.plupload.com/license
9236
 * Contributing: http://www.plupload.com/contributing
9237
 */
9238
 
9239
/**
9240
@class moxie/runtime/flash/file/FileReaderSync
9241
@private
9242
*/
9243
define("moxie/runtime/flash/file/FileReaderSync", [
9244
        "moxie/runtime/flash/Runtime",
9245
        "moxie/core/utils/Encode"
9246
], function(extensions, Encode) {
9247
 
9248
        function _formatData(data, op) {
9249
                switch (op) {
9250
                        case 'readAsText':
9251
                                return Encode.atob(data, 'utf8');
9252
                        case 'readAsBinaryString':
9253
                                return Encode.atob(data);
9254
                        case 'readAsDataURL':
9255
                                return data;
9256
                }
9257
                return null;
9258
        }
9259
 
9260
        var FileReaderSync = {
9261
                read: function(op, blob) {
9262
                        var result, self = this.getRuntime();
9263
 
9264
                        result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid);
9265
                        if (!result) {
9266
                                return null; // or throw ex
9267
                        }
9268
 
9269
                        // special prefix for DataURL read mode
9270
                        if (op === 'readAsDataURL') {
9271
                                result = 'data:' + (blob.type || '') + ';base64,' + result;
9272
                        }
9273
 
9274
                        return _formatData(result, op, blob.type);
9275
                }
9276
        };
9277
 
9278
        return (extensions.FileReaderSync = FileReaderSync);
9279
});
9280
 
9281
// Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js
9282
 
9283
/**
9284
 * XMLHttpRequest.js
9285
 *
9286
 * Copyright 2013, Moxiecode Systems AB
9287
 * Released under GPL License.
9288
 *
9289
 * License: http://www.plupload.com/license
9290
 * Contributing: http://www.plupload.com/contributing
9291
 */
9292
 
9293
/**
9294
@class moxie/runtime/flash/xhr/XMLHttpRequest
9295
@private
9296
*/
9297
define("moxie/runtime/flash/xhr/XMLHttpRequest", [
9298
        "moxie/runtime/flash/Runtime",
9299
        "moxie/core/utils/Basic",
9300
        "moxie/file/Blob",
9301
        "moxie/file/File",
9302
        "moxie/file/FileReaderSync",
9303
        "moxie/xhr/FormData",
9304
        "moxie/runtime/Transporter"
9305
], function(extensions, Basic, Blob, File, FileReaderSync, FormData, Transporter) {
9306
 
9307
        var XMLHttpRequest = {
9308
 
9309
                send: function(meta, data) {
9310
                        var target = this, self = target.getRuntime();
9311
 
9312
                        function send() {
9313
                                meta.transport = self.mode;
9314
                                self.shimExec.call(target, 'XMLHttpRequest', 'send', meta, data);
9315
                        }
9316
 
9317
 
9318
                        function appendBlob(name, blob) {
9319
                                self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid);
9320
                                data = null;
9321
                                send();
9322
                        }
9323
 
9324
 
9325
                        function attachBlob(blob, cb) {
9326
                                var tr = new Transporter();
9327
 
9328
                                tr.bind("TransportingComplete", function() {
9329
                                        cb(this.result);
9330
                                });
9331
 
9332
                                tr.transport(blob.getSource(), blob.type, {
9333
                                        ruid: self.uid
9334
                                });
9335
                        }
9336
 
9337
                        // copy over the headers if any
9338
                        if (!Basic.isEmptyObj(meta.headers)) {
9339
                                Basic.each(meta.headers, function(value, header) {
9340
                                        self.shimExec.call(target, 'XMLHttpRequest', 'setRequestHeader', header, value.toString()); // Silverlight doesn't accept integers into the arguments of type object
9341
                                });
9342
                        }
9343
 
9344
                        // transfer over multipart params and blob itself
9345
                        if (data instanceof FormData) {
9346
                                var blobField;
9347
                                data.each(function(value, name) {
9348
                                        if (value instanceof Blob) {
9349
                                                blobField = name;
9350
                                        } else {
9351
                                                self.shimExec.call(target, 'XMLHttpRequest', 'append', name, value);
9352
                                        }
9353
                                });
9354
 
9355
                                if (!data.hasBlob()) {
9356
                                        data = null;
9357
                                        send();
9358
                                } else {
9359
                                        var blob = data.getBlob();
9360
                                        if (blob.isDetached()) {
9361
                                                attachBlob(blob, function(attachedBlob) {
9362
                                                        blob.destroy();
9363
                                                        appendBlob(blobField, attachedBlob);           
9364
                                                });
9365
                                        } else {
9366
                                                appendBlob(blobField, blob);
9367
                                        }
9368
                                }
9369
                        } else if (data instanceof Blob) {
9370
                                if (data.isDetached()) {
9371
                                        attachBlob(data, function(attachedBlob) {
9372
                                                data.destroy();
9373
                                                data = attachedBlob.uid;
9374
                                                send();
9375
                                        });
9376
                                } else {
9377
                                        data = data.uid;
9378
                                        send();
9379
                                }
9380
                        } else {
9381
                                send();
9382
                        }
9383
                },
9384
 
9385
                getResponse: function(responseType) {
9386
                        var frs, blob, self = this.getRuntime();
9387
 
9388
                        blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob');
9389
 
9390
                        if (blob) {
9391
                                blob = new File(self.uid, blob);
9392
 
9393
                                if ('blob' === responseType) {
9394
                                        return blob;
9395
                                }
9396
 
9397
                                try {
9398
                                        frs = new FileReaderSync();
9399
 
9400
                                        if (!!~Basic.inArray(responseType, ["", "text"])) {
9401
                                                return frs.readAsText(blob);
9402
                                        } else if ('json' === responseType && !!window.JSON) {
9403
                                                return JSON.parse(frs.readAsText(blob));
9404
                                        }
9405
                                } finally {
9406
                                        blob.destroy();
9407
                                }
9408
                        }
9409
                        return null;
9410
                },
9411
 
9412
                abort: function(upload_complete_flag) {
9413
                        var self = this.getRuntime();
9414
 
9415
                        self.shimExec.call(this, 'XMLHttpRequest', 'abort');
9416
 
9417
                        this.dispatchEvent('readystatechange');
9418
                        // this.dispatchEvent('progress');
9419
                        this.dispatchEvent('abort');
9420
 
9421
                        //if (!upload_complete_flag) {
9422
                                // this.dispatchEvent('uploadprogress');
9423
                        //}
9424
                }
9425
        };
9426
 
9427
        return (extensions.XMLHttpRequest = XMLHttpRequest);
9428
});
9429
 
9430
// Included from: src/javascript/runtime/flash/runtime/Transporter.js
9431
 
9432
/**
9433
 * Transporter.js
9434
 *
9435
 * Copyright 2013, Moxiecode Systems AB
9436
 * Released under GPL License.
9437
 *
9438
 * License: http://www.plupload.com/license
9439
 * Contributing: http://www.plupload.com/contributing
9440
 */
9441
 
9442
/**
9443
@class moxie/runtime/flash/runtime/Transporter
9444
@private
9445
*/
9446
define("moxie/runtime/flash/runtime/Transporter", [
9447
        "moxie/runtime/flash/Runtime",
9448
        "moxie/file/Blob"
9449
], function(extensions, Blob) {
9450
 
9451
        var Transporter = {
9452
                getAsBlob: function(type) {
9453
                        var self = this.getRuntime()
9454
                        , blob = self.shimExec.call(this, 'Transporter', 'getAsBlob', type)
9455
                        ;
9456
                        if (blob) {
9457
                                return new Blob(self.uid, blob);
9458
                        }
9459
                        return null;
9460
                }
9461
        };
9462
 
9463
        return (extensions.Transporter = Transporter);
9464
});
9465
 
9466
// Included from: src/javascript/runtime/flash/image/Image.js
9467
 
9468
/**
9469
 * Image.js
9470
 *
9471
 * Copyright 2013, Moxiecode Systems AB
9472
 * Released under GPL License.
9473
 *
9474
 * License: http://www.plupload.com/license
9475
 * Contributing: http://www.plupload.com/contributing
9476
 */
9477
 
9478
/**
9479
@class moxie/runtime/flash/image/Image
9480
@private
9481
*/
9482
define("moxie/runtime/flash/image/Image", [
9483
        "moxie/runtime/flash/Runtime",
9484
        "moxie/core/utils/Basic",
9485
        "moxie/runtime/Transporter",
9486
        "moxie/file/Blob",
9487
        "moxie/file/FileReaderSync"
9488
], function(extensions, Basic, Transporter, Blob, FileReaderSync) {
9489
 
9490
        var Image = {
9491
                loadFromBlob: function(blob) {
9492
                        var comp = this, self = comp.getRuntime();
9493
 
9494
                        function exec(srcBlob) {
9495
                                self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid);
9496
                                comp = self = null;
9497
                        }
9498
 
9499
                        if (blob.isDetached()) { // binary string
9500
                                var tr = new Transporter();
9501
                                tr.bind("TransportingComplete", function() {
9502
                                        exec(tr.result.getSource());
9503
                                });
9504
                                tr.transport(blob.getSource(), blob.type, { ruid: self.uid });
9505
                        } else {
9506
                                exec(blob.getSource());
9507
                        }
9508
                },
9509
 
9510
                loadFromImage: function(img) {
9511
                        var self = this.getRuntime();
9512
                        return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid);
9513
                },
9514
 
9515
                getAsBlob: function(type, quality) {
9516
                        var self = this.getRuntime()
9517
                        , blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality)
9518
                        ;
9519
                        if (blob) {
9520
                                return new Blob(self.uid, blob);
9521
                        }
9522
                        return null;
9523
                },
9524
 
9525
                getAsDataURL: function() {
9526
                        var self = this.getRuntime()
9527
                        , blob = self.Image.getAsBlob.apply(this, arguments)
9528
                        , frs
9529
                        ;
9530
                        if (!blob) {
9531
                                return null;
9532
                        }
9533
                        frs = new FileReaderSync();
9534
                        return frs.readAsDataURL(blob);
9535
                }
9536
        };
9537
 
9538
        return (extensions.Image = Image);
9539
});
9540
 
9541
// Included from: src/javascript/runtime/silverlight/Runtime.js
9542
 
9543
/**
9544
 * RunTime.js
9545
 *
9546
 * Copyright 2013, Moxiecode Systems AB
9547
 * Released under GPL License.
9548
 *
9549
 * License: http://www.plupload.com/license
9550
 * Contributing: http://www.plupload.com/contributing
9551
 */
9552
 
9553
/*global ActiveXObject:true */
9554
 
9555
/**
9556
Defines constructor for Silverlight runtime.
9557
 
9558
@class moxie/runtime/silverlight/Runtime
9559
@private
9560
*/
9561
define("moxie/runtime/silverlight/Runtime", [
9562
        "moxie/core/utils/Basic",
9563
        "moxie/core/utils/Env",
9564
        "moxie/core/utils/Dom",
9565
        "moxie/core/Exceptions",
9566
        "moxie/runtime/Runtime"
9567
], function(Basic, Env, Dom, x, Runtime) {
9568
 
9569
        var type = "silverlight", extensions = {};
9570
 
9571
        function isInstalled(version) {
9572
                var isVersionSupported = false, control = null, actualVer,
9573
                        actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0;
9574
 
9575
                try {
9576
                        try {
9577
                                control = new ActiveXObject('AgControl.AgControl');
9578
 
9579
                                if (control.IsVersionSupported(version)) {
9580
                                        isVersionSupported = true;
9581
                                }
9582
 
9583
                                control = null;
9584
                        } catch (e) {
9585
                                var plugin = navigator.plugins["Silverlight Plug-In"];
9586
 
9587
                                if (plugin) {
9588
                                        actualVer = plugin.description;
9589
 
9590
                                        if (actualVer === "1.0.30226.2") {
9591
                                                actualVer = "2.0.30226.2";
9592
                                        }
9593
 
9594
                                        actualVerArray = actualVer.split(".");
9595
 
9596
                                        while (actualVerArray.length > 3) {
9597
                                                actualVerArray.pop();
9598
                                        }
9599
 
9600
                                        while ( actualVerArray.length < 4) {
9601
                                                actualVerArray.push(0);
9602
                                        }
9603
 
9604
                                        reqVerArray = version.split(".");
9605
 
9606
                                        while (reqVerArray.length > 4) {
9607
                                                reqVerArray.pop();
9608
                                        }
9609
 
9610
                                        do {
9611
                                                requiredVersionPart = parseInt(reqVerArray[index], 10);
9612
                                                actualVersionPart = parseInt(actualVerArray[index], 10);
9613
                                                index++;
9614
                                        } while (index < reqVerArray.length && requiredVersionPart === actualVersionPart);
9615
 
9616
                                        if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) {
9617
                                                isVersionSupported = true;
9618
                                        }
9619
                                }
9620
                        }
9621
                } catch (e2) {
9622
                        isVersionSupported = false;
9623
                }
9624
 
9625
                return isVersionSupported;
9626
        }
9627
 
9628
        /**
9629
        Constructor for the Silverlight Runtime
9630
 
9631
        @class SilverlightRuntime
9632
        @extends Runtime
9633
        */
9634
        function SilverlightRuntime(options) {
9635
                var I = this, initTimer;
9636
 
9637
                options = Basic.extend({ xap_url: Env.xap_url }, options);
9638
 
9639
                Runtime.call(this, options, type, {
9640
                        access_binary: Runtime.capTrue,
9641
                        access_image_binary: Runtime.capTrue,
9642
                        display_media: Runtime.capTrue,
9643
                        do_cors: Runtime.capTrue,
9644
                        drag_and_drop: false,
9645
                        report_upload_progress: Runtime.capTrue,
9646
                        resize_image: Runtime.capTrue,
9647
                        return_response_headers: function(value) {
9648
                                return value && I.mode === 'client';
9649
                        },
9650
                        return_response_type: function(responseType) {
9651
                                if (responseType !== 'json') {
9652
                                        return true;
9653
                                } else {
9654
                                        return !!window.JSON;
9655
                                }
9656
                        },
9657
                        return_status_code: function(code) {
9658
                                return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]);
9659
                        },
9660
                        select_file: Runtime.capTrue,
9661
                        select_multiple: Runtime.capTrue,
9662
                        send_binary_string: Runtime.capTrue,
9663
                        send_browser_cookies: function(value) {
9664
                                return value && I.mode === 'browser';
9665
                        },
9666
                        send_custom_headers: function(value) {
9667
                                return value && I.mode === 'client';
9668
                        },
9669
                        send_multipart: Runtime.capTrue,
9670
                        slice_blob: Runtime.capTrue,
9671
                        stream_upload: true,
9672
                        summon_file_dialog: false,
9673
                        upload_filesize: Runtime.capTrue,
9674
                        use_http_method: function(methods) {
9675
                                return I.mode === 'client' || !Basic.arrayDiff(methods, ['GET', 'POST']);
9676
                        }
9677
                }, {
9678
                        // capabilities that require specific mode
9679
                        return_response_headers: function(value) {
9680
                                return value ? 'client' : 'browser';
9681
                        },
9682
                        return_status_code: function(code) {
9683
                                return Basic.arrayDiff(code, [200, 404]) ? 'client' : ['client', 'browser'];
9684
                        },
9685
                        send_browser_cookies: function(value) {
9686
                                return value ? 'browser' : 'client';
9687
                        },
9688
                        send_custom_headers: function(value) {
9689
                                return value ? 'client' : 'browser';
9690
                        },
9691
                        use_http_method: function(methods) {
9692
                                return Basic.arrayDiff(methods, ['GET', 'POST']) ? 'client' : ['client', 'browser'];
9693
                        }
9694
                });
9695
 
9696
 
9697
                // minimal requirement
9698
                if (!isInstalled('2.0.31005.0') || Env.browser === 'Opera') {
9699
                        this.mode = false;
9700
                }
9701
 
9702
 
9703
                Basic.extend(this, {
9704
                        getShim: function() {
9705
                                return Dom.get(this.uid).content.Moxie;
9706
                        },
9707
 
9708
                        shimExec: function(component, action) {
9709
                                var args = [].slice.call(arguments, 2);
9710
                                return I.getShim().exec(this.uid, component, action, args);
9711
                        },
9712
 
9713
                        init : function() {
9714
                                var container;
9715
 
9716
                                container = this.getShimContainer();
9717
 
9718
                                container.innerHTML = '<object id="' + this.uid + '" data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%" style="outline:none;">' +
9719
                                        '<param name="source" value="' + options.xap_url + '"/>' +
9720
                                        '<param name="background" value="Transparent"/>' +
9721
                                        '<param name="windowless" value="true"/>' +
9722
                                        '<param name="enablehtmlaccess" value="true"/>' +
9723
                                        '<param name="initParams" value="uid=' + this.uid + ',target=' + Env.global_event_dispatcher + '"/>' +
9724
                                '</object>';
9725
 
9726
                                // Init is dispatched by the shim
9727
                                initTimer = setTimeout(function() {
9728
                                        if (I && !I.initialized) { // runtime might be already destroyed by this moment
9729
                                                I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
9730
                                        }
9731
                                }, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac)
9732
                        },
9733
 
9734
                        destroy: (function(destroy) { // extend default destroy method
9735
                                return function() {
9736
                                        destroy.call(I);
9737
                                        clearTimeout(initTimer); // initialization check might be still onwait
9738
                                        options = initTimer = destroy = I = null;
9739
                                };
9740
                        }(this.destroy))
9741
 
9742
                }, extensions);
9743
        }
9744
 
9745
        Runtime.addConstructor(type, SilverlightRuntime);
9746
 
9747
        return extensions;
9748
});
9749
 
9750
// Included from: src/javascript/runtime/silverlight/file/Blob.js
9751
 
9752
/**
9753
 * Blob.js
9754
 *
9755
 * Copyright 2013, Moxiecode Systems AB
9756
 * Released under GPL License.
9757
 *
9758
 * License: http://www.plupload.com/license
9759
 * Contributing: http://www.plupload.com/contributing
9760
 */
9761
 
9762
/**
9763
@class moxie/runtime/silverlight/file/Blob
9764
@private
9765
*/
9766
define("moxie/runtime/silverlight/file/Blob", [
9767
        "moxie/runtime/silverlight/Runtime",
9768
        "moxie/core/utils/Basic",
9769
        "moxie/runtime/flash/file/Blob"
9770
], function(extensions, Basic, Blob) {
9771
        return (extensions.Blob = Basic.extend({}, Blob));
9772
});
9773
 
9774
// Included from: src/javascript/runtime/silverlight/file/FileInput.js
9775
 
9776
/**
9777
 * FileInput.js
9778
 *
9779
 * Copyright 2013, Moxiecode Systems AB
9780
 * Released under GPL License.
9781
 *
9782
 * License: http://www.plupload.com/license
9783
 * Contributing: http://www.plupload.com/contributing
9784
 */
9785
 
9786
/**
9787
@class moxie/runtime/silverlight/file/FileInput
9788
@private
9789
*/
9790
define("moxie/runtime/silverlight/file/FileInput", [
9791
        "moxie/runtime/silverlight/Runtime"
9792
], function(extensions) {
9793
 
9794
        var FileInput = {
9795
                init: function(options) {
9796
 
9797
                        function toFilters(accept) {
9798
                                var filter = '';
9799
                                for (var i = 0; i < accept.length; i++) {
9800
                                        filter += (filter !== '' ? '|' : '') + accept[i].title + " | *." + accept[i].extensions.replace(/,/g, ';*.');
9801
                                }
9802
                                return filter;
9803
                        }
9804
 
9805
                        this.getRuntime().shimExec.call(this, 'FileInput', 'init', toFilters(options.accept), options.name, options.multiple);
9806
                        this.trigger('ready');
9807
                }
9808
        };
9809
 
9810
        return (extensions.FileInput = FileInput);
9811
});
9812
 
9813
// Included from: src/javascript/runtime/silverlight/file/FileDrop.js
9814
 
9815
/**
9816
 * FileDrop.js
9817
 *
9818
 * Copyright 2013, Moxiecode Systems AB
9819
 * Released under GPL License.
9820
 *
9821
 * License: http://www.plupload.com/license
9822
 * Contributing: http://www.plupload.com/contributing
9823
 */
9824
 
9825
/**
9826
@class moxie/runtime/silverlight/file/FileDrop
9827
@private
9828
*/
9829
define("moxie/runtime/silverlight/file/FileDrop", [
9830
        "moxie/runtime/silverlight/Runtime",
9831
        "moxie/core/utils/Dom",
9832
        "moxie/core/utils/Events"
9833
], function(extensions, Dom, Events) {
9834
 
9835
        // not exactly useful, since works only in safari (...crickets...)
9836
        var FileDrop = {
9837
                init: function() {
9838
                        var comp = this, self = comp.getRuntime(), dropZone;
9839
 
9840
                        dropZone = self.getShimContainer();
9841
 
9842
                        Events.addEvent(dropZone, 'dragover', function(e) {
9843
                                e.preventDefault();
9844
                                e.stopPropagation();
9845
                                e.dataTransfer.dropEffect = 'copy';
9846
                        }, comp.uid);
9847
 
9848
                        Events.addEvent(dropZone, 'dragenter', function(e) {
9849
                                e.preventDefault();
9850
                                var flag = Dom.get(self.uid).dragEnter(e);
9851
                                // If handled, then stop propagation of event in DOM
9852
                                if (flag) {
9853
                                        e.stopPropagation();
9854
                                }
9855
                        }, comp.uid);
9856
 
9857
                        Events.addEvent(dropZone, 'drop', function(e) {
9858
                                e.preventDefault();
9859
                                var flag = Dom.get(self.uid).dragDrop(e);
9860
                                // If handled, then stop propagation of event in DOM
9861
                                if (flag) {
9862
                                        e.stopPropagation();
9863
                                }
9864
                        }, comp.uid);
9865
 
9866
                        return self.shimExec.call(this, 'FileDrop', 'init');
9867
                }
9868
        };
9869
 
9870
        return (extensions.FileDrop = FileDrop);
9871
});
9872
 
9873
// Included from: src/javascript/runtime/silverlight/file/FileReader.js
9874
 
9875
/**
9876
 * FileReader.js
9877
 *
9878
 * Copyright 2013, Moxiecode Systems AB
9879
 * Released under GPL License.
9880
 *
9881
 * License: http://www.plupload.com/license
9882
 * Contributing: http://www.plupload.com/contributing
9883
 */
9884
 
9885
/**
9886
@class moxie/runtime/silverlight/file/FileReader
9887
@private
9888
*/
9889
define("moxie/runtime/silverlight/file/FileReader", [
9890
        "moxie/runtime/silverlight/Runtime",
9891
        "moxie/core/utils/Basic",
9892
        "moxie/runtime/flash/file/FileReader"
9893
], function(extensions, Basic, FileReader) {
9894
        return (extensions.FileReader = Basic.extend({}, FileReader));
9895
});
9896
 
9897
// Included from: src/javascript/runtime/silverlight/file/FileReaderSync.js
9898
 
9899
/**
9900
 * FileReaderSync.js
9901
 *
9902
 * Copyright 2013, Moxiecode Systems AB
9903
 * Released under GPL License.
9904
 *
9905
 * License: http://www.plupload.com/license
9906
 * Contributing: http://www.plupload.com/contributing
9907
 */
9908
 
9909
/**
9910
@class moxie/runtime/silverlight/file/FileReaderSync
9911
@private
9912
*/
9913
define("moxie/runtime/silverlight/file/FileReaderSync", [
9914
        "moxie/runtime/silverlight/Runtime",
9915
        "moxie/core/utils/Basic",
9916
        "moxie/runtime/flash/file/FileReaderSync"
9917
], function(extensions, Basic, FileReaderSync) {
9918
        return (extensions.FileReaderSync = Basic.extend({}, FileReaderSync));
9919
});
9920
 
9921
// Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js
9922
 
9923
/**
9924
 * XMLHttpRequest.js
9925
 *
9926
 * Copyright 2013, Moxiecode Systems AB
9927
 * Released under GPL License.
9928
 *
9929
 * License: http://www.plupload.com/license
9930
 * Contributing: http://www.plupload.com/contributing
9931
 */
9932
 
9933
/**
9934
@class moxie/runtime/silverlight/xhr/XMLHttpRequest
9935
@private
9936
*/
9937
define("moxie/runtime/silverlight/xhr/XMLHttpRequest", [
9938
        "moxie/runtime/silverlight/Runtime",
9939
        "moxie/core/utils/Basic",
9940
        "moxie/runtime/flash/xhr/XMLHttpRequest"
9941
], function(extensions, Basic, XMLHttpRequest) {
9942
        return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest));
9943
});
9944
 
9945
// Included from: src/javascript/runtime/silverlight/runtime/Transporter.js
9946
 
9947
/**
9948
 * Transporter.js
9949
 *
9950
 * Copyright 2013, Moxiecode Systems AB
9951
 * Released under GPL License.
9952
 *
9953
 * License: http://www.plupload.com/license
9954
 * Contributing: http://www.plupload.com/contributing
9955
 */
9956
 
9957
/**
9958
@class moxie/runtime/silverlight/runtime/Transporter
9959
@private
9960
*/
9961
define("moxie/runtime/silverlight/runtime/Transporter", [
9962
        "moxie/runtime/silverlight/Runtime",
9963
        "moxie/core/utils/Basic",
9964
        "moxie/runtime/flash/runtime/Transporter"
9965
], function(extensions, Basic, Transporter) {
9966
        return (extensions.Transporter = Basic.extend({}, Transporter));
9967
});
9968
 
9969
// Included from: src/javascript/runtime/silverlight/image/Image.js
9970
 
9971
/**
9972
 * Image.js
9973
 *
9974
 * Copyright 2013, Moxiecode Systems AB
9975
 * Released under GPL License.
9976
 *
9977
 * License: http://www.plupload.com/license
9978
 * Contributing: http://www.plupload.com/contributing
9979
 */
9980
 
9981
/**
9982
@class moxie/runtime/silverlight/image/Image
9983
@private
9984
*/
9985
define("moxie/runtime/silverlight/image/Image", [
9986
        "moxie/runtime/silverlight/Runtime",
9987
        "moxie/core/utils/Basic",
9988
        "moxie/runtime/flash/image/Image"
9989
], function(extensions, Basic, Image) {
9990
        return (extensions.Image = Basic.extend({}, Image, {
9991
 
9992
                getInfo: function() {
9993
                        var self = this.getRuntime()
9994
                        , grps = ['tiff', 'exif', 'gps']
9995
                        , info = { meta: {} }
9996
                        , rawInfo = self.shimExec.call(this, 'Image', 'getInfo')
9997
                        ;
9998
 
9999
                        if (rawInfo.meta) {
10000
                                Basic.each(grps, function(grp) {
10001
                                        var meta = rawInfo.meta[grp]
10002
                                        , tag
10003
                                        , i
10004
                                        , length
10005
                                        , value
10006
                                        ;
10007
                                        if (meta && meta.keys) {
10008
                                                info.meta[grp] = {};
10009
                                                for (i = 0, length = meta.keys.length; i < length; i++) {
10010
                                                        tag = meta.keys[i];
10011
                                                        value = meta[tag];
10012
                                                        if (value) {
10013
                                                                // convert numbers
10014
                                                                if (/^(\d|[1-9]\d+)$/.test(value)) { // integer (make sure doesn't start with zero)
10015
                                                                        value = parseInt(value, 10);
10016
                                                                } else if (/^\d*\.\d+$/.test(value)) { // double
10017
                                                                        value = parseFloat(value);
10018
                                                                }
10019
                                                                info.meta[grp][tag] = value;
10020
                                                        }
10021
                                                }
10022
                                        }
10023
                                });
10024
                        }
10025
 
10026
                        info.width = parseInt(rawInfo.width, 10);
10027
                        info.height = parseInt(rawInfo.height, 10);
10028
                        info.size = parseInt(rawInfo.size, 10);
10029
                        info.type = rawInfo.type;
10030
                        info.name = rawInfo.name;
10031
 
10032
                        return info;
10033
                }
10034
        }));
10035
});
10036
 
10037
// Included from: src/javascript/runtime/html4/Runtime.js
10038
 
10039
/**
10040
 * Runtime.js
10041
 *
10042
 * Copyright 2013, Moxiecode Systems AB
10043
 * Released under GPL License.
10044
 *
10045
 * License: http://www.plupload.com/license
10046
 * Contributing: http://www.plupload.com/contributing
10047
 */
10048
 
10049
/*global File:true */
10050
 
10051
/**
10052
Defines constructor for HTML4 runtime.
10053
 
10054
@class moxie/runtime/html4/Runtime
10055
@private
10056
*/
10057
define("moxie/runtime/html4/Runtime", [
10058
        "moxie/core/utils/Basic",
10059
        "moxie/core/Exceptions",
10060
        "moxie/runtime/Runtime",
10061
        "moxie/core/utils/Env"
10062
], function(Basic, x, Runtime, Env) {
10063
 
10064
        var type = 'html4', extensions = {};
10065
 
10066
        function Html4Runtime(options) {
10067
                var I = this
10068
                , Test = Runtime.capTest
10069
                , True = Runtime.capTrue
10070
                ;
10071
 
10072
                Runtime.call(this, options, type, {
10073
                        access_binary: Test(window.FileReader || window.File && File.getAsDataURL),
10074
                        access_image_binary: false,
10075
                        display_media: Test(extensions.Image && (Env.can('create_canvas') || Env.can('use_data_uri_over32kb'))),
10076
                        do_cors: false,
10077
                        drag_and_drop: false,
10078
                        filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest
10079
                                return (Env.browser === 'Chrome' && Env.version >= 28) || (Env.browser === 'IE' && Env.version >= 10);
10080
                        }()),
10081
                        resize_image: function() {
10082
                                return extensions.Image && I.can('access_binary') && Env.can('create_canvas');
10083
                        },
10084
                        report_upload_progress: false,
10085
                        return_response_headers: false,
10086
                        return_response_type: function(responseType) {
10087
                                if (responseType === 'json' && !!window.JSON) {
10088
                                        return true;
10089
                                }
10090
                                return !!~Basic.inArray(responseType, ['text', 'document', '']);
10091
                        },
10092
                        return_status_code: function(code) {
10093
                                return !Basic.arrayDiff(code, [200, 404]);
10094
                        },
10095
                        select_file: function() {
10096
                                return Env.can('use_fileinput');
10097
                        },
10098
                        select_multiple: false,
10099
                        send_binary_string: false,
10100
                        send_custom_headers: false,
10101
                        send_multipart: true,
10102
                        slice_blob: false,
10103
                        stream_upload: function() {
10104
                                return I.can('select_file');
10105
                        },
10106
                        summon_file_dialog: Test(function() { // yeah... some dirty sniffing here...
10107
                                return (Env.browser === 'Firefox' && Env.version >= 4) ||
10108
                                        (Env.browser === 'Opera' && Env.version >= 12) ||
10109
                                        !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']);
10110
                        }()),
10111
                        upload_filesize: True,
10112
                        use_http_method: function(methods) {
10113
                                return !Basic.arrayDiff(methods, ['GET', 'POST']);
10114
                        }
10115
                });
10116
 
10117
 
10118
                Basic.extend(this, {
10119
                        init : function() {
10120
                                this.trigger("Init");
10121
                        },
10122
 
10123
                        destroy: (function(destroy) { // extend default destroy method
10124
                                return function() {
10125
                                        destroy.call(I);
10126
                                        destroy = I = null;
10127
                                };
10128
                        }(this.destroy))
10129
                });
10130
 
10131
                Basic.extend(this.getShim(), extensions);
10132
        }
10133
 
10134
        Runtime.addConstructor(type, Html4Runtime);
10135
 
10136
        return extensions;
10137
});
10138
 
10139
// Included from: src/javascript/runtime/html4/file/FileInput.js
10140
 
10141
/**
10142
 * FileInput.js
10143
 *
10144
 * Copyright 2013, Moxiecode Systems AB
10145
 * Released under GPL License.
10146
 *
10147
 * License: http://www.plupload.com/license
10148
 * Contributing: http://www.plupload.com/contributing
10149
 */
10150
 
10151
/**
10152
@class moxie/runtime/html4/file/FileInput
10153
@private
10154
*/
10155
define("moxie/runtime/html4/file/FileInput", [
10156
        "moxie/runtime/html4/Runtime",
10157
        "moxie/core/utils/Basic",
10158
        "moxie/core/utils/Dom",
10159
        "moxie/core/utils/Events",
10160
        "moxie/core/utils/Mime",
10161
        "moxie/core/utils/Env"
10162
], function(extensions, Basic, Dom, Events, Mime, Env) {
10163
 
10164
        function FileInput() {
10165
                var _uid, _files = [], _mimes = [], _options;
10166
 
10167
                function addInput() {
10168
                        var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid;
10169
 
10170
                        uid = Basic.guid('uid_');
10171
 
10172
                        shimContainer = I.getShimContainer(); // we get new ref everytime to avoid memory leaks in IE
10173
 
10174
                        if (_uid) { // move previous form out of the view
10175
                                currForm = Dom.get(_uid + '_form');
10176
                                if (currForm) {
10177
                                        Basic.extend(currForm.style, { top: '100%' });
10178
                                }
10179
                        }
10180
 
10181
                        // build form in DOM, since innerHTML version not able to submit file for some reason
10182
                        form = document.createElement('form');
10183
                        form.setAttribute('id', uid + '_form');
10184
                        form.setAttribute('method', 'post');
10185
                        form.setAttribute('enctype', 'multipart/form-data');
10186
                        form.setAttribute('encoding', 'multipart/form-data');
10187
 
10188
                        Basic.extend(form.style, {
10189
                                overflow: 'hidden',
10190
                                position: 'absolute',
10191
                                top: 0,
10192
                                left: 0,
10193
                                width: '100%',
10194
                                height: '100%'
10195
                        });
10196
 
10197
                        input = document.createElement('input');
10198
                        input.setAttribute('id', uid);
10199
                        input.setAttribute('type', 'file');
10200
                        input.setAttribute('name', _options.name || 'Filedata');
10201
                        input.setAttribute('accept', _mimes.join(','));
10202
 
10203
                        Basic.extend(input.style, {
10204
                                fontSize: '999px',
10205
                                opacity: 0
10206
                        });
10207
 
10208
                        form.appendChild(input);
10209
                        shimContainer.appendChild(form);
10210
 
10211
                        // prepare file input to be placed underneath the browse_button element
10212
                        Basic.extend(input.style, {
10213
                                position: 'absolute',
10214
                                top: 0,
10215
                                left: 0,
10216
                                width: '100%',
10217
                                height: '100%'
10218
                        });
10219
 
10220
                        if (Env.browser === 'IE' && Env.version < 10) {
10221
                                Basic.extend(input.style, {
10222
                                        filter : "progid:DXImageTransform.Microsoft.Alpha(opacity=0)"
10223
                                });
10224
                        }
10225
 
10226
                        input.onchange = function() { // there should be only one handler for this
10227
                                var file;
10228
 
10229
                                if (!this.value) {
10230
                                        return;
10231
                                }
10232
 
10233
                                if (this.files) {
10234
                                        file = this.files[0];
10235
                                } else {
10236
                                        file = {
10237
                                                name: this.value
10238
                                        };
10239
                                }
10240
 
10241
                                _files = [file];
10242
 
10243
                                this.onchange = function() {}; // clear event handler
10244
                                addInput.call(comp);
10245
 
10246
                                // after file is initialized as o.File, we need to update form and input ids
10247
                                comp.bind('change', function onChange() {
10248
                                        var input = Dom.get(uid), form = Dom.get(uid + '_form'), file;
10249
 
10250
                                        comp.unbind('change', onChange);
10251
 
10252
                                        if (comp.files.length && input && form) {
10253
                                                file = comp.files[0];
10254
 
10255
                                                input.setAttribute('id', file.uid);
10256
                                                form.setAttribute('id', file.uid + '_form');
10257
 
10258
                                                // set upload target
10259
                                                form.setAttribute('target', file.uid + '_iframe');
10260
                                        }
10261
                                        input = form = null;
10262
                                }, 998);
10263
 
10264
                                input = form = null;
10265
                                comp.trigger('change');
10266
                        };
10267
 
10268
 
10269
                        // route click event to the input
10270
                        if (I.can('summon_file_dialog')) {
10271
                                browseButton = Dom.get(_options.browse_button);
10272
                                Events.removeEvent(browseButton, 'click', comp.uid);
10273
                                Events.addEvent(browseButton, 'click', function(e) {
10274
                                        if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file]
10275
                                                input.click();
10276
                                        }
10277
                                        e.preventDefault();
10278
                                }, comp.uid);
10279
                        }
10280
 
10281
                        _uid = uid;
10282
 
10283
                        shimContainer = currForm = browseButton = null;
10284
                }
10285
 
10286
                Basic.extend(this, {
10287
                        init: function(options) {
10288
                                var comp = this, I = comp.getRuntime(), shimContainer;
10289
 
10290
                                // figure out accept string
10291
                                _options = options;
10292
                                _mimes = options.accept.mimes || Mime.extList2mimes(options.accept, I.can('filter_by_extension'));
10293
 
10294
                                shimContainer = I.getShimContainer();
10295
 
10296
                                (function() {
10297
                                        var browseButton, zIndex, top;
10298
 
10299
                                        browseButton = Dom.get(options.browse_button);
10300
 
10301
                                        // Route click event to the input[type=file] element for browsers that support such behavior
10302
                                        if (I.can('summon_file_dialog')) {
10303
                                                if (Dom.getStyle(browseButton, 'position') === 'static') {
10304
                                                        browseButton.style.position = 'relative';
10305
                                                }
10306
 
10307
                                                zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1;
10308
 
10309
                                                browseButton.style.zIndex = zIndex;
10310
                                                shimContainer.style.zIndex = zIndex - 1;
10311
                                        }
10312
 
10313
                                        /* Since we have to place input[type=file] on top of the browse_button for some browsers,
10314
                                        browse_button loses interactivity, so we restore it here */
10315
                                        top = I.can('summon_file_dialog') ? browseButton : shimContainer;
10316
 
10317
                                        Events.addEvent(top, 'mouseover', function() {
10318
                                                comp.trigger('mouseenter');
10319
                                        }, comp.uid);
10320
 
10321
                                        Events.addEvent(top, 'mouseout', function() {
10322
                                                comp.trigger('mouseleave');
10323
                                        }, comp.uid);
10324
 
10325
                                        Events.addEvent(top, 'mousedown', function() {
10326
                                                comp.trigger('mousedown');
10327
                                        }, comp.uid);
10328
 
10329
                                        Events.addEvent(Dom.get(options.container), 'mouseup', function() {
10330
                                                comp.trigger('mouseup');
10331
                                        }, comp.uid);
10332
 
10333
                                        browseButton = null;
10334
                                }());
10335
 
10336
                                addInput.call(this);
10337
 
10338
                                shimContainer = null;
10339
 
10340
                                // trigger ready event asynchronously
10341
                                comp.trigger({
10342
                                        type: 'ready',
10343
                                        async: true
10344
                                });
10345
                        },
10346
 
10347
                        getFiles: function() {
10348
                                return _files;
10349
                        },
10350
 
10351
                        disable: function(state) {
10352
                                var input;
10353
 
10354
                                if ((input = Dom.get(_uid))) {
10355
                                        input.disabled = !!state;
10356
                                }
10357
                        },
10358
 
10359
                        destroy: function() {
10360
                                var I = this.getRuntime()
10361
                                , shim = I.getShim()
10362
                                , shimContainer = I.getShimContainer()
10363
                                ;
10364
 
10365
                                Events.removeAllEvents(shimContainer, this.uid);
10366
                                Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
10367
                                Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid);
10368
 
10369
                                if (shimContainer) {
10370
                                        shimContainer.innerHTML = '';
10371
                                }
10372
 
10373
                                shim.removeInstance(this.uid);
10374
 
10375
                                _uid = _files = _mimes = _options = shimContainer = shim = null;
10376
                        }
10377
                });
10378
        }
10379
 
10380
        return (extensions.FileInput = FileInput);
10381
});
10382
 
10383
// Included from: src/javascript/runtime/html4/file/FileReader.js
10384
 
10385
/**
10386
 * FileReader.js
10387
 *
10388
 * Copyright 2013, Moxiecode Systems AB
10389
 * Released under GPL License.
10390
 *
10391
 * License: http://www.plupload.com/license
10392
 * Contributing: http://www.plupload.com/contributing
10393
 */
10394
 
10395
/**
10396
@class moxie/runtime/html4/file/FileReader
10397
@private
10398
*/
10399
define("moxie/runtime/html4/file/FileReader", [
10400
        "moxie/runtime/html4/Runtime",
10401
        "moxie/runtime/html5/file/FileReader"
10402
], function(extensions, FileReader) {
10403
        return (extensions.FileReader = FileReader);
10404
});
10405
 
10406
// Included from: src/javascript/runtime/html4/xhr/XMLHttpRequest.js
10407
 
10408
/**
10409
 * XMLHttpRequest.js
10410
 *
10411
 * Copyright 2013, Moxiecode Systems AB
10412
 * Released under GPL License.
10413
 *
10414
 * License: http://www.plupload.com/license
10415
 * Contributing: http://www.plupload.com/contributing
10416
 */
10417
 
10418
/**
10419
@class moxie/runtime/html4/xhr/XMLHttpRequest
10420
@private
10421
*/
10422
define("moxie/runtime/html4/xhr/XMLHttpRequest", [
10423
        "moxie/runtime/html4/Runtime",
10424
        "moxie/core/utils/Basic",
10425
        "moxie/core/utils/Dom",
10426
        "moxie/core/utils/Url",
10427
        "moxie/core/Exceptions",
10428
        "moxie/core/utils/Events",
10429
        "moxie/file/Blob",
10430
        "moxie/xhr/FormData"
10431
], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) {
10432
 
10433
        function XMLHttpRequest() {
10434
                var _status, _response, _iframe;
10435
 
10436
                function cleanup(cb) {
10437
                        var target = this, uid, form, inputs, i, hasFile = false;
10438
 
10439
                        if (!_iframe) {
10440
                                return;
10441
                        }
10442
 
10443
                        uid = _iframe.id.replace(/_iframe$/, '');
10444
 
10445
                        form = Dom.get(uid + '_form');
10446
                        if (form) {
10447
                                inputs = form.getElementsByTagName('input');
10448
                                i = inputs.length;
10449
 
10450
                                while (i--) {
10451
                                        switch (inputs[i].getAttribute('type')) {
10452
                                                case 'hidden':
10453
                                                        inputs[i].parentNode.removeChild(inputs[i]);
10454
                                                        break;
10455
                                                case 'file':
10456
                                                        hasFile = true; // flag the case for later
10457
                                                        break;
10458
                                        }
10459
                                }
10460
                                inputs = [];
10461
 
10462
                                if (!hasFile) { // we need to keep the form for sake of possible retries
10463
                                        form.parentNode.removeChild(form);
10464
                                }
10465
                                form = null;
10466
                        }
10467
 
10468
                        // without timeout, request is marked as canceled (in console)
10469
                        setTimeout(function() {
10470
                                Events.removeEvent(_iframe, 'load', target.uid);
10471
                                if (_iframe.parentNode) { // #382
10472
                                        _iframe.parentNode.removeChild(_iframe);
10473
                                }
10474
 
10475
                                // check if shim container has any other children, if - not, remove it as well
10476
                                var shimContainer = target.getRuntime().getShimContainer();
10477
                                if (!shimContainer.children.length) {
10478
                                        shimContainer.parentNode.removeChild(shimContainer);
10479
                                }
10480
 
10481
                                shimContainer = _iframe = null;
10482
                                cb();
10483
                        }, 1);
10484
                }
10485
 
10486
                Basic.extend(this, {
10487
                        send: function(meta, data) {
10488
                                var target = this, I = target.getRuntime(), uid, form, input, blob;
10489
 
10490
                                _status = _response = null;
10491
 
10492
                                function createIframe() {
10493
                                        var container = I.getShimContainer() || document.body
10494
                                        , temp = document.createElement('div')
10495
                                        ;
10496
 
10497
                                        // IE 6 won't be able to set the name using setAttribute or iframe.name
10498
                                        temp.innerHTML = '<iframe id="' + uid + '_iframe" name="' + uid + '_iframe" src="javascript:&quot;&quot;" style="display:none"></iframe>';
10499
                                        _iframe = temp.firstChild;
10500
                                        container.appendChild(_iframe);
10501
 
10502
                                        /* _iframe.onreadystatechange = function() {
10503
                                                console.info(_iframe.readyState);
10504
                                        };*/
10505
 
10506
                                        Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8
10507
                                                var el;
10508
 
10509
                                                try {
10510
                                                        el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document;
10511
 
10512
                                                        // try to detect some standard error pages
10513
                                                        if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error
10514
                                                                _status = el.title.replace(/^(\d+).*$/, '$1');
10515
                                                        } else {
10516
                                                                _status = 200;
10517
                                                                // get result
10518
                                                                _response = Basic.trim(el.body.innerHTML);
10519
 
10520
                                                                // we need to fire these at least once
10521
                                                                target.trigger({
10522
                                                                        type: 'progress',
10523
                                                                        loaded: _response.length,
10524
                                                                        total: _response.length
10525
                                                                });
10526
 
10527
                                                                if (blob) { // if we were uploading a file
10528
                                                                        target.trigger({
10529
                                                                                type: 'uploadprogress',
10530
                                                                                loaded: blob.size || 1025,
10531
                                                                                total: blob.size || 1025
10532
                                                                        });
10533
                                                                }
10534
                                                        }
10535
                                                } catch (ex) {
10536
                                                        if (Url.hasSameOrigin(meta.url)) {
10537
                                                                // if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm
10538
                                                                // which obviously results to cross domain error (wtf?)
10539
                                                                _status = 404;
10540
                                                        } else {
10541
                                                                cleanup.call(target, function() {
10542
                                                                        target.trigger('error');
10543
                                                                });
10544
                                                                return;
10545
                                                        }
10546
                                                }      
10547
 
10548
                                                cleanup.call(target, function() {
10549
                                                        target.trigger('load');
10550
                                                });
10551
                                        }, target.uid);
10552
                                } // end createIframe
10553
 
10554
                                // prepare data to be sent and convert if required
10555
                                if (data instanceof FormData && data.hasBlob()) {
10556
                                        blob = data.getBlob();
10557
                                        uid = blob.uid;
10558
                                        input = Dom.get(uid);
10559
                                        form = Dom.get(uid + '_form');
10560
                                        if (!form) {
10561
                                                throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
10562
                                        }
10563
                                } else {
10564
                                        uid = Basic.guid('uid_');
10565
 
10566
                                        form = document.createElement('form');
10567
                                        form.setAttribute('id', uid + '_form');
10568
                                        form.setAttribute('method', meta.method);
10569
                                        form.setAttribute('enctype', 'multipart/form-data');
10570
                                        form.setAttribute('encoding', 'multipart/form-data');
10571
                                        form.setAttribute('target', uid + '_iframe');
10572
 
10573
                                        I.getShimContainer().appendChild(form);
10574
                                }
10575
 
10576
                                if (data instanceof FormData) {
10577
                                        data.each(function(value, name) {
10578
                                                if (value instanceof Blob) {
10579
                                                        if (input) {
10580
                                                                input.setAttribute('name', name);
10581
                                                        }
10582
                                                } else {
10583
                                                        var hidden = document.createElement('input');
10584
 
10585
                                                        Basic.extend(hidden, {
10586
                                                                type : 'hidden',
10587
                                                                name : name,
10588
                                                                value : value
10589
                                                        });
10590
 
10591
                                                        // make sure that input[type="file"], if it's there, comes last
10592
                                                        if (input) {
10593
                                                                form.insertBefore(hidden, input);
10594
                                                        } else {
10595
                                                                form.appendChild(hidden);
10596
                                                        }
10597
                                                }
10598
                                        });
10599
                                }
10600
 
10601
                                // set destination url
10602
                                form.setAttribute("action", meta.url);
10603
 
10604
                                createIframe();
10605
                                form.submit();
10606
                                target.trigger('loadstart');
10607
                        },
10608
 
10609
                        getStatus: function() {
10610
                                return _status;
10611
                        },
10612
 
10613
                        getResponse: function(responseType) {
10614
                                if ('json' === responseType) {
10615
                                        // strip off <pre>..</pre> tags that might be enclosing the response
10616
                                        if (Basic.typeOf(_response) === 'string' && !!window.JSON) {
10617
                                                try {
10618
                                                        return JSON.parse(_response.replace(/^\s*<pre[^>]*>/, '').replace(/<\/pre>\s*$/, ''));
10619
                                                } catch (ex) {
10620
                                                        return null;
10621
                                                }
10622
                                        }
10623
                                } else if ('document' === responseType) {
10624
 
10625
                                }
10626
                                return _response;
10627
                        },
10628
 
10629
                        abort: function() {
10630
                                var target = this;
10631
 
10632
                                if (_iframe && _iframe.contentWindow) {
10633
                                        if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome
10634
                                                _iframe.contentWindow.stop();
10635
                                        } else if (_iframe.contentWindow.document.execCommand) { // IE
10636
                                                _iframe.contentWindow.document.execCommand('Stop');
10637
                                        } else {
10638
                                                _iframe.src = "about:blank";
10639
                                        }
10640
                                }
10641
 
10642
                                cleanup.call(this, function() {
10643
                                        // target.dispatchEvent('readystatechange');
10644
                                        target.dispatchEvent('abort');
10645
                                });
10646
                        }
10647
                });
10648
        }
10649
 
10650
        return (extensions.XMLHttpRequest = XMLHttpRequest);
10651
});
10652
 
10653
// Included from: src/javascript/runtime/html4/image/Image.js
10654
 
10655
/**
10656
 * Image.js
10657
 *
10658
 * Copyright 2013, Moxiecode Systems AB
10659
 * Released under GPL License.
10660
 *
10661
 * License: http://www.plupload.com/license
10662
 * Contributing: http://www.plupload.com/contributing
10663
 */
10664
 
10665
/**
10666
@class moxie/runtime/html4/image/Image
10667
@private
10668
*/
10669
define("moxie/runtime/html4/image/Image", [
10670
        "moxie/runtime/html4/Runtime",
10671
        "moxie/runtime/html5/image/Image"
10672
], function(extensions, Image) {
10673
        return (extensions.Image = Image);
10674
});
10675
 
10676
expose(["moxie/core/utils/Basic","moxie/core/I18n","moxie/core/utils/Mime","moxie/core/utils/Env","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/EventTarget","moxie/core/utils/Encode","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/file/File","moxie/file/FileInput","moxie/file/FileDrop","moxie/runtime/RuntimeTarget","moxie/file/FileReader","moxie/core/utils/Url","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/image/Image","moxie/core/utils/Events"]);
10677
})(this);/**
10678
 * o.js
10679
 *
10680
 * Copyright 2013, Moxiecode Systems AB
10681
 * Released under GPL License.
10682
 *
10683
 * License: http://www.plupload.com/license
10684
 * Contributing: http://www.plupload.com/contributing
10685
 */
10686
 
10687
/*global moxie:true */
10688
 
10689
/**
10690
Globally exposed namespace with the most frequently used public classes and handy methods.
10691
 
10692
@class o
10693
@static
10694
@private
10695
*/
10696
(function(exports) {
10697
        "use strict";
10698
 
10699
        var o = {}, inArray = exports.moxie.core.utils.Basic.inArray;
10700
 
10701
        // directly add some public classes
10702
        // (we do it dynamically here, since for custom builds we cannot know beforehand what modules were included)
10703
        (function addAlias(ns) {
10704
                var name, itemType;
10705
                for (name in ns) {
10706
                        itemType = typeof(ns[name]);
10707
                        if (itemType === 'object' && !~inArray(name, ['Exceptions', 'Env', 'Mime'])) {
10708
                                addAlias(ns[name]);
10709
                        } else if (itemType === 'function') {
10710
                                o[name] = ns[name];
10711
                        }
10712
                }
10713
        })(exports.moxie);
10714
 
10715
        // add some manually
10716
        o.Env = exports.moxie.core.utils.Env;
10717
        o.Mime = exports.moxie.core.utils.Mime;
10718
        o.Exceptions = exports.moxie.core.Exceptions;
10719
 
10720
        // expose globally
10721
        exports.mOxie = o;
10722
        if (!exports.o) {
10723
                exports.o = o;
10724
        }
10725
        return o;
10726
})(this);