WordPress.org

Make WordPress Core

Ticket #41755: 41755.2.patch

File 41755.2.patch, 537.1 KB (added by azaozz, 4 years ago)
  • src/wp-admin/includes/media.php

     
    18681868 */
    18691869$post_params = apply_filters( 'upload_post_params', $post_params );
    18701870
     1871/*
     1872 * Since 4.9 the `runtimes` setting is hardcoded in our version of Plupload to `html5,html4`,
     1873 * and the `flash_swf_url` and `silverlight_xap_url` are not used.
     1874 */
    18711875$plupload_init = array(
    1872         'runtimes'            => 'html5,flash,silverlight,html4',
    18731876        'browse_button'       => 'plupload-browse-button',
    18741877        'container'           => 'plupload-upload-ui',
    18751878        'drop_element'        => 'drag-drop-area',
    18761879        'file_data_name'      => 'async-upload',
    18771880        'url'                 => $upload_action_url,
    1878         'flash_swf_url'       => includes_url( 'js/plupload/plupload.flash.swf' ),
    1879         'silverlight_xap_url' => includes_url( 'js/plupload/plupload.silverlight.xap' ),
    18801881        'filters' => array(
    18811882                'max_file_size'   => $max_upload_size . 'b',
    18821883        ),
  • src/wp-admin/includes/update-core.php

     
    712712'wp-includes/js/tinymce/skins/lightgray/fonts/tinymce-small.json',
    713713'wp-includes/js/tinymce/skins/lightgray/fonts/tinymce.json',
    714714'wp-includes/js/tinymce/skins/lightgray/skin.ie7.min.css',
     715// 4.9
     716'wp-includes/js/plupload/plupload.flash.swf',
     717'wp-includes/js/plupload/plupload.silverlight.xap',
    715718);
    716719
    717720/**
  • src/wp-includes/js/plupload/moxie.js

     
     1;var MXI_DEBUG = true;
     2/**
     3 * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
     4 * v1.3.5
     5 *
     6 * Copyright 2013, Moxiecode Systems AB
     7 * Released under GPL License.
     8 *
     9 * License: http://www.plupload.com/license
     10 * Contributing: http://www.plupload.com/contributing
     11 *
     12 * Date: 2016-05-15
     13 */
     14/**
     15 * Compiled inline version. (Library mode)
     16 */
     17
     18/**
     19 * Modified for WordPress, Silverlight and Flash runtimes support was removed.
     20 * See https://core.trac.wordpress.org/ticket/41755.
     21 */
     22
     23/*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
     24/*globals $code */
     25
     26(function(exports, undefined) {
     27        "use strict";
     28
     29        var modules = {};
     30
     31        function require(ids, callback) {
     32                var module, defs = [];
     33
     34                for (var i = 0; i < ids.length; ++i) {
     35                        module = modules[ids[i]] || resolve(ids[i]);
     36                        if (!module) {
     37                                throw 'module definition dependecy not found: ' + ids[i];
     38                        }
     39
     40                        defs.push(module);
     41                }
     42
     43                callback.apply(null, defs);
     44        }
     45
     46        function define(id, dependencies, definition) {
     47                if (typeof id !== 'string') {
     48                        throw 'invalid module definition, module id must be defined and be a string';
     49                }
     50
     51                if (dependencies === undefined) {
     52                        throw 'invalid module definition, dependencies must be specified';
     53                }
     54
     55                if (definition === undefined) {
     56                        throw 'invalid module definition, definition function must be specified';
     57                }
     58
     59                require(dependencies, function() {
     60                        modules[id] = definition.apply(null, arguments);
     61                });
     62        }
     63
     64        function defined(id) {
     65                return !!modules[id];
     66        }
     67
     68        function resolve(id) {
     69                var target = exports;
     70                var fragments = id.split(/[.\/]/);
     71
     72                for (var fi = 0; fi < fragments.length; ++fi) {
     73                        if (!target[fragments[fi]]) {
     74                                return;
     75                        }
     76
     77                        target = target[fragments[fi]];
     78                }
     79
     80                return target;
     81        }
     82
     83        function expose(ids) {
     84                for (var i = 0; i < ids.length; i++) {
     85                        var target = exports;
     86                        var id = ids[i];
     87                        var fragments = id.split(/[.\/]/);
     88
     89                        for (var fi = 0; fi < fragments.length - 1; ++fi) {
     90                                if (target[fragments[fi]] === undefined) {
     91                                        target[fragments[fi]] = {};
     92                                }
     93
     94                                target = target[fragments[fi]];
     95                        }
     96
     97                        target[fragments[fragments.length - 1]] = modules[id];
     98                }
     99        }
     100
     101// Included from: src/javascript/core/utils/Basic.js
     102
     103/**
     104 * Basic.js
     105 *
     106 * Copyright 2013, Moxiecode Systems AB
     107 * Released under GPL License.
     108 *
     109 * License: http://www.plupload.com/license
     110 * Contributing: http://www.plupload.com/contributing
     111 */
     112
     113define('moxie/core/utils/Basic', [], function() {
     114        /**
     115        Gets the true type of the built-in object (better version of typeof).
     116        @author Angus Croll (http://javascriptweblog.wordpress.com/)
     117
     118        @method typeOf
     119        @for Utils
     120        @static
     121        @param {Object} o Object to check.
     122        @return {String} Object [[Class]]
     123        */
     124        var typeOf = function(o) {
     125                var undef;
     126
     127                if (o === undef) {
     128                        return 'undefined';
     129                } else if (o === null) {
     130                        return 'null';
     131                } else if (o.nodeType) {
     132                        return 'node';
     133                }
     134
     135                // the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8
     136                return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase();
     137        };
     138               
     139        /**
     140        Extends the specified object with another object.
     141
     142        @method extend
     143        @static
     144        @param {Object} target Object to extend.
     145        @param {Object} [obj]* Multiple objects to extend with.
     146        @return {Object} Same as target, the extended object.
     147        */
     148        var extend = function(target) {
     149                var undef;
     150
     151                each(arguments, function(arg, i) {
     152                        if (i > 0) {
     153                                each(arg, function(value, key) {
     154                                        if (value !== undef) {
     155                                                if (typeOf(target[key]) === typeOf(value) && !!~inArray(typeOf(value), ['array', 'object'])) {
     156                                                        extend(target[key], value);
     157                                                } else {
     158                                                        target[key] = value;
     159                                                }
     160                                        }
     161                                });
     162                        }
     163                });
     164                return target;
     165        };
     166               
     167        /**
     168        Executes the callback function for each item in array/object. If you return false in the
     169        callback it will break the loop.
     170
     171        @method each
     172        @static
     173        @param {Object} obj Object to iterate.
     174        @param {function} callback Callback function to execute for each item.
     175        */
     176        var each = function(obj, callback) {
     177                var length, key, i, undef;
     178
     179                if (obj) {
     180                        if (typeOf(obj.length) === 'number') { // it might be Array, FileList or even arguments object
     181                                // Loop array items
     182                                for (i = 0, length = obj.length; i < length; i++) {
     183                                        if (callback(obj[i], i) === false) {
     184                                                return;
     185                                        }
     186                                }
     187                        } else if (typeOf(obj) === 'object') {
     188                                // Loop object items
     189                                for (key in obj) {
     190                                        if (obj.hasOwnProperty(key)) {
     191                                                if (callback(obj[key], key) === false) {
     192                                                        return;
     193                                                }
     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 error
     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. The only way a user would be able to get the same ID is if the two persons
     388        at the same exact millisecond manage to get the same 5 random numbers between 0-65535; it also uses
     389        a counter so each ID is guaranteed to be unique for the given page. It is more probable for the earth
     390        to be hit with an asteroid.
     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
     451                size = /^([0-9\.]+)([tmgk]?)$/.exec(size.toLowerCase().replace(/[^0-9\.tmkg]/g, ''));
     452                mul = size[2];
     453                size = +size[1];
     454               
     455                if (muls.hasOwnProperty(mul)) {
     456                        size *= muls[mul];
     457                }
     458                return Math.floor(size);
     459        };
     460
     461
     462        /**
     463         * Pseudo sprintf implementation - simple way to replace tokens with specified values.
     464         *
     465         * @param {String} str String with tokens
     466         * @return {String} String with replaced tokens
     467         */
     468        var sprintf = function(str) {
     469                var args = [].slice.call(arguments, 1);
     470
     471                return str.replace(/%[a-z]/g, function() {
     472                        var value = args.shift();
     473                        return typeOf(value) !== 'undefined' ? value : '';
     474                });
     475        };
     476       
     477
     478        return {
     479                guid: guid,
     480                typeOf: typeOf,
     481                extend: extend,
     482                each: each,
     483                isEmptyObj: isEmptyObj,
     484                inSeries: inSeries,
     485                inParallel: inParallel,
     486                inArray: inArray,
     487                arrayDiff: arrayDiff,
     488                arrayIntersect: arrayIntersect,
     489                toArray: toArray,
     490                trim: trim,
     491                sprintf: sprintf,
     492                parseSizeStr: parseSizeStr
     493        };
     494});
     495
     496// Included from: src/javascript/core/utils/Env.js
     497
     498/**
     499 * Env.js
     500 *
     501 * Copyright 2013, Moxiecode Systems AB
     502 * Released under GPL License.
     503 *
     504 * License: http://www.plupload.com/license
     505 * Contributing: http://www.plupload.com/contributing
     506 */
     507
     508define("moxie/core/utils/Env", [
     509        "moxie/core/utils/Basic"
     510], function(Basic) {
     511       
     512        /**
     513         * UAParser.js v0.7.7
     514         * Lightweight JavaScript-based User-Agent string parser
     515         * https://github.com/faisalman/ua-parser-js
     516         *
     517         * Copyright © 2012-2015 Faisal Salman <fyzlman@gmail.com>
     518         * Dual licensed under GPLv2 & MIT
     519         */
     520        var UAParser = (function (undefined) {
     521
     522            //////////////
     523            // Constants
     524            /////////////
     525
     526
     527            var EMPTY       = '',
     528                UNKNOWN     = '?',
     529                FUNC_TYPE   = 'function',
     530                UNDEF_TYPE  = 'undefined',
     531                OBJ_TYPE    = 'object',
     532                MAJOR       = 'major',
     533                MODEL       = 'model',
     534                NAME        = 'name',
     535                TYPE        = 'type',
     536                VENDOR      = 'vendor',
     537                VERSION     = 'version',
     538                ARCHITECTURE= 'architecture',
     539                CONSOLE     = 'console',
     540                MOBILE      = 'mobile',
     541                TABLET      = 'tablet';
     542
     543
     544            ///////////
     545            // Helper
     546            //////////
     547
     548
     549            var util = {
     550                has : function (str1, str2) {
     551                    return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1;
     552                },
     553                lowerize : function (str) {
     554                    return str.toLowerCase();
     555                }
     556            };
     557
     558
     559            ///////////////
     560            // Map helper
     561            //////////////
     562
     563
     564            var mapper = {
     565
     566                rgx : function () {
     567
     568                    // loop through all regexes maps
     569                    for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) {
     570
     571                        var regex = args[i],       // even sequence (0,2,4,..)
     572                            props = args[i + 1];   // odd sequence (1,3,5,..)
     573
     574                        // construct object barebones
     575                        if (typeof(result) === UNDEF_TYPE) {
     576                            result = {};
     577                            for (p in props) {
     578                                q = props[p];
     579                                if (typeof(q) === OBJ_TYPE) {
     580                                    result[q[0]] = undefined;
     581                                } else {
     582                                    result[q] = undefined;
     583                                }
     584                            }
     585                        }
     586
     587                        // try matching uastring with regexes
     588                        for (j = k = 0; j < regex.length; j++) {
     589                            matches = regex[j].exec(this.getUA());
     590                            if (!!matches) {
     591                                for (p = 0; p < props.length; p++) {
     592                                    match = matches[++k];
     593                                    q = props[p];
     594                                    // check if given property is actually array
     595                                    if (typeof(q) === OBJ_TYPE && q.length > 0) {
     596                                        if (q.length == 2) {
     597                                            if (typeof(q[1]) == FUNC_TYPE) {
     598                                                // assign modified match
     599                                                result[q[0]] = q[1].call(this, match);
     600                                            } else {
     601                                                // assign given value, ignore regex match
     602                                                result[q[0]] = q[1];
     603                                            }
     604                                        } else if (q.length == 3) {
     605                                            // check whether function or regex
     606                                            if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) {
     607                                                // call function (usually string mapper)
     608                                                result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
     609                                            } else {
     610                                                // sanitize match using given regex
     611                                                result[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
     612                                            }
     613                                        } else if (q.length == 4) {
     614                                                result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
     615                                        }
     616                                    } else {
     617                                        result[q] = match ? match : undefined;
     618                                    }
     619                                }
     620                                break;
     621                            }
     622                        }
     623
     624                        if(!!matches) break; // break the loop immediately if match found
     625                    }
     626                    return result;
     627                },
     628
     629                str : function (str, map) {
     630
     631                    for (var i in map) {
     632                        // check if array
     633                        if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) {
     634                            for (var j = 0; j < map[i].length; j++) {
     635                                if (util.has(map[i][j], str)) {
     636                                    return (i === UNKNOWN) ? undefined : i;
     637                                }
     638                            }
     639                        } else if (util.has(map[i], str)) {
     640                            return (i === UNKNOWN) ? undefined : i;
     641                        }
     642                    }
     643                    return str;
     644                }
     645            };
     646
     647
     648            ///////////////
     649            // String map
     650            //////////////
     651
     652
     653            var maps = {
     654
     655                browser : {
     656                    oldsafari : {
     657                        major : {
     658                            '1' : ['/8', '/1', '/3'],
     659                            '2' : '/4',
     660                            '?' : '/'
     661                        },
     662                        version : {
     663                            '1.0'   : '/8',
     664                            '1.2'   : '/1',
     665                            '1.3'   : '/3',
     666                            '2.0'   : '/412',
     667                            '2.0.2' : '/416',
     668                            '2.0.3' : '/417',
     669                            '2.0.4' : '/419',
     670                            '?'     : '/'
     671                        }
     672                    }
     673                },
     674
     675                device : {
     676                    sprint : {
     677                        model : {
     678                            'Evo Shift 4G' : '7373KT'
     679                        },
     680                        vendor : {
     681                            'HTC'       : 'APA',
     682                            'Sprint'    : 'Sprint'
     683                        }
     684                    }
     685                },
     686
     687                os : {
     688                    windows : {
     689                        version : {
     690                            'ME'        : '4.90',
     691                            'NT 3.11'   : 'NT3.51',
     692                            'NT 4.0'    : 'NT4.0',
     693                            '2000'      : 'NT 5.0',
     694                            'XP'        : ['NT 5.1', 'NT 5.2'],
     695                            'Vista'     : 'NT 6.0',
     696                            '7'         : 'NT 6.1',
     697                            '8'         : 'NT 6.2',
     698                            '8.1'       : 'NT 6.3',
     699                            'RT'        : 'ARM'
     700                        }
     701                    }
     702                }
     703            };
     704
     705
     706            //////////////
     707            // Regex map
     708            /////////////
     709
     710
     711            var regexes = {
     712
     713                browser : [[
     714               
     715                    // Presto based
     716                    /(opera\smini)\/([\w\.-]+)/i,                                       // Opera Mini
     717                    /(opera\s[mobiletab]+).+version\/([\w\.-]+)/i,                      // Opera Mobi/Tablet
     718                    /(opera).+version\/([\w\.]+)/i,                                     // Opera > 9.80
     719                    /(opera)[\/\s]+([\w\.]+)/i                                          // Opera < 9.80
     720
     721                    ], [NAME, VERSION], [
     722
     723                    /\s(opr)\/([\w\.]+)/i                                               // Opera Webkit
     724                    ], [[NAME, 'Opera'], VERSION], [
     725
     726                    // Mixed
     727                    /(kindle)\/([\w\.]+)/i,                                             // Kindle
     728                    /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?([\w\.]+)*/i,
     729                                                                                        // Lunascape/Maxthon/Netfront/Jasmine/Blazer
     730
     731                    // Trident based
     732                    /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?([\w\.]*)/i,
     733                                                                                        // Avant/IEMobile/SlimBrowser/Baidu
     734                    /(?:ms|\()(ie)\s([\w\.]+)/i,                                        // Internet Explorer
     735
     736                    // Webkit/KHTML based
     737                    /(rekonq)\/([\w\.]+)*/i,                                            // Rekonq
     738                    /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi)\/([\w\.-]+)/i
     739                                                                                        // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron
     740                    ], [NAME, VERSION], [
     741
     742                    /(trident).+rv[:\s]([\w\.]+).+like\sgecko/i                         // IE11
     743                    ], [[NAME, 'IE'], VERSION], [
     744
     745                    /(edge)\/((\d+)?[\w\.]+)/i                                          // Microsoft Edge
     746                    ], [NAME, VERSION], [
     747
     748                    /(yabrowser)\/([\w\.]+)/i                                           // Yandex
     749                    ], [[NAME, 'Yandex'], VERSION], [
     750
     751                    /(comodo_dragon)\/([\w\.]+)/i                                       // Comodo Dragon
     752                    ], [[NAME, /_/g, ' '], VERSION], [
     753
     754                    /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?([\w\.]+)/i,
     755                                                                                        // Chrome/OmniWeb/Arora/Tizen/Nokia
     756                    /(uc\s?browser|qqbrowser)[\/\s]?([\w\.]+)/i
     757                                                                                        // UCBrowser/QQBrowser
     758                    ], [NAME, VERSION], [
     759
     760                    /(dolfin)\/([\w\.]+)/i                                              // Dolphin
     761                    ], [[NAME, 'Dolphin'], VERSION], [
     762
     763                    /((?:android.+)crmo|crios)\/([\w\.]+)/i                             // Chrome for Android/iOS
     764                    ], [[NAME, 'Chrome'], VERSION], [
     765
     766                    /XiaoMi\/MiuiBrowser\/([\w\.]+)/i                                   // MIUI Browser
     767                    ], [VERSION, [NAME, 'MIUI Browser']], [
     768
     769                    /android.+version\/([\w\.]+)\s+(?:mobile\s?safari|safari)/i         // Android Browser
     770                    ], [VERSION, [NAME, 'Android Browser']], [
     771
     772                    /FBAV\/([\w\.]+);/i                                                 // Facebook App for iOS
     773                    ], [VERSION, [NAME, 'Facebook']], [
     774
     775                    /version\/([\w\.]+).+?mobile\/\w+\s(safari)/i                       // Mobile Safari
     776                    ], [VERSION, [NAME, 'Mobile Safari']], [
     777
     778                    /version\/([\w\.]+).+?(mobile\s?safari|safari)/i                    // Safari & Safari Mobile
     779                    ], [VERSION, NAME], [
     780
     781                    /webkit.+?(mobile\s?safari|safari)(\/[\w\.]+)/i                     // Safari < 3.0
     782                    ], [NAME, [VERSION, mapper.str, maps.browser.oldsafari.version]], [
     783
     784                    /(konqueror)\/([\w\.]+)/i,                                          // Konqueror
     785                    /(webkit|khtml)\/([\w\.]+)/i
     786                    ], [NAME, VERSION], [
     787
     788                    // Gecko based
     789                    /(navigator|netscape)\/([\w\.-]+)/i                                 // Netscape
     790                    ], [[NAME, 'Netscape'], VERSION], [
     791                    /(swiftfox)/i,                                                      // Swiftfox
     792                    /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?([\w\.\+]+)/i,
     793                                                                                        // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
     794                    /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/([\w\.-]+)/i,
     795                                                                                        // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
     796                    /(mozilla)\/([\w\.]+).+rv\:.+gecko\/\d+/i,                          // Mozilla
     797
     798                    // Other
     799                    /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf)[\/\s]?([\w\.]+)/i,
     800                                                                                        // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf
     801                    /(links)\s\(([\w\.]+)/i,                                            // Links
     802                    /(gobrowser)\/?([\w\.]+)*/i,                                        // GoBrowser
     803                    /(ice\s?browser)\/v?([\w\._]+)/i,                                   // ICE Browser
     804                    /(mosaic)[\/\s]([\w\.]+)/i                                          // Mosaic
     805                    ], [NAME, VERSION]
     806                ],
     807
     808                engine : [[
     809
     810                    /windows.+\sedge\/([\w\.]+)/i                                       // EdgeHTML
     811                    ], [VERSION, [NAME, 'EdgeHTML']], [
     812
     813                    /(presto)\/([\w\.]+)/i,                                             // Presto
     814                    /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i,     // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m
     815                    /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i,                          // KHTML/Tasman/Links
     816                    /(icab)[\/\s]([23]\.[\d\.]+)/i                                      // iCab
     817                    ], [NAME, VERSION], [
     818
     819                    /rv\:([\w\.]+).*(gecko)/i                                           // Gecko
     820                    ], [VERSION, NAME]
     821                ],
     822
     823                os : [[
     824
     825                    // Windows based
     826                    /microsoft\s(windows)\s(vista|xp)/i                                 // Windows (iTunes)
     827                    ], [NAME, VERSION], [
     828                    /(windows)\snt\s6\.2;\s(arm)/i,                                     // Windows RT
     829                    /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i
     830                    ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [
     831                    /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
     832                    ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [
     833
     834                    // Mobile/Embedded OS
     835                    /\((bb)(10);/i                                                      // BlackBerry 10
     836                    ], [[NAME, 'BlackBerry'], VERSION], [
     837                    /(blackberry)\w*\/?([\w\.]+)*/i,                                    // Blackberry
     838                    /(tizen)[\/\s]([\w\.]+)/i,                                          // Tizen
     839                    /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego|contiki)[\/\s-]?([\w\.]+)*/i,
     840                                                                                        // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo/Contiki
     841                    /linux;.+(sailfish);/i                                              // Sailfish OS
     842                    ], [NAME, VERSION], [
     843                    /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i                 // Symbian
     844                    ], [[NAME, 'Symbian'], VERSION], [
     845                    /\((series40);/i                                                    // Series 40
     846                    ], [NAME], [
     847                    /mozilla.+\(mobile;.+gecko.+firefox/i                               // Firefox OS
     848                    ], [[NAME, 'Firefox OS'], VERSION], [
     849
     850                    // Console
     851                    /(nintendo|playstation)\s([wids3portablevu]+)/i,                    // Nintendo/Playstation
     852
     853                    // GNU/Linux based
     854                    /(mint)[\/\s\(]?(\w+)*/i,                                           // Mint
     855                    /(mageia|vectorlinux)[;\s]/i,                                       // Mageia/VectorLinux
     856                    /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk|linpus)[\/\s-]?([\w\.-]+)*/i,
     857                                                                                        // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware
     858                                                                                        // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus
     859                    /(hurd|linux)\s?([\w\.]+)*/i,                                       // Hurd/Linux
     860                    /(gnu)\s?([\w\.]+)*/i                                               // GNU
     861                    ], [NAME, VERSION], [
     862
     863                    /(cros)\s[\w]+\s([\w\.]+\w)/i                                       // Chromium OS
     864                    ], [[NAME, 'Chromium OS'], VERSION],[
     865
     866                    // Solaris
     867                    /(sunos)\s?([\w\.]+\d)*/i                                           // Solaris
     868                    ], [[NAME, 'Solaris'], VERSION], [
     869
     870                    // BSD based
     871                    /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i                   // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
     872                    ], [NAME, VERSION],[
     873
     874                    /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i             // iOS
     875                    ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [
     876
     877                    /(mac\sos\sx)\s?([\w\s\.]+\w)*/i,
     878                    /(macintosh|mac(?=_powerpc)\s)/i                                    // Mac OS
     879                    ], [[NAME, 'Mac OS'], [VERSION, /_/g, '.']], [
     880
     881                    // Other
     882                    /((?:open)?solaris)[\/\s-]?([\w\.]+)*/i,                            // Solaris
     883                    /(haiku)\s(\w+)/i,                                                  // Haiku
     884                    /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i,                               // AIX
     885                    /(plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos|openvms)/i,
     886                                                                                        // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS/OpenVMS
     887                    /(unix)\s?([\w\.]+)*/i                                              // UNIX
     888                    ], [NAME, VERSION]
     889                ]
     890            };
     891
     892
     893            /////////////////
     894            // Constructor
     895            ////////////////
     896
     897
     898            var UAParser = function (uastring) {
     899
     900                var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
     901
     902                this.getBrowser = function () {
     903                    return mapper.rgx.apply(this, regexes.browser);
     904                };
     905                this.getEngine = function () {
     906                    return mapper.rgx.apply(this, regexes.engine);
     907                };
     908                this.getOS = function () {
     909                    return mapper.rgx.apply(this, regexes.os);
     910                };
     911                this.getResult = function() {
     912                    return {
     913                        ua      : this.getUA(),
     914                        browser : this.getBrowser(),
     915                        engine  : this.getEngine(),
     916                        os      : this.getOS()
     917                    };
     918                };
     919                this.getUA = function () {
     920                    return ua;
     921                };
     922                this.setUA = function (uastring) {
     923                    ua = uastring;
     924                    return this;
     925                };
     926                this.setUA(ua);
     927            };
     928
     929            return UAParser;
     930        })();
     931
     932
     933        function version_compare(v1, v2, operator) {
     934          // From: http://phpjs.org/functions
     935          // +      original by: Philippe Jausions (http://pear.php.net/user/jausions)
     936          // +      original by: Aidan Lister (http://aidanlister.com/)
     937          // + reimplemented by: Kankrelune (http://www.webfaktory.info/)
     938          // +      improved by: Brett Zamir (http://brett-zamir.me)
     939          // +      improved by: Scott Baker
     940          // +      improved by: Theriault
     941          // *        example 1: version_compare('8.2.5rc', '8.2.5a');
     942          // *        returns 1: 1
     943          // *        example 2: version_compare('8.2.50', '8.2.52', '<');
     944          // *        returns 2: true
     945          // *        example 3: version_compare('5.3.0-dev', '5.3.0');
     946          // *        returns 3: -1
     947          // *        example 4: version_compare('4.1.0.52','4.01.0.51');
     948          // *        returns 4: 1
     949
     950          // Important: compare must be initialized at 0.
     951          var i = 0,
     952            x = 0,
     953            compare = 0,
     954            // vm maps textual PHP versions to negatives so they're less than 0.
     955            // PHP currently defines these as CASE-SENSITIVE. It is important to
     956            // leave these as negatives so that they can come before numerical versions
     957            // and as if no letters were there to begin with.
     958            // (1alpha is < 1 and < 1.1 but > 1dev1)
     959            // If a non-numerical value can't be mapped to this table, it receives
     960            // -7 as its value.
     961            vm = {
     962              'dev': -6,
     963              'alpha': -5,
     964              'a': -5,
     965              'beta': -4,
     966              'b': -4,
     967              'RC': -3,
     968              'rc': -3,
     969              '#': -2,
     970              'p': 1,
     971              'pl': 1
     972            },
     973            // This function will be called to prepare each version argument.
     974            // It replaces every _, -, and + with a dot.
     975            // It surrounds any nonsequence of numbers/dots with dots.
     976            // It replaces sequences of dots with a single dot.
     977            //    version_compare('4..0', '4.0') == 0
     978            // Important: A string of 0 length needs to be converted into a value
     979            // even less than an unexisting value in vm (-7), hence [-8].
     980            // It's also important to not strip spaces because of this.
     981            //   version_compare('', ' ') == 1
     982            prepVersion = function (v) {
     983              v = ('' + v).replace(/[_\-+]/g, '.');
     984              v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
     985              return (!v.length ? [-8] : v.split('.'));
     986            },
     987            // This converts a version component to a number.
     988            // Empty component becomes 0.
     989            // Non-numerical component becomes a negative number.
     990            // Numerical component becomes itself as an integer.
     991            numVersion = function (v) {
     992              return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
     993            };
     994
     995          v1 = prepVersion(v1);
     996          v2 = prepVersion(v2);
     997          x = Math.max(v1.length, v2.length);
     998          for (i = 0; i < x; i++) {
     999            if (v1[i] == v2[i]) {
     1000              continue;
     1001            }
     1002            v1[i] = numVersion(v1[i]);
     1003            v2[i] = numVersion(v2[i]);
     1004            if (v1[i] < v2[i]) {
     1005              compare = -1;
     1006              break;
     1007            } else if (v1[i] > v2[i]) {
     1008              compare = 1;
     1009              break;
     1010            }
     1011          }
     1012          if (!operator) {
     1013            return compare;
     1014          }
     1015
     1016          // Important: operator is CASE-SENSITIVE.
     1017          // "No operator" seems to be treated as "<."
     1018          // Any other values seem to make the function return null.
     1019          switch (operator) {
     1020          case '>':
     1021          case 'gt':
     1022            return (compare > 0);
     1023          case '>=':
     1024          case 'ge':
     1025            return (compare >= 0);
     1026          case '<=':
     1027          case 'le':
     1028            return (compare <= 0);
     1029          case '==':
     1030          case '=':
     1031          case 'eq':
     1032            return (compare === 0);
     1033          case '<>':
     1034          case '!=':
     1035          case 'ne':
     1036            return (compare !== 0);
     1037          case '':
     1038          case '<':
     1039          case 'lt':
     1040            return (compare < 0);
     1041          default:
     1042            return null;
     1043          }
     1044        }
     1045
     1046
     1047        var can = (function() {
     1048                var caps = {
     1049                                define_property: (function() {
     1050                                        /* // currently too much extra code required, not exactly worth it
     1051                                        try { // as of IE8, getters/setters are supported only on DOM elements
     1052                                                var obj = {};
     1053                                                if (Object.defineProperty) {
     1054                                                        Object.defineProperty(obj, 'prop', {
     1055                                                                enumerable: true,
     1056                                                                configurable: true
     1057                                                        });
     1058                                                        return true;
     1059                                                }
     1060                                        } catch(ex) {}
     1061
     1062                                        if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) {
     1063                                                return true;
     1064                                        }*/
     1065                                        return false;
     1066                                }()),
     1067
     1068                                create_canvas: (function() {
     1069                                        // On the S60 and BB Storm, getContext exists, but always returns undefined
     1070                                        // so we actually have to call getContext() to verify
     1071                                        // github.com/Modernizr/Modernizr/issues/issue/97/
     1072                                        var el = document.createElement('canvas');
     1073                                        return !!(el.getContext && el.getContext('2d'));
     1074                                }()),
     1075
     1076                                return_response_type: function(responseType) {
     1077                                        try {
     1078                                                if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) {
     1079                                                        return true;
     1080                                                } else if (window.XMLHttpRequest) {
     1081                                                        var xhr = new XMLHttpRequest();
     1082                                                        xhr.open('get', '/'); // otherwise Gecko throws an exception
     1083                                                        if ('responseType' in xhr) {
     1084                                                                xhr.responseType = responseType;
     1085                                                                // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?)
     1086                                                                if (xhr.responseType !== responseType) {
     1087                                                                        return false;
     1088                                                                }
     1089                                                                return true;
     1090                                                        }
     1091                                                }
     1092                                        } catch (ex) {}
     1093                                        return false;
     1094                                },
     1095
     1096                                // ideas for this heavily come from Modernizr (http://modernizr.com/)
     1097                                use_data_uri: (function() {
     1098                                        var du = new Image();
     1099
     1100                                        du.onload = function() {
     1101                                                caps.use_data_uri = (du.width === 1 && du.height === 1);
     1102                                        };
     1103                                       
     1104                                        setTimeout(function() {
     1105                                                du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw==";
     1106                                        }, 1);
     1107                                        return false;
     1108                                }()),
     1109
     1110                                use_data_uri_over32kb: function() { // IE8
     1111                                        return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9);
     1112                                },
     1113
     1114                                use_data_uri_of: function(bytes) {
     1115                                        return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb());
     1116                                },
     1117
     1118                                use_fileinput: function() {
     1119                                        if (navigator.userAgent.match(/(Android (1.0|1.1|1.5|1.6|2.0|2.1))|(Windows Phone (OS 7|8.0))|(XBLWP)|(ZuneWP)|(w(eb)?OSBrowser)|(webOS)|(Kindle\/(1.0|2.0|2.5|3.0))/)) {
     1120                                                return false;
     1121                                        }
     1122
     1123                                        var el = document.createElement('input');
     1124                                        el.setAttribute('type', 'file');
     1125                                        return !el.disabled;
     1126                                }
     1127                        };
     1128
     1129                return function(cap) {
     1130                        var args = [].slice.call(arguments);
     1131                        args.shift(); // shift of cap
     1132                        return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap];
     1133                };
     1134        }());
     1135
     1136
     1137        var uaResult = new UAParser().getResult();
     1138
     1139
     1140        var Env = {
     1141                can: can,
     1142
     1143                uaParser: UAParser,
     1144               
     1145                browser: uaResult.browser.name,
     1146                version: uaResult.browser.version,
     1147                os: uaResult.os.name, // everybody intuitively types it in a lowercase for some reason
     1148                osVersion: uaResult.os.version,
     1149
     1150                verComp: version_compare,
     1151
     1152                global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent"
     1153        };
     1154
     1155        // for backward compatibility
     1156        // @deprecated Use `Env.os` instead
     1157        Env.OS = Env.os;
     1158
     1159        if (MXI_DEBUG) {
     1160                Env.debug = {
     1161                        runtime: true,
     1162                        events: false
     1163                };
     1164
     1165                Env.log = function() {
     1166                       
     1167                        function logObj(data) {
     1168                                // TODO: this should recursively print out the object in a pretty way
     1169                                console.appendChild(document.createTextNode(data + "\n"));
     1170                        }
     1171
     1172                        var data = arguments[0];
     1173
     1174                        if (Basic.typeOf(data) === 'string') {
     1175                                data = Basic.sprintf.apply(this, arguments);
     1176                        }
     1177
     1178                        if (window && window.console && window.console.log) {
     1179                                window.console.log(data);
     1180                        } else if (document) {
     1181                                var console = document.getElementById('moxie-console');
     1182                                if (!console) {
     1183                                        console = document.createElement('pre');
     1184                                        console.id = 'moxie-console';
     1185                                        //console.style.display = 'none';
     1186                                        document.body.appendChild(console);
     1187                                }
     1188
     1189                                if (Basic.inArray(Basic.typeOf(data), ['object', 'array']) !== -1) {
     1190                                        logObj(data);
     1191                                } else {
     1192                                        console.appendChild(document.createTextNode(data + "\n"));
     1193                                }
     1194                        }
     1195                };
     1196        }
     1197
     1198        return Env;
     1199});
     1200
     1201// Included from: src/javascript/core/I18n.js
     1202
     1203/**
     1204 * I18n.js
     1205 *
     1206 * Copyright 2013, Moxiecode Systems AB
     1207 * Released under GPL License.
     1208 *
     1209 * License: http://www.plupload.com/license
     1210 * Contributing: http://www.plupload.com/contributing
     1211 */
     1212
     1213define("moxie/core/I18n", [
     1214        "moxie/core/utils/Basic"
     1215], function(Basic) {
     1216        var i18n = {};
     1217
     1218        return {
     1219                /**
     1220                 * Extends the language pack object with new items.
     1221                 *
     1222                 * @param {Object} pack Language pack items to add.
     1223                 * @return {Object} Extended language pack object.
     1224                 */
     1225                addI18n: function(pack) {
     1226                        return Basic.extend(i18n, pack);
     1227                },
     1228
     1229                /**
     1230                 * Translates the specified string by checking for the english string in the language pack lookup.
     1231                 *
     1232                 * @param {String} str String to look for.
     1233                 * @return {String} Translated string or the input string if it wasn't found.
     1234                 */
     1235                translate: function(str) {
     1236                        return i18n[str] || str;
     1237                },
     1238
     1239                /**
     1240                 * Shortcut for translate function
     1241                 *
     1242                 * @param {String} str String to look for.
     1243                 * @return {String} Translated string or the input string if it wasn't found.
     1244                 */
     1245                _: function(str) {
     1246                        return this.translate(str);
     1247                },
     1248
     1249                /**
     1250                 * Pseudo sprintf implementation - simple way to replace tokens with specified values.
     1251                 *
     1252                 * @param {String} str String with tokens
     1253                 * @return {String} String with replaced tokens
     1254                 */
     1255                sprintf: function(str) {
     1256                        var args = [].slice.call(arguments, 1);
     1257
     1258                        return str.replace(/%[a-z]/g, function() {
     1259                                var value = args.shift();
     1260                                return Basic.typeOf(value) !== 'undefined' ? value : '';
     1261                        });
     1262                }
     1263        };
     1264});
     1265
     1266// Included from: src/javascript/core/utils/Mime.js
     1267
     1268/**
     1269 * Mime.js
     1270 *
     1271 * Copyright 2013, Moxiecode Systems AB
     1272 * Released under GPL License.
     1273 *
     1274 * License: http://www.plupload.com/license
     1275 * Contributing: http://www.plupload.com/contributing
     1276 */
     1277
     1278define("moxie/core/utils/Mime", [
     1279        "moxie/core/utils/Basic",
     1280        "moxie/core/I18n"
     1281], function(Basic, I18n) {
     1282       
     1283        var mimeData = "" +
     1284                "application/msword,doc dot," +
     1285                "application/pdf,pdf," +
     1286                "application/pgp-signature,pgp," +
     1287                "application/postscript,ps ai eps," +
     1288                "application/rtf,rtf," +
     1289                "application/vnd.ms-excel,xls xlb," +
     1290                "application/vnd.ms-powerpoint,ppt pps pot," +
     1291                "application/zip,zip," +
     1292                "application/x-shockwave-flash,swf swfl," +
     1293                "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," +
     1294                "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," +
     1295                "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," +
     1296                "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," +
     1297                "application/vnd.openxmlformats-officedocument.presentationml.template,potx," +
     1298                "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," +
     1299                "application/x-javascript,js," +
     1300                "application/json,json," +
     1301                "audio/mpeg,mp3 mpga mpega mp2," +
     1302                "audio/x-wav,wav," +
     1303                "audio/x-m4a,m4a," +
     1304                "audio/ogg,oga ogg," +
     1305                "audio/aiff,aiff aif," +
     1306                "audio/flac,flac," +
     1307                "audio/aac,aac," +
     1308                "audio/ac3,ac3," +
     1309                "audio/x-ms-wma,wma," +
     1310                "image/bmp,bmp," +
     1311                "image/gif,gif," +
     1312                "image/jpeg,jpg jpeg jpe," +
     1313                "image/photoshop,psd," +
     1314                "image/png,png," +
     1315                "image/svg+xml,svg svgz," +
     1316                "image/tiff,tiff tif," +
     1317                "text/plain,asc txt text diff log," +
     1318                "text/html,htm html xhtml," +
     1319                "text/css,css," +
     1320                "text/csv,csv," +
     1321                "text/rtf,rtf," +
     1322                "video/mpeg,mpeg mpg mpe m2v," +
     1323                "video/quicktime,qt mov," +
     1324                "video/mp4,mp4," +
     1325                "video/x-m4v,m4v," +
     1326                "video/x-flv,flv," +
     1327                "video/x-ms-wmv,wmv," +
     1328                "video/avi,avi," +
     1329                "video/webm,webm," +
     1330                "video/3gpp,3gpp 3gp," +
     1331                "video/3gpp2,3g2," +
     1332                "video/vnd.rn-realvideo,rv," +
     1333                "video/ogg,ogv," +
     1334                "video/x-matroska,mkv," +
     1335                "application/vnd.oasis.opendocument.formula-template,otf," +
     1336                "application/octet-stream,exe";
     1337       
     1338       
     1339        var Mime = {
     1340
     1341                mimes: {},
     1342
     1343                extensions: {},
     1344
     1345                // Parses the default mime types string into a mimes and extensions lookup maps
     1346                addMimeType: function (mimeData) {
     1347                        var items = mimeData.split(/,/), i, ii, ext;
     1348                       
     1349                        for (i = 0; i < items.length; i += 2) {
     1350                                ext = items[i + 1].split(/ /);
     1351
     1352                                // extension to mime lookup
     1353                                for (ii = 0; ii < ext.length; ii++) {
     1354                                        this.mimes[ext[ii]] = items[i];
     1355                                }
     1356                                // mime to extension lookup
     1357                                this.extensions[items[i]] = ext;
     1358                        }
     1359                },
     1360
     1361
     1362                extList2mimes: function (filters, addMissingExtensions) {
     1363                        var self = this, ext, i, ii, type, mimes = [];
     1364                       
     1365                        // convert extensions to mime types list
     1366                        for (i = 0; i < filters.length; i++) {
     1367                                ext = filters[i].extensions.split(/\s*,\s*/);
     1368
     1369                                for (ii = 0; ii < ext.length; ii++) {
     1370                                       
     1371                                        // if there's an asterisk in the list, then accept attribute is not required
     1372                                        if (ext[ii] === '*') {
     1373                                                return [];
     1374                                        }
     1375
     1376                                        type = self.mimes[ext[ii]];
     1377                                        if (type && Basic.inArray(type, mimes) === -1) {
     1378                                                mimes.push(type);
     1379                                        }
     1380
     1381                                        // future browsers should filter by extension, finally
     1382                                        if (addMissingExtensions && /^\w+$/.test(ext[ii])) {
     1383                                                mimes.push('.' + ext[ii]);
     1384                                        } else if (!type) {
     1385                                                // if we have no type in our map, then accept all
     1386                                                return [];
     1387                                        }
     1388                                }
     1389                        }
     1390                        return mimes;
     1391                },
     1392
     1393
     1394                mimes2exts: function(mimes) {
     1395                        var self = this, exts = [];
     1396                       
     1397                        Basic.each(mimes, function(mime) {
     1398                                if (mime === '*') {
     1399                                        exts = [];
     1400                                        return false;
     1401                                }
     1402
     1403                                // check if this thing looks like mime type
     1404                                var m = mime.match(/^(\w+)\/(\*|\w+)$/);
     1405                                if (m) {
     1406                                        if (m[2] === '*') {
     1407                                                // wildcard mime type detected
     1408                                                Basic.each(self.extensions, function(arr, mime) {
     1409                                                        if ((new RegExp('^' + m[1] + '/')).test(mime)) {
     1410                                                                [].push.apply(exts, self.extensions[mime]);
     1411                                                        }
     1412                                                });
     1413                                        } else if (self.extensions[mime]) {
     1414                                                [].push.apply(exts, self.extensions[mime]);
     1415                                        }
     1416                                }
     1417                        });
     1418                        return exts;
     1419                },
     1420
     1421
     1422                mimes2extList: function(mimes) {
     1423                        var accept = [], exts = [];
     1424
     1425                        if (Basic.typeOf(mimes) === 'string') {
     1426                                mimes = Basic.trim(mimes).split(/\s*,\s*/);
     1427                        }
     1428
     1429                        exts = this.mimes2exts(mimes);
     1430                       
     1431                        accept.push({
     1432                                title: I18n.translate('Files'),
     1433                                extensions: exts.length ? exts.join(',') : '*'
     1434                        });
     1435                       
     1436                        // save original mimes string
     1437                        accept.mimes = mimes;
     1438
     1439                        return accept;
     1440                },
     1441
     1442
     1443                getFileExtension: function(fileName) {
     1444                        var matches = fileName && fileName.match(/\.([^.]+)$/);
     1445                        if (matches) {
     1446                                return matches[1].toLowerCase();
     1447                        }
     1448                        return '';
     1449                },
     1450
     1451                getFileMime: function(fileName) {
     1452                        return this.mimes[this.getFileExtension(fileName)] || '';
     1453                }
     1454        };
     1455
     1456        Mime.addMimeType(mimeData);
     1457
     1458        return Mime;
     1459});
     1460
     1461// Included from: src/javascript/core/utils/Dom.js
     1462
     1463/**
     1464 * Dom.js
     1465 *
     1466 * Copyright 2013, Moxiecode Systems AB
     1467 * Released under GPL License.
     1468 *
     1469 * License: http://www.plupload.com/license
     1470 * Contributing: http://www.plupload.com/contributing
     1471 */
     1472
     1473define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
     1474
     1475        /**
     1476        Get DOM Element by it's id.
     1477
     1478        @method get
     1479        @for Utils
     1480        @param {String} id Identifier of the DOM Element
     1481        @return {DOMElement}
     1482        */
     1483        var get = function(id) {
     1484                if (typeof id !== 'string') {
     1485                        return id;
     1486                }
     1487                return document.getElementById(id);
     1488        };
     1489
     1490        /**
     1491        Checks if specified DOM element has specified class.
     1492
     1493        @method hasClass
     1494        @static
     1495        @param {Object} obj DOM element like object to add handler to.
     1496        @param {String} name Class name
     1497        */
     1498        var hasClass = function(obj, name) {
     1499                if (!obj.className) {
     1500                        return false;
     1501                }
     1502
     1503                var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
     1504                return regExp.test(obj.className);
     1505        };
     1506
     1507        /**
     1508        Adds specified className to specified DOM element.
     1509
     1510        @method addClass
     1511        @static
     1512        @param {Object} obj DOM element like object to add handler to.
     1513        @param {String} name Class name
     1514        */
     1515        var addClass = function(obj, name) {
     1516                if (!hasClass(obj, name)) {
     1517                        obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name;
     1518                }
     1519        };
     1520
     1521        /**
     1522        Removes specified className from specified DOM element.
     1523
     1524        @method removeClass
     1525        @static
     1526        @param {Object} obj DOM element like object to add handler to.
     1527        @param {String} name Class name
     1528        */
     1529        var removeClass = function(obj, name) {
     1530                if (obj.className) {
     1531                        var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
     1532                        obj.className = obj.className.replace(regExp, function($0, $1, $2) {
     1533                                return $1 === ' ' && $2 === ' ' ? ' ' : '';
     1534                        });
     1535                }
     1536        };
     1537
     1538        /**
     1539        Returns a given computed style of a DOM element.
     1540
     1541        @method getStyle
     1542        @static
     1543        @param {Object} obj DOM element like object.
     1544        @param {String} name Style you want to get from the DOM element
     1545        */
     1546        var getStyle = function(obj, name) {
     1547                if (obj.currentStyle) {
     1548                        return obj.currentStyle[name];
     1549                } else if (window.getComputedStyle) {
     1550                        return window.getComputedStyle(obj, null)[name];
     1551                }
     1552        };
     1553
     1554
     1555        /**
     1556        Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields.
     1557
     1558        @method getPos
     1559        @static
     1560        @param {Element} node HTML element or element id to get x, y position from.
     1561        @param {Element} root Optional root element to stop calculations at.
     1562        @return {object} Absolute position of the specified element object with x, y fields.
     1563        */
     1564        var getPos = function(node, root) {
     1565                var x = 0, y = 0, parent, doc = document, nodeRect, rootRect;
     1566
     1567                node = node;
     1568                root = root || doc.body;
     1569
     1570                // Returns the x, y cordinate for an element on IE 6 and IE 7
     1571                function getIEPos(node) {
     1572                        var bodyElm, rect, x = 0, y = 0;
     1573
     1574                        if (node) {
     1575                                rect = node.getBoundingClientRect();
     1576                                bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body;
     1577                                x = rect.left + bodyElm.scrollLeft;
     1578                                y = rect.top + bodyElm.scrollTop;
     1579                        }
     1580
     1581                        return {
     1582                                x : x,
     1583                                y : y
     1584                        };
     1585                }
     1586
     1587                // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode
     1588                if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) {
     1589                        nodeRect = getIEPos(node);
     1590                        rootRect = getIEPos(root);
     1591
     1592                        return {
     1593                                x : nodeRect.x - rootRect.x,
     1594                                y : nodeRect.y - rootRect.y
     1595                        };
     1596                }
     1597
     1598                parent = node;
     1599                while (parent && parent != root && parent.nodeType) {
     1600                        x += parent.offsetLeft || 0;
     1601                        y += parent.offsetTop || 0;
     1602                        parent = parent.offsetParent;
     1603                }
     1604
     1605                parent = node.parentNode;
     1606                while (parent && parent != root && parent.nodeType) {
     1607                        x -= parent.scrollLeft || 0;
     1608                        y -= parent.scrollTop || 0;
     1609                        parent = parent.parentNode;
     1610                }
     1611
     1612                return {
     1613                        x : x,
     1614                        y : y
     1615                };
     1616        };
     1617
     1618        /**
     1619        Returns the size of the specified node in pixels.
     1620
     1621        @method getSize
     1622        @static
     1623        @param {Node} node Node to get the size of.
     1624        @return {Object} Object with a w and h property.
     1625        */
     1626        var getSize = function(node) {
     1627                return {
     1628                        w : node.offsetWidth || node.clientWidth,
     1629                        h : node.offsetHeight || node.clientHeight
     1630                };
     1631        };
     1632
     1633        return {
     1634                get: get,
     1635                hasClass: hasClass,
     1636                addClass: addClass,
     1637                removeClass: removeClass,
     1638                getStyle: getStyle,
     1639                getPos: getPos,
     1640                getSize: getSize
     1641        };
     1642});
     1643
     1644// Included from: src/javascript/core/Exceptions.js
     1645
     1646/**
     1647 * Exceptions.js
     1648 *
     1649 * Copyright 2013, Moxiecode Systems AB
     1650 * Released under GPL License.
     1651 *
     1652 * License: http://www.plupload.com/license
     1653 * Contributing: http://www.plupload.com/contributing
     1654 */
     1655
     1656define('moxie/core/Exceptions', [
     1657        'moxie/core/utils/Basic'
     1658], function(Basic) {
     1659        function _findKey(obj, value) {
     1660                var key;
     1661                for (key in obj) {
     1662                        if (obj[key] === value) {
     1663                                return key;
     1664                        }
     1665                }
     1666                return null;
     1667        }
     1668
     1669        return {
     1670                RuntimeError: (function() {
     1671                        var namecodes = {
     1672                                NOT_INIT_ERR: 1,
     1673                                NOT_SUPPORTED_ERR: 9,
     1674                                JS_ERR: 4
     1675                        };
     1676
     1677                        function RuntimeError(code) {
     1678                                this.code = code;
     1679                                this.name = _findKey(namecodes, code);
     1680                                this.message = this.name + ": RuntimeError " + this.code;
     1681                        }
     1682                       
     1683                        Basic.extend(RuntimeError, namecodes);
     1684                        RuntimeError.prototype = Error.prototype;
     1685                        return RuntimeError;
     1686                }()),
     1687               
     1688                OperationNotAllowedException: (function() {
     1689                       
     1690                        function OperationNotAllowedException(code) {
     1691                                this.code = code;
     1692                                this.name = 'OperationNotAllowedException';
     1693                        }
     1694                       
     1695                        Basic.extend(OperationNotAllowedException, {
     1696                                NOT_ALLOWED_ERR: 1
     1697                        });
     1698                       
     1699                        OperationNotAllowedException.prototype = Error.prototype;
     1700                       
     1701                        return OperationNotAllowedException;
     1702                }()),
     1703
     1704                ImageError: (function() {
     1705                        var namecodes = {
     1706                                WRONG_FORMAT: 1,
     1707                                MAX_RESOLUTION_ERR: 2,
     1708                                INVALID_META_ERR: 3
     1709                        };
     1710
     1711                        function ImageError(code) {
     1712                                this.code = code;
     1713                                this.name = _findKey(namecodes, code);
     1714                                this.message = this.name + ": ImageError " + this.code;
     1715                        }
     1716                       
     1717                        Basic.extend(ImageError, namecodes);
     1718                        ImageError.prototype = Error.prototype;
     1719
     1720                        return ImageError;
     1721                }()),
     1722
     1723                FileException: (function() {
     1724                        var namecodes = {
     1725                                NOT_FOUND_ERR: 1,
     1726                                SECURITY_ERR: 2,
     1727                                ABORT_ERR: 3,
     1728                                NOT_READABLE_ERR: 4,
     1729                                ENCODING_ERR: 5,
     1730                                NO_MODIFICATION_ALLOWED_ERR: 6,
     1731                                INVALID_STATE_ERR: 7,
     1732                                SYNTAX_ERR: 8
     1733                        };
     1734
     1735                        function FileException(code) {
     1736                                this.code = code;
     1737                                this.name = _findKey(namecodes, code);
     1738                                this.message = this.name + ": FileException " + this.code;
     1739                        }
     1740                       
     1741                        Basic.extend(FileException, namecodes);
     1742                        FileException.prototype = Error.prototype;
     1743                        return FileException;
     1744                }()),
     1745               
     1746                DOMException: (function() {
     1747                        var namecodes = {
     1748                                INDEX_SIZE_ERR: 1,
     1749                                DOMSTRING_SIZE_ERR: 2,
     1750                                HIERARCHY_REQUEST_ERR: 3,
     1751                                WRONG_DOCUMENT_ERR: 4,
     1752                                INVALID_CHARACTER_ERR: 5,
     1753                                NO_DATA_ALLOWED_ERR: 6,
     1754                                NO_MODIFICATION_ALLOWED_ERR: 7,
     1755                                NOT_FOUND_ERR: 8,
     1756                                NOT_SUPPORTED_ERR: 9,
     1757                                INUSE_ATTRIBUTE_ERR: 10,
     1758                                INVALID_STATE_ERR: 11,
     1759                                SYNTAX_ERR: 12,
     1760                                INVALID_MODIFICATION_ERR: 13,
     1761                                NAMESPACE_ERR: 14,
     1762                                INVALID_ACCESS_ERR: 15,
     1763                                VALIDATION_ERR: 16,
     1764                                TYPE_MISMATCH_ERR: 17,
     1765                                SECURITY_ERR: 18,
     1766                                NETWORK_ERR: 19,
     1767                                ABORT_ERR: 20,
     1768                                URL_MISMATCH_ERR: 21,
     1769                                QUOTA_EXCEEDED_ERR: 22,
     1770                                TIMEOUT_ERR: 23,
     1771                                INVALID_NODE_TYPE_ERR: 24,
     1772                                DATA_CLONE_ERR: 25
     1773                        };
     1774
     1775                        function DOMException(code) {
     1776                                this.code = code;
     1777                                this.name = _findKey(namecodes, code);
     1778                                this.message = this.name + ": DOMException " + this.code;
     1779                        }
     1780                       
     1781                        Basic.extend(DOMException, namecodes);
     1782                        DOMException.prototype = Error.prototype;
     1783                        return DOMException;
     1784                }()),
     1785               
     1786                EventException: (function() {
     1787                        function EventException(code) {
     1788                                this.code = code;
     1789                                this.name = 'EventException';
     1790                        }
     1791                       
     1792                        Basic.extend(EventException, {
     1793                                UNSPECIFIED_EVENT_TYPE_ERR: 0
     1794                        });
     1795                       
     1796                        EventException.prototype = Error.prototype;
     1797                       
     1798                        return EventException;
     1799                }())
     1800        };
     1801});
     1802
     1803// Included from: src/javascript/core/EventTarget.js
     1804
     1805/**
     1806 * EventTarget.js
     1807 *
     1808 * Copyright 2013, Moxiecode Systems AB
     1809 * Released under GPL License.
     1810 *
     1811 * License: http://www.plupload.com/license
     1812 * Contributing: http://www.plupload.com/contributing
     1813 */
     1814
     1815define('moxie/core/EventTarget', [
     1816        'moxie/core/utils/Env',
     1817        'moxie/core/Exceptions',
     1818        'moxie/core/utils/Basic'
     1819], function(Env, x, Basic) {
     1820        /**
     1821        Parent object for all event dispatching components and objects
     1822
     1823        @class EventTarget
     1824        @constructor EventTarget
     1825        */
     1826        function EventTarget() {
     1827                // hash of event listeners by object uid
     1828                var eventpool = {};
     1829                               
     1830                Basic.extend(this, {
     1831                       
     1832                        /**
     1833                        Unique id of the event dispatcher, usually overriden by children
     1834
     1835                        @property uid
     1836                        @type String
     1837                        */
     1838                        uid: null,
     1839                       
     1840                        /**
     1841                        Can be called from within a child  in order to acquire uniqie id in automated manner
     1842
     1843                        @method init
     1844                        */
     1845                        init: function() {
     1846                                if (!this.uid) {
     1847                                        this.uid = Basic.guid('uid_');
     1848                                }
     1849                        },
     1850
     1851                        /**
     1852                        Register a handler to a specific event dispatched by the object
     1853
     1854                        @method addEventListener
     1855                        @param {String} type Type or basically a name of the event to subscribe to
     1856                        @param {Function} fn Callback function that will be called when event happens
     1857                        @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first
     1858                        @param {Object} [scope=this] A scope to invoke event handler in
     1859                        */
     1860                        addEventListener: function(type, fn, priority, scope) {
     1861                                var self = this, list;
     1862
     1863                                // without uid no event handlers can be added, so make sure we got one
     1864                                if (!this.hasOwnProperty('uid')) {
     1865                                        this.uid = Basic.guid('uid_');
     1866                                }
     1867                               
     1868                                type = Basic.trim(type);
     1869                               
     1870                                if (/\s/.test(type)) {
     1871                                        // multiple event types were passed for one handler
     1872                                        Basic.each(type.split(/\s+/), function(type) {
     1873                                                self.addEventListener(type, fn, priority, scope);
     1874                                        });
     1875                                        return;
     1876                                }
     1877                               
     1878                                type = type.toLowerCase();
     1879                                priority = parseInt(priority, 10) || 0;
     1880                               
     1881                                list = eventpool[this.uid] && eventpool[this.uid][type] || [];
     1882                                list.push({fn : fn, priority : priority, scope : scope || this});
     1883                               
     1884                                if (!eventpool[this.uid]) {
     1885                                        eventpool[this.uid] = {};
     1886                                }
     1887                                eventpool[this.uid][type] = list;
     1888                        },
     1889                       
     1890                        /**
     1891                        Check if any handlers were registered to the specified event
     1892
     1893                        @method hasEventListener
     1894                        @param {String} type Type or basically a name of the event to check
     1895                        @return {Mixed} Returns a handler if it was found and false, if - not
     1896                        */
     1897                        hasEventListener: function(type) {
     1898                                var list = type ? eventpool[this.uid] && eventpool[this.uid][type] : eventpool[this.uid];
     1899                                return list ? list : false;
     1900                        },
     1901                       
     1902                        /**
     1903                        Unregister the handler from the event, or if former was not specified - unregister all handlers
     1904
     1905                        @method removeEventListener
     1906                        @param {String} type Type or basically a name of the event
     1907                        @param {Function} [fn] Handler to unregister
     1908                        */
     1909                        removeEventListener: function(type, fn) {
     1910                                type = type.toLowerCase();
     1911       
     1912                                var list = eventpool[this.uid] && eventpool[this.uid][type], i;
     1913       
     1914                                if (list) {
     1915                                        if (fn) {
     1916                                                for (i = list.length - 1; i >= 0; i--) {
     1917                                                        if (list[i].fn === fn) {
     1918                                                                list.splice(i, 1);
     1919                                                                break;
     1920                                                        }
     1921                                                }
     1922                                        } else {
     1923                                                list = [];
     1924                                        }
     1925       
     1926                                        // delete event list if it has become empty
     1927                                        if (!list.length) {
     1928                                                delete eventpool[this.uid][type];
     1929                                               
     1930                                                // and object specific entry in a hash if it has no more listeners attached
     1931                                                if (Basic.isEmptyObj(eventpool[this.uid])) {
     1932                                                        delete eventpool[this.uid];
     1933                                                }
     1934                                        }
     1935                                }
     1936                        },
     1937                       
     1938                        /**
     1939                        Remove all event handlers from the object
     1940
     1941                        @method removeAllEventListeners
     1942                        */
     1943                        removeAllEventListeners: function() {
     1944                                if (eventpool[this.uid]) {
     1945                                        delete eventpool[this.uid];
     1946                                }
     1947                        },
     1948                       
     1949                        /**
     1950                        Dispatch the event
     1951
     1952                        @method dispatchEvent
     1953                        @param {String/Object} Type of event or event object to dispatch
     1954                        @param {Mixed} [...] Variable number of arguments to be passed to a handlers
     1955                        @return {Boolean} true by default and false if any handler returned false
     1956                        */
     1957                        dispatchEvent: function(type) {
     1958                                var uid, list, args, tmpEvt, evt = {}, result = true, undef;
     1959                               
     1960                                if (Basic.typeOf(type) !== 'string') {
     1961                                        // we can't use original object directly (because of Silverlight)
     1962                                        tmpEvt = type;
     1963
     1964                                        if (Basic.typeOf(tmpEvt.type) === 'string') {
     1965                                                type = tmpEvt.type;
     1966
     1967                                                if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event
     1968                                                        evt.total = tmpEvt.total;
     1969                                                        evt.loaded = tmpEvt.loaded;
     1970                                                }
     1971                                                evt.async = tmpEvt.async || false;
     1972                                        } else {
     1973                                                throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR);
     1974                                        }
     1975                                }
     1976                               
     1977                                // check if event is meant to be dispatched on an object having specific uid
     1978                                if (type.indexOf('::') !== -1) {
     1979                                        (function(arr) {
     1980                                                uid = arr[0];
     1981                                                type = arr[1];
     1982                                        }(type.split('::')));
     1983                                } else {
     1984                                        uid = this.uid;
     1985                                }
     1986                               
     1987                                type = type.toLowerCase();
     1988                                                               
     1989                                list = eventpool[uid] && eventpool[uid][type];
     1990
     1991                                if (list) {
     1992                                        // sort event list by prority
     1993                                        list.sort(function(a, b) { return b.priority - a.priority; });
     1994                                       
     1995                                        args = [].slice.call(arguments);
     1996                                       
     1997                                        // first argument will be pseudo-event object
     1998                                        args.shift();
     1999                                        evt.type = type;
     2000                                        args.unshift(evt);
     2001
     2002                                        if (MXI_DEBUG && Env.debug.events) {
     2003                                                Env.log("Event '%s' fired on %u", evt.type, uid);       
     2004                                        }
     2005
     2006                                        // Dispatch event to all listeners
     2007                                        var queue = [];
     2008                                        Basic.each(list, function(handler) {
     2009                                                // explicitly set the target, otherwise events fired from shims do not get it
     2010                                                args[0].target = handler.scope;
     2011                                                // if event is marked as async, detach the handler
     2012                                                if (evt.async) {
     2013                                                        queue.push(function(cb) {
     2014                                                                setTimeout(function() {
     2015                                                                        cb(handler.fn.apply(handler.scope, args) === false);
     2016                                                                }, 1);
     2017                                                        });
     2018                                                } else {
     2019                                                        queue.push(function(cb) {
     2020                                                                cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation
     2021                                                        });
     2022                                                }
     2023                                        });
     2024                                        if (queue.length) {
     2025                                                Basic.inSeries(queue, function(err) {
     2026                                                        result = !err;
     2027                                                });
     2028                                        }
     2029                                }
     2030                                return result;
     2031                        },
     2032                       
     2033                        /**
     2034                        Alias for addEventListener
     2035
     2036                        @method bind
     2037                        @protected
     2038                        */
     2039                        bind: function() {
     2040                                this.addEventListener.apply(this, arguments);
     2041                        },
     2042                       
     2043                        /**
     2044                        Alias for removeEventListener
     2045
     2046                        @method unbind
     2047                        @protected
     2048                        */
     2049                        unbind: function() {
     2050                                this.removeEventListener.apply(this, arguments);
     2051                        },
     2052                       
     2053                        /**
     2054                        Alias for removeAllEventListeners
     2055
     2056                        @method unbindAll
     2057                        @protected
     2058                        */
     2059                        unbindAll: function() {
     2060                                this.removeAllEventListeners.apply(this, arguments);
     2061                        },
     2062                       
     2063                        /**
     2064                        Alias for dispatchEvent
     2065
     2066                        @method trigger
     2067                        @protected
     2068                        */
     2069                        trigger: function() {
     2070                                return this.dispatchEvent.apply(this, arguments);
     2071                        },
     2072                       
     2073
     2074                        /**
     2075                        Handle properties of on[event] type.
     2076
     2077                        @method handleEventProps
     2078                        @private
     2079                        */
     2080                        handleEventProps: function(dispatches) {
     2081                                var self = this;
     2082
     2083                                this.bind(dispatches.join(' '), function(e) {
     2084                                        var prop = 'on' + e.type.toLowerCase();
     2085                                        if (Basic.typeOf(this[prop]) === 'function') {
     2086                                                this[prop].apply(this, arguments);
     2087                                        }
     2088                                });
     2089
     2090                                // object must have defined event properties, even if it doesn't make use of them
     2091                                Basic.each(dispatches, function(prop) {
     2092                                        prop = 'on' + prop.toLowerCase(prop);
     2093                                        if (Basic.typeOf(self[prop]) === 'undefined') {
     2094                                                self[prop] = null;
     2095                                        }
     2096                                });
     2097                        }
     2098                       
     2099                });
     2100        }
     2101
     2102        EventTarget.instance = new EventTarget();
     2103
     2104        return EventTarget;
     2105});
     2106
     2107// Included from: src/javascript/runtime/Runtime.js
     2108
     2109/**
     2110 * Runtime.js
     2111 *
     2112 * Copyright 2013, Moxiecode Systems AB
     2113 * Released under GPL License.
     2114 *
     2115 * License: http://www.plupload.com/license
     2116 * Contributing: http://www.plupload.com/contributing
     2117 */
     2118
     2119define('moxie/runtime/Runtime', [
     2120        "moxie/core/utils/Env",
     2121        "moxie/core/utils/Basic",
     2122        "moxie/core/utils/Dom",
     2123        "moxie/core/EventTarget"
     2124], function(Env, Basic, Dom, EventTarget) {
     2125        var runtimeConstructors = {}, runtimes = {};
     2126
     2127        /**
     2128        Common set of methods and properties for every runtime instance
     2129
     2130        @class Runtime
     2131
     2132        @param {Object} options
     2133        @param {String} type Sanitized name of the runtime
     2134        @param {Object} [caps] Set of capabilities that differentiate specified runtime
     2135        @param {Object} [modeCaps] Set of capabilities that do require specific operational mode
     2136        @param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested
     2137        */
     2138        function Runtime(options, type, caps, modeCaps, preferredMode) {
     2139                /**
     2140                Dispatched when runtime is initialized and ready.
     2141                Results in RuntimeInit on a connected component.
     2142
     2143                @event Init
     2144                */
     2145
     2146                /**
     2147                Dispatched when runtime fails to initialize.
     2148                Results in RuntimeError on a connected component.
     2149
     2150                @event Error
     2151                */
     2152
     2153                var self = this
     2154                , _shim
     2155                , _uid = Basic.guid(type + '_')
     2156                , defaultMode = preferredMode || 'browser'
     2157                ;
     2158
     2159                options = options || {};
     2160
     2161                // register runtime in private hash
     2162                runtimes[_uid] = this;
     2163
     2164                /**
     2165                Default set of capabilities, which can be redifined later by specific runtime
     2166
     2167                @private
     2168                @property caps
     2169                @type Object
     2170                */
     2171                caps = Basic.extend({
     2172                        // Runtime can:
     2173                        // provide access to raw binary data of the file
     2174                        access_binary: false,
     2175                        // provide access to raw binary data of the image (image extension is optional)
     2176                        access_image_binary: false,
     2177                        // display binary data as thumbs for example
     2178                        display_media: false,
     2179                        // make cross-domain requests
     2180                        do_cors: false,
     2181                        // accept files dragged and dropped from the desktop
     2182                        drag_and_drop: false,
     2183                        // filter files in selection dialog by their extensions
     2184                        filter_by_extension: true,
     2185                        // resize image (and manipulate it raw data of any file in general)
     2186                        resize_image: false,
     2187                        // periodically report how many bytes of total in the file were uploaded (loaded)
     2188                        report_upload_progress: false,
     2189                        // provide access to the headers of http response
     2190                        return_response_headers: false,
     2191                        // support response of specific type, which should be passed as an argument
     2192                        // e.g. runtime.can('return_response_type', 'blob')
     2193                        return_response_type: false,
     2194                        // return http status code of the response
     2195                        return_status_code: true,
     2196                        // send custom http header with the request
     2197                        send_custom_headers: false,
     2198                        // pick up the files from a dialog
     2199                        select_file: false,
     2200                        // select whole folder in file browse dialog
     2201                        select_folder: false,
     2202                        // select multiple files at once in file browse dialog
     2203                        select_multiple: true,
     2204                        // send raw binary data, that is generated after image resizing or manipulation of other kind
     2205                        send_binary_string: false,
     2206                        // send cookies with http request and therefore retain session
     2207                        send_browser_cookies: true,
     2208                        // send data formatted as multipart/form-data
     2209                        send_multipart: true,
     2210                        // slice the file or blob to smaller parts
     2211                        slice_blob: false,
     2212                        // upload file without preloading it to memory, stream it out directly from disk
     2213                        stream_upload: false,
     2214                        // programmatically trigger file browse dialog
     2215                        summon_file_dialog: false,
     2216                        // upload file of specific size, size should be passed as argument
     2217                        // e.g. runtime.can('upload_filesize', '500mb')
     2218                        upload_filesize: true,
     2219                        // initiate http request with specific http method, method should be passed as argument
     2220                        // e.g. runtime.can('use_http_method', 'put')
     2221                        use_http_method: true
     2222                }, caps);
     2223                       
     2224       
     2225                // default to the mode that is compatible with preferred caps
     2226                if (options.preferred_caps) {
     2227                        defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode);
     2228                }
     2229
     2230                if (MXI_DEBUG && Env.debug.runtime) {
     2231                        Env.log("\tdefault mode: %s", defaultMode);     
     2232                }
     2233               
     2234                // small extension factory here (is meant to be extended with actual extensions constructors)
     2235                _shim = (function() {
     2236                        var objpool = {};
     2237                        return {
     2238                                exec: function(uid, comp, fn, args) {
     2239                                        if (_shim[comp]) {
     2240                                                if (!objpool[uid]) {
     2241                                                        objpool[uid] = {
     2242                                                                context: this,
     2243                                                                instance: new _shim[comp]()
     2244                                                        };
     2245                                                }
     2246                                                if (objpool[uid].instance[fn]) {
     2247                                                        return objpool[uid].instance[fn].apply(this, args);
     2248                                                }
     2249                                        }
     2250                                },
     2251
     2252                                removeInstance: function(uid) {
     2253                                        delete objpool[uid];
     2254                                },
     2255
     2256                                removeAllInstances: function() {
     2257                                        var self = this;
     2258                                        Basic.each(objpool, function(obj, uid) {
     2259                                                if (Basic.typeOf(obj.instance.destroy) === 'function') {
     2260                                                        obj.instance.destroy.call(obj.context);
     2261                                                }
     2262                                                self.removeInstance(uid);
     2263                                        });
     2264                                }
     2265                        };
     2266                }());
     2267
     2268
     2269                // public methods
     2270                Basic.extend(this, {
     2271                        /**
     2272                        Specifies whether runtime instance was initialized or not
     2273
     2274                        @property initialized
     2275                        @type {Boolean}
     2276                        @default false
     2277                        */
     2278                        initialized: false, // shims require this flag to stop initialization retries
     2279
     2280                        /**
     2281                        Unique ID of the runtime
     2282
     2283                        @property uid
     2284                        @type {String}
     2285                        */
     2286                        uid: _uid,
     2287
     2288                        /**
     2289                        Runtime type (e.g. flash, html5, etc)
     2290
     2291                        @property type
     2292                        @type {String}
     2293                        */
     2294                        type: type,
     2295
     2296                        /**
     2297                        Runtime (not native one) may operate in browser or client mode.
     2298
     2299                        @property mode
     2300                        @private
     2301                        @type {String|Boolean} current mode or false, if none possible
     2302                        */
     2303                        mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode),
     2304
     2305                        /**
     2306                        id of the DOM container for the runtime (if available)
     2307
     2308                        @property shimid
     2309                        @type {String}
     2310                        */
     2311                        shimid: _uid + '_container',
     2312
     2313                        /**
     2314                        Number of connected clients. If equal to zero, runtime can be destroyed
     2315
     2316                        @property clients
     2317                        @type {Number}
     2318                        */
     2319                        clients: 0,
     2320
     2321                        /**
     2322                        Runtime initialization options
     2323
     2324                        @property options
     2325                        @type {Object}
     2326                        */
     2327                        options: options,
     2328
     2329                        /**
     2330                        Checks if the runtime has specific capability
     2331
     2332                        @method can
     2333                        @param {String} cap Name of capability to check
     2334                        @param {Mixed} [value] If passed, capability should somehow correlate to the value
     2335                        @param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set)
     2336                        @return {Boolean} true if runtime has such capability and false, if - not
     2337                        */
     2338                        can: function(cap, value) {
     2339                                var refCaps = arguments[2] || caps;
     2340
     2341                                // if cap var is a comma-separated list of caps, convert it to object (key/value)
     2342                                if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') {
     2343                                        cap = Runtime.parseCaps(cap);
     2344                                }
     2345
     2346                                if (Basic.typeOf(cap) === 'object') {
     2347                                        for (var key in cap) {
     2348                                                if (!this.can(key, cap[key], refCaps)) {
     2349                                                        return false;
     2350                                                }
     2351                                        }
     2352                                        return true;
     2353                                }
     2354
     2355                                // check the individual cap
     2356                                if (Basic.typeOf(refCaps[cap]) === 'function') {
     2357                                        return refCaps[cap].call(this, value);
     2358                                } else {
     2359                                        return (value === refCaps[cap]);
     2360                                }
     2361                        },
     2362
     2363                        /**
     2364                        Returns container for the runtime as DOM element
     2365
     2366                        @method getShimContainer
     2367                        @return {DOMElement}
     2368                        */
     2369                        getShimContainer: function() {
     2370                                var container, shimContainer = Dom.get(this.shimid);
     2371
     2372                                // if no container for shim, create one
     2373                                if (!shimContainer) {
     2374                                        container = this.options.container ? Dom.get(this.options.container) : document.body;
     2375
     2376                                        // create shim container and insert it at an absolute position into the outer container
     2377                                        shimContainer = document.createElement('div');
     2378                                        shimContainer.id = this.shimid;
     2379                                        shimContainer.className = 'moxie-shim moxie-shim-' + this.type;
     2380
     2381                                        Basic.extend(shimContainer.style, {
     2382                                                position: 'absolute',
     2383                                                top: '0px',
     2384                                                left: '0px',
     2385                                                width: '1px',
     2386                                                height: '1px',
     2387                                                overflow: 'hidden'
     2388                                        });
     2389
     2390                                        container.appendChild(shimContainer);
     2391                                        container = null;
     2392                                }
     2393
     2394                                return shimContainer;
     2395                        },
     2396
     2397                        /**
     2398                        Returns runtime as DOM element (if appropriate)
     2399
     2400                        @method getShim
     2401                        @return {DOMElement}
     2402                        */
     2403                        getShim: function() {
     2404                                return _shim;
     2405                        },
     2406
     2407                        /**
     2408                        Invokes a method within the runtime itself (might differ across the runtimes)
     2409
     2410                        @method shimExec
     2411                        @param {Mixed} []
     2412                        @protected
     2413                        @return {Mixed} Depends on the action and component
     2414                        */
     2415                        shimExec: function(component, action) {
     2416                                var args = [].slice.call(arguments, 2);
     2417                                return self.getShim().exec.call(this, this.uid, component, action, args);
     2418                        },
     2419
     2420                        /**
     2421                        Operaional interface that is used by components to invoke specific actions on the runtime
     2422                        (is invoked in the scope of component)
     2423
     2424                        @method exec
     2425                        @param {Mixed} []*
     2426                        @protected
     2427                        @return {Mixed} Depends on the action and component
     2428                        */
     2429                        exec: function(component, action) { // this is called in the context of component, not runtime
     2430                                var args = [].slice.call(arguments, 2);
     2431
     2432                                if (self[component] && self[component][action]) {
     2433                                        return self[component][action].apply(this, args);
     2434                                }
     2435                                return self.shimExec.apply(this, arguments);
     2436                        },
     2437
     2438                        /**
     2439                        Destroys the runtime (removes all events and deletes DOM structures)
     2440
     2441                        @method destroy
     2442                        */
     2443                        destroy: function() {
     2444                                if (!self) {
     2445                                        return; // obviously already destroyed
     2446                                }
     2447
     2448                                var shimContainer = Dom.get(this.shimid);
     2449                                if (shimContainer) {
     2450                                        shimContainer.parentNode.removeChild(shimContainer);
     2451                                }
     2452
     2453                                if (_shim) {
     2454                                        _shim.removeAllInstances();
     2455                                }
     2456
     2457                                this.unbindAll();
     2458                                delete runtimes[this.uid];
     2459                                this.uid = null; // mark this runtime as destroyed
     2460                                _uid = self = _shim = shimContainer = null;
     2461                        }
     2462                });
     2463
     2464                // once we got the mode, test against all caps
     2465                if (this.mode && options.required_caps && !this.can(options.required_caps)) {
     2466                        this.mode = false;
     2467                }       
     2468        }
     2469
     2470
     2471        /**
     2472        Default order to try different runtime types
     2473
     2474        @property order
     2475        @type String
     2476        @static
     2477        */
     2478        Runtime.order = 'html5,html4';
     2479
     2480
     2481        /**
     2482        Retrieves runtime from private hash by it's uid
     2483
     2484        @method getRuntime
     2485        @private
     2486        @static
     2487        @param {String} uid Unique identifier of the runtime
     2488        @return {Runtime|Boolean} Returns runtime, if it exists and false, if - not
     2489        */
     2490        Runtime.getRuntime = function(uid) {
     2491                return runtimes[uid] ? runtimes[uid] : false;
     2492        };
     2493
     2494
     2495        /**
     2496        Register constructor for the Runtime of new (or perhaps modified) type
     2497
     2498        @method addConstructor
     2499        @static
     2500        @param {String} type Runtime type (e.g. flash, html5, etc)
     2501        @param {Function} construct Constructor for the Runtime type
     2502        */
     2503        Runtime.addConstructor = function(type, constructor) {
     2504                constructor.prototype = EventTarget.instance;
     2505                runtimeConstructors[type] = constructor;
     2506        };
     2507
     2508
     2509        /**
     2510        Get the constructor for the specified type.
     2511
     2512        method getConstructor
     2513        @static
     2514        @param {String} type Runtime type (e.g. flash, html5, etc)
     2515        @return {Function} Constructor for the Runtime type
     2516        */
     2517        Runtime.getConstructor = function(type) {
     2518                return runtimeConstructors[type] || null;
     2519        };
     2520
     2521
     2522        /**
     2523        Get info about the runtime (uid, type, capabilities)
     2524
     2525        @method getInfo
     2526        @static
     2527        @param {String} uid Unique identifier of the runtime
     2528        @return {Mixed} Info object or null if runtime doesn't exist
     2529        */
     2530        Runtime.getInfo = function(uid) {
     2531                var runtime = Runtime.getRuntime(uid);
     2532
     2533                if (runtime) {
     2534                        return {
     2535                                uid: runtime.uid,
     2536                                type: runtime.type,
     2537                                mode: runtime.mode,
     2538                                can: function() {
     2539                                        return runtime.can.apply(runtime, arguments);
     2540                                }
     2541                        };
     2542                }
     2543                return null;
     2544        };
     2545
     2546
     2547        /**
     2548        Convert caps represented by a comma-separated string to the object representation.
     2549
     2550        @method parseCaps
     2551        @static
     2552        @param {String} capStr Comma-separated list of capabilities
     2553        @return {Object}
     2554        */
     2555        Runtime.parseCaps = function(capStr) {
     2556                var capObj = {};
     2557
     2558                if (Basic.typeOf(capStr) !== 'string') {
     2559                        return capStr || {};
     2560                }
     2561
     2562                Basic.each(capStr.split(','), function(key) {
     2563                        capObj[key] = true; // we assume it to be - true
     2564                });
     2565
     2566                return capObj;
     2567        };
     2568
     2569        /**
     2570        Test the specified runtime for specific capabilities.
     2571
     2572        @method can
     2573        @static
     2574        @param {String} type Runtime type (e.g. flash, html5, etc)
     2575        @param {String|Object} caps Set of capabilities to check
     2576        @return {Boolean} Result of the test
     2577        */
     2578        Runtime.can = function(type, caps) {
     2579                var runtime
     2580                , constructor = Runtime.getConstructor(type)
     2581                , mode
     2582                ;
     2583                if (constructor) {
     2584                        runtime = new constructor({
     2585                                required_caps: caps
     2586                        });
     2587                        mode = runtime.mode;
     2588                        runtime.destroy();
     2589                        return !!mode;
     2590                }
     2591                return false;
     2592        };
     2593
     2594
     2595        /**
     2596        Figure out a runtime that supports specified capabilities.
     2597
     2598        @method thatCan
     2599        @static
     2600        @param {String|Object} caps Set of capabilities to check
     2601        @param {String} [runtimeOrder] Comma-separated list of runtimes to check against
     2602        @return {String} Usable runtime identifier or null
     2603        */
     2604        Runtime.thatCan = function(caps, runtimeOrder) {
     2605                var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/);
     2606                for (var i in types) {
     2607                        if (Runtime.can(types[i], caps)) {
     2608                                return types[i];
     2609                        }
     2610                }
     2611                return null;
     2612        };
     2613
     2614
     2615        /**
     2616        Figure out an operational mode for the specified set of capabilities.
     2617
     2618        @method getMode
     2619        @static
     2620        @param {Object} modeCaps Set of capabilities that depend on particular runtime mode
     2621        @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for
     2622        @param {String|Boolean} [defaultMode='browser'] Default mode to use
     2623        @return {String|Boolean} Compatible operational mode
     2624        */
     2625        Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) {
     2626                var mode = null;
     2627
     2628                if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified
     2629                        defaultMode = 'browser';
     2630                }
     2631
     2632                if (requiredCaps && !Basic.isEmptyObj(modeCaps)) {
     2633                        // loop over required caps and check if they do require the same mode
     2634                        Basic.each(requiredCaps, function(value, cap) {
     2635                                if (modeCaps.hasOwnProperty(cap)) {
     2636                                        var capMode = modeCaps[cap](value);
     2637
     2638                                        // make sure we always have an array
     2639                                        if (typeof(capMode) === 'string') {
     2640                                                capMode = [capMode];
     2641                                        }
     2642                                       
     2643                                        if (!mode) {
     2644                                                mode = capMode;                                         
     2645                                        } else if (!(mode = Basic.arrayIntersect(mode, capMode))) {
     2646                                                // if cap requires conflicting mode - runtime cannot fulfill required caps
     2647
     2648                                                if (MXI_DEBUG && Env.debug.runtime) {
     2649                                                        Env.log("\t\t%c: %v (conflicting mode requested: %s)", cap, value, capMode);   
     2650                                                }
     2651
     2652                                                return (mode = false);
     2653                                        }                                       
     2654                                }
     2655
     2656                                if (MXI_DEBUG && Env.debug.runtime) {
     2657                                        Env.log("\t\t%c: %v (compatible modes: %s)", cap, value, mode);
     2658                                }
     2659                        });
     2660
     2661                        if (mode) {
     2662                                return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0];
     2663                        } else if (mode === false) {
     2664                                return false;
     2665                        }
     2666                }
     2667                return defaultMode;
     2668        };
     2669
     2670
     2671        /**
     2672        Capability check that always returns true
     2673
     2674        @private
     2675        @static
     2676        @return {True}
     2677        */
     2678        Runtime.capTrue = function() {
     2679                return true;
     2680        };
     2681
     2682        /**
     2683        Capability check that always returns false
     2684
     2685        @private
     2686        @static
     2687        @return {False}
     2688        */
     2689        Runtime.capFalse = function() {
     2690                return false;
     2691        };
     2692
     2693        /**
     2694        Evaluate the expression to boolean value and create a function that always returns it.
     2695
     2696        @private
     2697        @static
     2698        @param {Mixed} expr Expression to evaluate
     2699        @return {Function} Function returning the result of evaluation
     2700        */
     2701        Runtime.capTest = function(expr) {
     2702                return function() {
     2703                        return !!expr;
     2704                };
     2705        };
     2706
     2707        return Runtime;
     2708});
     2709
     2710// Included from: src/javascript/runtime/RuntimeClient.js
     2711
     2712/**
     2713 * RuntimeClient.js
     2714 *
     2715 * Copyright 2013, Moxiecode Systems AB
     2716 * Released under GPL License.
     2717 *
     2718 * License: http://www.plupload.com/license
     2719 * Contributing: http://www.plupload.com/contributing
     2720 */
     2721
     2722define('moxie/runtime/RuntimeClient', [
     2723        'moxie/core/utils/Env',
     2724        'moxie/core/Exceptions',
     2725        'moxie/core/utils/Basic',
     2726        'moxie/runtime/Runtime'
     2727], function(Env, x, Basic, Runtime) {
     2728        /**
     2729        Set of methods and properties, required by a component to acquire ability to connect to a runtime
     2730
     2731        @class RuntimeClient
     2732        */
     2733        return function RuntimeClient() {
     2734                var runtime;
     2735
     2736                Basic.extend(this, {
     2737                        /**
     2738                        Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one.
     2739                        Increments number of clients connected to the specified runtime.
     2740
     2741                        @private
     2742                        @method connectRuntime
     2743                        @param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites
     2744                        */
     2745                        connectRuntime: function(options) {
     2746                                var comp = this, ruid;
     2747
     2748                                function initialize(items) {
     2749                                        var type, constructor;
     2750
     2751                                        // if we ran out of runtimes
     2752                                        if (!items.length) {
     2753                                                comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
     2754                                                runtime = null;
     2755                                                return;
     2756                                        }
     2757
     2758                                        type = items.shift().toLowerCase();
     2759                                        constructor = Runtime.getConstructor(type);
     2760                                        if (!constructor) {
     2761                                                initialize(items);
     2762                                                return;
     2763                                        }
     2764
     2765                                        if (MXI_DEBUG && Env.debug.runtime) {
     2766                                                Env.log("Trying runtime: %s", type);
     2767                                                Env.log(options);
     2768                                        }
     2769
     2770                                        // try initializing the runtime
     2771                                        runtime = new constructor(options);
     2772
     2773                                        runtime.bind('Init', function() {
     2774                                                // mark runtime as initialized
     2775                                                runtime.initialized = true;
     2776
     2777                                                if (MXI_DEBUG && Env.debug.runtime) {
     2778                                                        Env.log("Runtime '%s' initialized", runtime.type);
     2779                                                }
     2780
     2781                                                // jailbreak ...
     2782                                                setTimeout(function() {
     2783                                                        runtime.clients++;
     2784                                                        // this will be triggered on component
     2785                                                        comp.trigger('RuntimeInit', runtime);
     2786                                                }, 1);
     2787                                        });
     2788
     2789                                        runtime.bind('Error', function() {
     2790                                                if (MXI_DEBUG && Env.debug.runtime) {
     2791                                                        Env.log("Runtime '%s' failed to initialize", runtime.type);
     2792                                                }
     2793
     2794                                                runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here
     2795                                                initialize(items);
     2796                                        });
     2797
     2798                                        /*runtime.bind('Exception', function() { });*/
     2799
     2800                                        if (MXI_DEBUG && Env.debug.runtime) {
     2801                                                Env.log("\tselected mode: %s", runtime.mode);   
     2802                                        }
     2803
     2804                                        // check if runtime managed to pick-up operational mode
     2805                                        if (!runtime.mode) {
     2806                                                runtime.trigger('Error');
     2807                                                return;
     2808                                        }
     2809
     2810                                        runtime.init();
     2811                                }
     2812
     2813                                // check if a particular runtime was requested
     2814                                if (Basic.typeOf(options) === 'string') {
     2815                                        ruid = options;
     2816                                } else if (Basic.typeOf(options.ruid) === 'string') {
     2817                                        ruid = options.ruid;
     2818                                }
     2819
     2820                                if (ruid) {
     2821                                        runtime = Runtime.getRuntime(ruid);
     2822                                        if (runtime) {
     2823                                                runtime.clients++;
     2824                                                return runtime;
     2825                                        } else {
     2826                                                // there should be a runtime and there's none - weird case
     2827                                                throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR);
     2828                                        }
     2829                                }
     2830
     2831                                // initialize a fresh one, that fits runtime list and required features best
     2832                                initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/));
     2833                        },
     2834
     2835
     2836                        /**
     2837                        Disconnects from the runtime. Decrements number of clients connected to the specified runtime.
     2838
     2839                        @private
     2840                        @method disconnectRuntime
     2841                        */
     2842                        disconnectRuntime: function() {
     2843                                if (runtime && --runtime.clients <= 0) {
     2844                                        runtime.destroy();
     2845                                }
     2846
     2847                                // once the component is disconnected, it shouldn't have access to the runtime
     2848                                runtime = null;
     2849                        },
     2850
     2851
     2852                        /**
     2853                        Returns the runtime to which the client is currently connected.
     2854
     2855                        @method getRuntime
     2856                        @return {Runtime} Runtime or null if client is not connected
     2857                        */
     2858                        getRuntime: function() {
     2859                                if (runtime && runtime.uid) {
     2860                                        return runtime;
     2861                                }
     2862                                return runtime = null; // make sure we do not leave zombies rambling around
     2863                        },
     2864
     2865
     2866                        /**
     2867                        Handy shortcut to safely invoke runtime extension methods.
     2868                       
     2869                        @private
     2870                        @method exec
     2871                        @return {Mixed} Whatever runtime extension method returns
     2872                        */
     2873                        exec: function() {
     2874                                if (runtime) {
     2875                                        return runtime.exec.apply(this, arguments);
     2876                                }
     2877                                return null;
     2878                        }
     2879
     2880                });
     2881        };
     2882
     2883
     2884});
     2885
     2886// Included from: src/javascript/file/FileInput.js
     2887
     2888/**
     2889 * FileInput.js
     2890 *
     2891 * Copyright 2013, Moxiecode Systems AB
     2892 * Released under GPL License.
     2893 *
     2894 * License: http://www.plupload.com/license
     2895 * Contributing: http://www.plupload.com/contributing
     2896 */
     2897
     2898define('moxie/file/FileInput', [
     2899        'moxie/core/utils/Basic',
     2900        'moxie/core/utils/Env',
     2901        'moxie/core/utils/Mime',
     2902        'moxie/core/utils/Dom',
     2903        'moxie/core/Exceptions',
     2904        'moxie/core/EventTarget',
     2905        'moxie/core/I18n',
     2906        'moxie/runtime/Runtime',
     2907        'moxie/runtime/RuntimeClient'
     2908], function(Basic, Env, Mime, Dom, x, EventTarget, I18n, Runtime, RuntimeClient) {
     2909        /**
     2910        Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click,
     2911        converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory
     2912        with _FileReader_ or uploaded to a server through _XMLHttpRequest_.
     2913
     2914        @class FileInput
     2915        @constructor
     2916        @extends EventTarget
     2917        @uses RuntimeClient
     2918        @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_.
     2919                @param {String|DOMElement} options.browse_button DOM Element to turn into file picker.
     2920                @param {Array} [options.accept] Array of mime types to accept. By default accepts all.
     2921                @param {String} [options.file='file'] Name of the file field (not the filename).
     2922                @param {Boolean} [options.multiple=false] Enable selection of multiple files.
     2923                @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time).
     2924                @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode
     2925                for _browse\_button_.
     2926                @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support.
     2927
     2928        @example
     2929                <div id="container">
     2930                        <a id="file-picker" href="javascript:;">Browse...</a>
     2931                </div>
     2932
     2933                <script>
     2934                        var fileInput = new mOxie.FileInput({
     2935                                browse_button: 'file-picker', // or document.getElementById('file-picker')
     2936                                container: 'container',
     2937                                accept: [
     2938                                        {title: "Image files", extensions: "jpg,gif,png"} // accept only images
     2939                                ],
     2940                                multiple: true // allow multiple file selection
     2941                        });
     2942
     2943                        fileInput.onchange = function(e) {
     2944                                // do something to files array
     2945                                console.info(e.target.files); // or this.files or fileInput.files
     2946                        };
     2947
     2948                        fileInput.init(); // initialize
     2949                </script>
     2950        */
     2951        var dispatches = [
     2952                /**
     2953                Dispatched when runtime is connected and file-picker is ready to be used.
     2954
     2955                @event ready
     2956                @param {Object} event
     2957                */
     2958                'ready',
     2959
     2960                /**
     2961                Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked.
     2962                Check [corresponding documentation entry](#method_refresh) for more info.
     2963
     2964                @event refresh
     2965                @param {Object} event
     2966                */
     2967
     2968                /**
     2969                Dispatched when selection of files in the dialog is complete.
     2970
     2971                @event change
     2972                @param {Object} event
     2973                */
     2974                'change',
     2975
     2976                'cancel', // TODO: might be useful
     2977
     2978                /**
     2979                Dispatched when mouse cursor enters file-picker area. Can be used to style element
     2980                accordingly.
     2981
     2982                @event mouseenter
     2983                @param {Object} event
     2984                */
     2985                'mouseenter',
     2986
     2987                /**
     2988                Dispatched when mouse cursor leaves file-picker area. Can be used to style element
     2989                accordingly.
     2990
     2991                @event mouseleave
     2992                @param {Object} event
     2993                */
     2994                'mouseleave',
     2995
     2996                /**
     2997                Dispatched when functional mouse button is pressed on top of file-picker area.
     2998
     2999                @event mousedown
     3000                @param {Object} event
     3001                */
     3002                'mousedown',
     3003
     3004                /**
     3005                Dispatched when functional mouse button is released on top of file-picker area.
     3006
     3007                @event mouseup
     3008                @param {Object} event
     3009                */
     3010                'mouseup'
     3011        ];
     3012
     3013        function FileInput(options) {
     3014                if (MXI_DEBUG) {
     3015                        Env.log("Instantiating FileInput..."); 
     3016                }
     3017
     3018                var self = this,
     3019                        container, browseButton, defaults;
     3020
     3021                // if flat argument passed it should be browse_button id
     3022                if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) {
     3023                        options = { browse_button : options };
     3024                }
     3025
     3026                // this will help us to find proper default container
     3027                browseButton = Dom.get(options.browse_button);
     3028                if (!browseButton) {
     3029                        // browse button is required
     3030                        throw new x.DOMException(x.DOMException.NOT_FOUND_ERR);
     3031                }
     3032
     3033                // figure out the options
     3034                defaults = {
     3035                        accept: [{
     3036                                title: I18n.translate('All Files'),
     3037                                extensions: '*'
     3038                        }],
     3039                        name: 'file',
     3040                        multiple: false,
     3041                        required_caps: false,
     3042                        container: browseButton.parentNode || document.body
     3043                };
     3044               
     3045                options = Basic.extend({}, defaults, options);
     3046
     3047                // convert to object representation
     3048                if (typeof(options.required_caps) === 'string') {
     3049                        options.required_caps = Runtime.parseCaps(options.required_caps);
     3050                }
     3051                                       
     3052                // normalize accept option (could be list of mime types or array of title/extensions pairs)
     3053                if (typeof(options.accept) === 'string') {
     3054                        options.accept = Mime.mimes2extList(options.accept);
     3055                }
     3056
     3057                container = Dom.get(options.container);
     3058                // make sure we have container
     3059                if (!container) {
     3060                        container = document.body;
     3061                }
     3062
     3063                // make container relative, if it's not
     3064                if (Dom.getStyle(container, 'position') === 'static') {
     3065                        container.style.position = 'relative';
     3066                }
     3067
     3068                container = browseButton = null; // IE
     3069                                               
     3070                RuntimeClient.call(self);
     3071               
     3072                Basic.extend(self, {
     3073                        /**
     3074                        Unique id of the component
     3075
     3076                        @property uid
     3077                        @protected
     3078                        @readOnly
     3079                        @type {String}
     3080                        @default UID
     3081                        */
     3082                        uid: Basic.guid('uid_'),
     3083                       
     3084                        /**
     3085                        Unique id of the connected runtime, if any.
     3086
     3087                        @property ruid
     3088                        @protected
     3089                        @type {String}
     3090                        */
     3091                        ruid: null,
     3092
     3093                        /**
     3094                        Unique id of the runtime container. Useful to get hold of it for various manipulations.
     3095
     3096                        @property shimid
     3097                        @protected
     3098                        @type {String}
     3099                        */
     3100                        shimid: null,
     3101                       
     3102                        /**
     3103                        Array of selected mOxie.File objects
     3104
     3105                        @property files
     3106                        @type {Array}
     3107                        @default null
     3108                        */
     3109                        files: null,
     3110
     3111                        /**
     3112                        Initializes the file-picker, connects it to runtime and dispatches event ready when done.
     3113
     3114                        @method init
     3115                        */
     3116                        init: function() {
     3117                                self.bind('RuntimeInit', function(e, runtime) {
     3118                                        self.ruid = runtime.uid;
     3119                                        self.shimid = runtime.shimid;
     3120
     3121                                        self.bind("Ready", function() {
     3122                                                self.trigger("Refresh");
     3123                                        }, 999);
     3124
     3125                                        // re-position and resize shim container
     3126                                        self.bind('Refresh', function() {
     3127                                                var pos, size, browseButton, shimContainer;
     3128                                               
     3129                                                browseButton = Dom.get(options.browse_button);
     3130                                                shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist
     3131
     3132                                                if (browseButton) {
     3133                                                        pos = Dom.getPos(browseButton, Dom.get(options.container));
     3134                                                        size = Dom.getSize(browseButton);
     3135
     3136                                                        if (shimContainer) {
     3137                                                                Basic.extend(shimContainer.style, {
     3138                                                                        top     : pos.y + 'px',
     3139                                                                        left    : pos.x + 'px',
     3140                                                                        width   : size.w + 'px',
     3141                                                                        height  : size.h + 'px'
     3142                                                                });
     3143                                                        }
     3144                                                }
     3145                                                shimContainer = browseButton = null;
     3146                                        });
     3147                                       
     3148                                        runtime.exec.call(self, 'FileInput', 'init', options);
     3149                                });
     3150
     3151                                // runtime needs: options.required_features, options.runtime_order and options.container
     3152                                self.connectRuntime(Basic.extend({}, options, {
     3153                                        required_caps: {
     3154                                                select_file: true
     3155                                        }
     3156                                }));
     3157                        },
     3158
     3159                        /**
     3160                        Disables file-picker element, so that it doesn't react to mouse clicks.
     3161
     3162                        @method disable
     3163                        @param {Boolean} [state=true] Disable component if - true, enable if - false
     3164                        */
     3165                        disable: function(state) {
     3166                                var runtime = this.getRuntime();
     3167                                if (runtime) {
     3168                                        runtime.exec.call(this, 'FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state);
     3169                                }
     3170                        },
     3171
     3172
     3173                        /**
     3174                        Reposition and resize dialog trigger to match the position and size of browse_button element.
     3175
     3176                        @method refresh
     3177                        */
     3178                        refresh: function() {
     3179                                self.trigger("Refresh");
     3180                        },
     3181
     3182
     3183                        /**
     3184                        Destroy component.
     3185
     3186                        @method destroy
     3187                        */
     3188                        destroy: function() {
     3189                                var runtime = this.getRuntime();
     3190                                if (runtime) {
     3191                                        runtime.exec.call(this, 'FileInput', 'destroy');
     3192                                        this.disconnectRuntime();
     3193                                }
     3194
     3195                                if (Basic.typeOf(this.files) === 'array') {
     3196                                        // no sense in leaving associated files behind
     3197                                        Basic.each(this.files, function(file) {
     3198                                                file.destroy();
     3199                                        });
     3200                                }
     3201                                this.files = null;
     3202
     3203                                this.unbindAll();
     3204                        }
     3205                });
     3206
     3207                this.handleEventProps(dispatches);
     3208        }
     3209
     3210        FileInput.prototype = EventTarget.instance;
     3211
     3212        return FileInput;
     3213});
     3214
     3215// Included from: src/javascript/core/utils/Encode.js
     3216
     3217/**
     3218 * Encode.js
     3219 *
     3220 * Copyright 2013, Moxiecode Systems AB
     3221 * Released under GPL License.
     3222 *
     3223 * License: http://www.plupload.com/license
     3224 * Contributing: http://www.plupload.com/contributing
     3225 */
     3226
     3227define('moxie/core/utils/Encode', [], function() {
     3228
     3229        /**
     3230        Encode string with UTF-8
     3231
     3232        @method utf8_encode
     3233        @for Utils
     3234        @static
     3235        @param {String} str String to encode
     3236        @return {String} UTF-8 encoded string
     3237        */
     3238        var utf8_encode = function(str) {
     3239                return unescape(encodeURIComponent(str));
     3240        };
     3241       
     3242        /**
     3243        Decode UTF-8 encoded string
     3244
     3245        @method utf8_decode
     3246        @static
     3247        @param {String} str String to decode
     3248        @return {String} Decoded string
     3249        */
     3250        var utf8_decode = function(str_data) {
     3251                return decodeURIComponent(escape(str_data));
     3252        };
     3253       
     3254        /**
     3255        Decode Base64 encoded string (uses browser's default method if available),
     3256        from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js
     3257
     3258        @method atob
     3259        @static
     3260        @param {String} data String to decode
     3261        @return {String} Decoded string
     3262        */
     3263        var atob = function(data, utf8) {
     3264                if (typeof(window.atob) === 'function') {
     3265                        return utf8 ? utf8_decode(window.atob(data)) : window.atob(data);
     3266                }
     3267
     3268                // http://kevin.vanzonneveld.net
     3269                // +   original by: Tyler Akins (http://rumkin.com)
     3270                // +   improved by: Thunder.m
     3271                // +      input by: Aman Gupta
     3272                // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
     3273                // +   bugfixed by: Onno Marsman
     3274                // +   bugfixed by: Pellentesque Malesuada
     3275                // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
     3276                // +      input by: Brett Zamir (http://brett-zamir.me)
     3277                // +   bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
     3278                // *     example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA==');
     3279                // *     returns 1: 'Kevin van Zonneveld'
     3280                // mozilla has this native
     3281                // - but breaks in 2.0.0.12!
     3282                //if (typeof this.window.atob == 'function') {
     3283                //    return atob(data);
     3284                //}
     3285                var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
     3286                var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
     3287                        ac = 0,
     3288                        dec = "",
     3289                        tmp_arr = [];
     3290
     3291                if (!data) {
     3292                        return data;
     3293                }
     3294
     3295                data += '';
     3296
     3297                do { // unpack four hexets into three octets using index points in b64
     3298                        h1 = b64.indexOf(data.charAt(i++));
     3299                        h2 = b64.indexOf(data.charAt(i++));
     3300                        h3 = b64.indexOf(data.charAt(i++));
     3301                        h4 = b64.indexOf(data.charAt(i++));
     3302
     3303                        bits = h1 << 18 | h2 << 12 | h3 << 6 | h4;
     3304
     3305                        o1 = bits >> 16 & 0xff;
     3306                        o2 = bits >> 8 & 0xff;
     3307                        o3 = bits & 0xff;
     3308
     3309                        if (h3 == 64) {
     3310                                tmp_arr[ac++] = String.fromCharCode(o1);
     3311                        } else if (h4 == 64) {
     3312                                tmp_arr[ac++] = String.fromCharCode(o1, o2);
     3313                        } else {
     3314                                tmp_arr[ac++] = String.fromCharCode(o1, o2, o3);
     3315                        }
     3316                } while (i < data.length);
     3317
     3318                dec = tmp_arr.join('');
     3319
     3320                return utf8 ? utf8_decode(dec) : dec;
     3321        };
     3322       
     3323        /**
     3324        Base64 encode string (uses browser's default method if available),
     3325        from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js
     3326
     3327        @method btoa
     3328        @static
     3329        @param {String} data String to encode
     3330        @return {String} Base64 encoded string
     3331        */
     3332        var btoa = function(data, utf8) {
     3333                if (utf8) {
     3334                        data = utf8_encode(data);
     3335                }
     3336
     3337                if (typeof(window.btoa) === 'function') {
     3338                        return window.btoa(data);
     3339                }
     3340
     3341                // http://kevin.vanzonneveld.net
     3342                // +   original by: Tyler Akins (http://rumkin.com)
     3343                // +   improved by: Bayron Guevara
     3344                // +   improved by: Thunder.m
     3345                // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
     3346                // +   bugfixed by: Pellentesque Malesuada
     3347                // +   improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net)
     3348                // +   improved by: Rafał Kukawski (http://kukawski.pl)
     3349                // *     example 1: base64_encode('Kevin van Zonneveld');
     3350                // *     returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA=='
     3351                // mozilla has this native
     3352                // - but breaks in 2.0.0.12!
     3353                var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
     3354                var o1, o2, o3, h1, h2, h3, h4, bits, i = 0,
     3355                        ac = 0,
     3356                        enc = "",
     3357                        tmp_arr = [];
     3358
     3359                if (!data) {
     3360                        return data;
     3361                }
     3362
     3363                do { // pack three octets into four hexets
     3364                        o1 = data.charCodeAt(i++);
     3365                        o2 = data.charCodeAt(i++);
     3366                        o3 = data.charCodeAt(i++);
     3367
     3368                        bits = o1 << 16 | o2 << 8 | o3;
     3369
     3370                        h1 = bits >> 18 & 0x3f;
     3371                        h2 = bits >> 12 & 0x3f;
     3372                        h3 = bits >> 6 & 0x3f;
     3373                        h4 = bits & 0x3f;
     3374
     3375                        // use hexets to index into b64, and append result to encoded string
     3376                        tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
     3377                } while (i < data.length);
     3378
     3379                enc = tmp_arr.join('');
     3380
     3381                var r = data.length % 3;
     3382
     3383                return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3);
     3384        };
     3385
     3386
     3387        return {
     3388                utf8_encode: utf8_encode,
     3389                utf8_decode: utf8_decode,
     3390                atob: atob,
     3391                btoa: btoa
     3392        };
     3393});
     3394
     3395// Included from: src/javascript/file/Blob.js
     3396
     3397/**
     3398 * Blob.js
     3399 *
     3400 * Copyright 2013, Moxiecode Systems AB
     3401 * Released under GPL License.
     3402 *
     3403 * License: http://www.plupload.com/license
     3404 * Contributing: http://www.plupload.com/contributing
     3405 */
     3406
     3407define('moxie/file/Blob', [
     3408        'moxie/core/utils/Basic',
     3409        'moxie/core/utils/Encode',
     3410        'moxie/runtime/RuntimeClient'
     3411], function(Basic, Encode, RuntimeClient) {
     3412       
     3413        var blobpool = {};
     3414
     3415        /**
     3416        @class Blob
     3417        @constructor
     3418        @param {String} ruid Unique id of the runtime, to which this blob belongs to
     3419        @param {Object} blob Object "Native" blob object, as it is represented in the runtime
     3420        */
     3421        function Blob(ruid, blob) {
     3422
     3423                function _sliceDetached(start, end, type) {
     3424                        var blob, data = blobpool[this.uid];
     3425
     3426                        if (Basic.typeOf(data) !== 'string' || !data.length) {
     3427                                return null; // or throw exception
     3428                        }
     3429
     3430                        blob = new Blob(null, {
     3431                                type: type,
     3432                                size: end - start
     3433                        });
     3434                        blob.detach(data.substr(start, blob.size));
     3435
     3436                        return blob;
     3437                }
     3438
     3439                RuntimeClient.call(this);
     3440
     3441                if (ruid) {     
     3442                        this.connectRuntime(ruid);
     3443                }
     3444
     3445                if (!blob) {
     3446                        blob = {};
     3447                } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string
     3448                        blob = { data: blob };
     3449                }
     3450
     3451                Basic.extend(this, {
     3452                       
     3453                        /**
     3454                        Unique id of the component
     3455
     3456                        @property uid
     3457                        @type {String}
     3458                        */
     3459                        uid: blob.uid || Basic.guid('uid_'),
     3460                       
     3461                        /**
     3462                        Unique id of the connected runtime, if falsy, then runtime will have to be initialized
     3463                        before this Blob can be used, modified or sent
     3464
     3465                        @property ruid
     3466                        @type {String}
     3467                        */
     3468                        ruid: ruid,
     3469       
     3470                        /**
     3471                        Size of blob
     3472
     3473                        @property size
     3474                        @type {Number}
     3475                        @default 0
     3476                        */
     3477                        size: blob.size || 0,
     3478                       
     3479                        /**
     3480                        Mime type of blob
     3481
     3482                        @property type
     3483                        @type {String}
     3484                        @default ''
     3485                        */
     3486                        type: blob.type || '',
     3487                       
     3488                        /**
     3489                        @method slice
     3490                        @param {Number} [start=0]
     3491                        */
     3492                        slice: function(start, end, type) {             
     3493                                if (this.isDetached()) {
     3494                                        return _sliceDetached.apply(this, arguments);
     3495                                }
     3496                                return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type);
     3497                        },
     3498
     3499                        /**
     3500                        Returns "native" blob object (as it is represented in connected runtime) or null if not found
     3501
     3502                        @method getSource
     3503                        @return {Blob} Returns "native" blob object or null if not found
     3504                        */
     3505                        getSource: function() {
     3506                                if (!blobpool[this.uid]) {
     3507                                        return null;   
     3508                                }
     3509                                return blobpool[this.uid];
     3510                        },
     3511
     3512                        /**
     3513                        Detaches blob from any runtime that it depends on and initialize with standalone value
     3514
     3515                        @method detach
     3516                        @protected
     3517                        @param {DOMString} [data=''] Standalone value
     3518                        */
     3519                        detach: function(data) {
     3520                                if (this.ruid) {
     3521                                        this.getRuntime().exec.call(this, 'Blob', 'destroy');
     3522                                        this.disconnectRuntime();
     3523                                        this.ruid = null;
     3524                                }
     3525
     3526                                data = data || '';
     3527
     3528                                // if dataUrl, convert to binary string
     3529                                if (data.substr(0, 5) == 'data:') {
     3530                                        var base64Offset = data.indexOf(';base64,');
     3531                                        this.type = data.substring(5, base64Offset);
     3532                                        data = Encode.atob(data.substring(base64Offset + 8));
     3533                                }
     3534
     3535                                this.size = data.length;
     3536
     3537                                blobpool[this.uid] = data;
     3538                        },
     3539
     3540                        /**
     3541                        Checks if blob is standalone (detached of any runtime)
     3542                       
     3543                        @method isDetached
     3544                        @protected
     3545                        @return {Boolean}
     3546                        */
     3547                        isDetached: function() {
     3548                                return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string';
     3549                        },
     3550                       
     3551                        /**
     3552                        Destroy Blob and free any resources it was using
     3553
     3554                        @method destroy
     3555                        */
     3556                        destroy: function() {
     3557                                this.detach();
     3558                                delete blobpool[this.uid];
     3559                        }
     3560                });
     3561
     3562               
     3563                if (blob.data) {
     3564                        this.detach(blob.data); // auto-detach if payload has been passed
     3565                } else {
     3566                        blobpool[this.uid] = blob;     
     3567                }
     3568        }
     3569       
     3570        return Blob;
     3571});
     3572
     3573// Included from: src/javascript/file/File.js
     3574
     3575/**
     3576 * File.js
     3577 *
     3578 * Copyright 2013, Moxiecode Systems AB
     3579 * Released under GPL License.
     3580 *
     3581 * License: http://www.plupload.com/license
     3582 * Contributing: http://www.plupload.com/contributing
     3583 */
     3584
     3585define('moxie/file/File', [
     3586        'moxie/core/utils/Basic',
     3587        'moxie/core/utils/Mime',
     3588        'moxie/file/Blob'
     3589], function(Basic, Mime, Blob) {
     3590        /**
     3591        @class File
     3592        @extends Blob
     3593        @constructor
     3594        @param {String} ruid Unique id of the runtime, to which this blob belongs to
     3595        @param {Object} file Object "Native" file object, as it is represented in the runtime
     3596        */
     3597        function File(ruid, file) {
     3598                if (!file) { // avoid extra errors in case we overlooked something
     3599                        file = {};
     3600                }
     3601
     3602                Blob.apply(this, arguments);
     3603
     3604                if (!this.type) {
     3605                        this.type = Mime.getFileMime(file.name);
     3606                }
     3607
     3608                // sanitize file name or generate new one
     3609                var name;
     3610                if (file.name) {
     3611                        name = file.name.replace(/\\/g, '/');
     3612                        name = name.substr(name.lastIndexOf('/') + 1);
     3613                } else if (this.type) {
     3614                        var prefix = this.type.split('/')[0];
     3615                        name = Basic.guid((prefix !== '' ? prefix : 'file') + '_');
     3616                       
     3617                        if (Mime.extensions[this.type]) {
     3618                                name += '.' + Mime.extensions[this.type][0]; // append proper extension if possible
     3619                        }
     3620                }
     3621               
     3622               
     3623                Basic.extend(this, {
     3624                        /**
     3625                        File name
     3626
     3627                        @property name
     3628                        @type {String}
     3629                        @default UID
     3630                        */
     3631                        name: name || Basic.guid('file_'),
     3632
     3633                        /**
     3634                        Relative path to the file inside a directory
     3635
     3636                        @property relativePath
     3637                        @type {String}
     3638                        @default ''
     3639                        */
     3640                        relativePath: '',
     3641                       
     3642                        /**
     3643                        Date of last modification
     3644
     3645                        @property lastModifiedDate
     3646                        @type {String}
     3647                        @default now
     3648                        */
     3649                        lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET)
     3650                });
     3651        }
     3652
     3653        File.prototype = Blob.prototype;
     3654
     3655        return File;
     3656});
     3657
     3658// Included from: src/javascript/file/FileDrop.js
     3659
     3660/**
     3661 * FileDrop.js
     3662 *
     3663 * Copyright 2013, Moxiecode Systems AB
     3664 * Released under GPL License.
     3665 *
     3666 * License: http://www.plupload.com/license
     3667 * Contributing: http://www.plupload.com/contributing
     3668 */
     3669
     3670define('moxie/file/FileDrop', [
     3671        'moxie/core/I18n',
     3672        'moxie/core/utils/Dom',
     3673        'moxie/core/Exceptions',
     3674        'moxie/core/utils/Basic',
     3675        'moxie/core/utils/Env',
     3676        'moxie/file/File',
     3677        'moxie/runtime/RuntimeClient',
     3678        'moxie/core/EventTarget',
     3679        'moxie/core/utils/Mime'
     3680], function(I18n, Dom, x, Basic, Env, File, RuntimeClient, EventTarget, Mime) {
     3681        /**
     3682        Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used
     3683        in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through
     3684        _XMLHttpRequest_.
     3685
     3686        @example
     3687                <div id="drop_zone">
     3688                        Drop files here
     3689                </div>
     3690                <br />
     3691                <div id="filelist"></div>
     3692
     3693                <script type="text/javascript">
     3694                        var fileDrop = new mOxie.FileDrop('drop_zone'), fileList = mOxie.get('filelist');
     3695
     3696                        fileDrop.ondrop = function() {
     3697                                mOxie.each(this.files, function(file) {
     3698                                        fileList.innerHTML += '<div>' + file.name + '</div>';
     3699                                });
     3700                        };
     3701
     3702                        fileDrop.init();
     3703                </script>
     3704
     3705        @class FileDrop
     3706        @constructor
     3707        @extends EventTarget
     3708        @uses RuntimeClient
     3709        @param {Object|String} options If options has typeof string, argument is considered as options.drop_zone
     3710                @param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone
     3711                @param {Array} [options.accept] Array of mime types to accept. By default accepts all
     3712                @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support
     3713        */
     3714        var dispatches = [
     3715                /**
     3716                Dispatched when runtime is connected and drop zone is ready to accept files.
     3717
     3718                @event ready
     3719                @param {Object} event
     3720                */
     3721                'ready',
     3722
     3723                /**
     3724                Dispatched when dragging cursor enters the drop zone.
     3725
     3726                @event dragenter
     3727                @param {Object} event
     3728                */
     3729                'dragenter',
     3730
     3731                /**
     3732                Dispatched when dragging cursor leaves the drop zone.
     3733
     3734                @event dragleave
     3735                @param {Object} event
     3736                */
     3737                'dragleave',
     3738
     3739                /**
     3740                Dispatched when file is dropped onto the drop zone.
     3741
     3742                @event drop
     3743                @param {Object} event
     3744                */
     3745                'drop',
     3746
     3747                /**
     3748                Dispatched if error occurs.
     3749
     3750                @event error
     3751                @param {Object} event
     3752                */
     3753                'error'
     3754        ];
     3755
     3756        function FileDrop(options) {
     3757                if (MXI_DEBUG) {
     3758                        Env.log("Instantiating FileDrop...");   
     3759                }
     3760
     3761                var self = this, defaults;
     3762
     3763                // if flat argument passed it should be drop_zone id
     3764                if (typeof(options) === 'string') {
     3765                        options = { drop_zone : options };
     3766                }
     3767
     3768                // figure out the options
     3769                defaults = {
     3770                        accept: [{
     3771                                title: I18n.translate('All Files'),
     3772                                extensions: '*'
     3773                        }],
     3774                        required_caps: {
     3775                                drag_and_drop: true
     3776                        }
     3777                };
     3778               
     3779                options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults;
     3780
     3781                // this will help us to find proper default container
     3782                options.container = Dom.get(options.drop_zone) || document.body;
     3783
     3784                // make container relative, if it is not
     3785                if (Dom.getStyle(options.container, 'position') === 'static') {
     3786                        options.container.style.position = 'relative';
     3787                }
     3788                                       
     3789                // normalize accept option (could be list of mime types or array of title/extensions pairs)
     3790                if (typeof(options.accept) === 'string') {
     3791                        options.accept = Mime.mimes2extList(options.accept);
     3792                }
     3793
     3794                RuntimeClient.call(self);
     3795
     3796                Basic.extend(self, {
     3797                        uid: Basic.guid('uid_'),
     3798
     3799                        ruid: null,
     3800
     3801                        files: null,
     3802
     3803                        init: function() {             
     3804                                self.bind('RuntimeInit', function(e, runtime) {
     3805                                        self.ruid = runtime.uid;
     3806                                        runtime.exec.call(self, 'FileDrop', 'init', options);
     3807                                        self.dispatchEvent('ready');
     3808                                });
     3809                                                       
     3810                                // runtime needs: options.required_features, options.runtime_order and options.container
     3811                                self.connectRuntime(options); // throws RuntimeError
     3812                        },
     3813
     3814                        destroy: function() {
     3815                                var runtime = this.getRuntime();
     3816                                if (runtime) {
     3817                                        runtime.exec.call(this, 'FileDrop', 'destroy');
     3818                                        this.disconnectRuntime();
     3819                                }
     3820                                this.files = null;
     3821                               
     3822                                this.unbindAll();
     3823                        }
     3824                });
     3825
     3826                this.handleEventProps(dispatches);
     3827        }
     3828
     3829        FileDrop.prototype = EventTarget.instance;
     3830
     3831        return FileDrop;
     3832});
     3833
     3834// Included from: src/javascript/file/FileReader.js
     3835
     3836/**
     3837 * FileReader.js
     3838 *
     3839 * Copyright 2013, Moxiecode Systems AB
     3840 * Released under GPL License.
     3841 *
     3842 * License: http://www.plupload.com/license
     3843 * Contributing: http://www.plupload.com/contributing
     3844 */
     3845
     3846define('moxie/file/FileReader', [
     3847        'moxie/core/utils/Basic',
     3848        'moxie/core/utils/Encode',
     3849        'moxie/core/Exceptions',
     3850        'moxie/core/EventTarget',
     3851        'moxie/file/Blob',
     3852        'moxie/runtime/RuntimeClient'
     3853], function(Basic, Encode, x, EventTarget, Blob, RuntimeClient) {
     3854        /**
     3855        Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader)
     3856        interface. Where possible uses native FileReader, where - not falls back to shims.
     3857
     3858        @class FileReader
     3859        @constructor FileReader
     3860        @extends EventTarget
     3861        @uses RuntimeClient
     3862        */
     3863        var dispatches = [
     3864
     3865                /**
     3866                Dispatched when the read starts.
     3867
     3868                @event loadstart
     3869                @param {Object} event
     3870                */
     3871                'loadstart',
     3872
     3873                /**
     3874                Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total).
     3875
     3876                @event progress
     3877                @param {Object} event
     3878                */
     3879                'progress',
     3880
     3881                /**
     3882                Dispatched when the read has successfully completed.
     3883
     3884                @event load
     3885                @param {Object} event
     3886                */
     3887                'load',
     3888
     3889                /**
     3890                Dispatched when the read has been aborted. For instance, by invoking the abort() method.
     3891
     3892                @event abort
     3893                @param {Object} event
     3894                */
     3895                'abort',
     3896
     3897                /**
     3898                Dispatched when the read has failed.
     3899
     3900                @event error
     3901                @param {Object} event
     3902                */
     3903                'error',
     3904
     3905                /**
     3906                Dispatched when the request has completed (either in success or failure).
     3907
     3908                @event loadend
     3909                @param {Object} event
     3910                */
     3911                'loadend'
     3912        ];
     3913       
     3914        function FileReader() {
     3915
     3916                RuntimeClient.call(this);
     3917
     3918                Basic.extend(this, {
     3919                        /**
     3920                        UID of the component instance.
     3921
     3922                        @property uid
     3923                        @type {String}
     3924                        */
     3925                        uid: Basic.guid('uid_'),
     3926
     3927                        /**
     3928                        Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING
     3929                        and FileReader.DONE.
     3930
     3931                        @property readyState
     3932                        @type {Number}
     3933                        @default FileReader.EMPTY
     3934                        */
     3935                        readyState: FileReader.EMPTY,
     3936                       
     3937                        /**
     3938                        Result of the successful read operation.
     3939
     3940                        @property result
     3941                        @type {String}
     3942                        */
     3943                        result: null,
     3944                       
     3945                        /**
     3946                        Stores the error of failed asynchronous read operation.
     3947
     3948                        @property error
     3949                        @type {DOMError}
     3950                        */
     3951                        error: null,
     3952                       
     3953                        /**
     3954                        Initiates reading of File/Blob object contents to binary string.
     3955
     3956                        @method readAsBinaryString
     3957                        @param {Blob|File} blob Object to preload
     3958                        */
     3959                        readAsBinaryString: function(blob) {
     3960                                _read.call(this, 'readAsBinaryString', blob);
     3961                        },
     3962                       
     3963                        /**
     3964                        Initiates reading of File/Blob object contents to dataURL string.
     3965
     3966                        @method readAsDataURL
     3967                        @param {Blob|File} blob Object to preload
     3968                        */
     3969                        readAsDataURL: function(blob) {
     3970                                _read.call(this, 'readAsDataURL', blob);
     3971                        },
     3972                       
     3973                        /**
     3974                        Initiates reading of File/Blob object contents to string.
     3975
     3976                        @method readAsText
     3977                        @param {Blob|File} blob Object to preload
     3978                        */
     3979                        readAsText: function(blob) {
     3980                                _read.call(this, 'readAsText', blob);
     3981                        },
     3982                       
     3983                        /**
     3984                        Aborts preloading process.
     3985
     3986                        @method abort
     3987                        */
     3988                        abort: function() {
     3989                                this.result = null;
     3990                               
     3991                                if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) {
     3992                                        return;
     3993                                } else if (this.readyState === FileReader.LOADING) {
     3994                                        this.readyState = FileReader.DONE;
     3995                                }
     3996
     3997                                this.exec('FileReader', 'abort');
     3998                               
     3999                                this.trigger('abort');
     4000                                this.trigger('loadend');
     4001                        },
     4002
     4003                        /**
     4004                        Destroy component and release resources.
     4005
     4006                        @method destroy
     4007                        */
     4008                        destroy: function() {
     4009                                this.abort();
     4010                                this.exec('FileReader', 'destroy');
     4011                                this.disconnectRuntime();
     4012                                this.unbindAll();
     4013                        }
     4014                });
     4015
     4016                // uid must already be assigned
     4017                this.handleEventProps(dispatches);
     4018
     4019                this.bind('Error', function(e, err) {
     4020                        this.readyState = FileReader.DONE;
     4021                        this.error = err;
     4022                }, 999);
     4023               
     4024                this.bind('Load', function(e) {
     4025                        this.readyState = FileReader.DONE;
     4026                }, 999);
     4027
     4028               
     4029                function _read(op, blob) {
     4030                        var self = this;                       
     4031
     4032                        this.trigger('loadstart');
     4033
     4034                        if (this.readyState === FileReader.LOADING) {
     4035                                this.trigger('error', new x.DOMException(x.DOMException.INVALID_STATE_ERR));
     4036                                this.trigger('loadend');
     4037                                return;
     4038                        }
     4039
     4040                        // if source is not o.Blob/o.File
     4041                        if (!(blob instanceof Blob)) {
     4042                                this.trigger('error', new x.DOMException(x.DOMException.NOT_FOUND_ERR));
     4043                                this.trigger('loadend');
     4044                                return;
     4045                        }
     4046
     4047                        this.result = null;
     4048                        this.readyState = FileReader.LOADING;
     4049                       
     4050                        if (blob.isDetached()) {
     4051                                var src = blob.getSource();
     4052                                switch (op) {
     4053                                        case 'readAsText':
     4054                                        case 'readAsBinaryString':
     4055                                                this.result = src;
     4056                                                break;
     4057                                        case 'readAsDataURL':
     4058                                                this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src);
     4059                                                break;
     4060                                }
     4061                                this.readyState = FileReader.DONE;
     4062                                this.trigger('load');
     4063                                this.trigger('loadend');
     4064                        } else {
     4065                                this.connectRuntime(blob.ruid);
     4066                                this.exec('FileReader', 'read', op, blob);
     4067                        }
     4068                }
     4069        }
     4070       
     4071        /**
     4072        Initial FileReader state
     4073
     4074        @property EMPTY
     4075        @type {Number}
     4076        @final
     4077        @static
     4078        @default 0
     4079        */
     4080        FileReader.EMPTY = 0;
     4081
     4082        /**
     4083        FileReader switches to this state when it is preloading the source
     4084
     4085        @property LOADING
     4086        @type {Number}
     4087        @final
     4088        @static
     4089        @default 1
     4090        */
     4091        FileReader.LOADING = 1;
     4092
     4093        /**
     4094        Preloading is complete, this is a final state
     4095
     4096        @property DONE
     4097        @type {Number}
     4098        @final
     4099        @static
     4100        @default 2
     4101        */
     4102        FileReader.DONE = 2;
     4103
     4104        FileReader.prototype = EventTarget.instance;
     4105
     4106        return FileReader;
     4107});
     4108
     4109// Included from: src/javascript/core/utils/Url.js
     4110
     4111/**
     4112 * Url.js
     4113 *
     4114 * Copyright 2013, Moxiecode Systems AB
     4115 * Released under GPL License.
     4116 *
     4117 * License: http://www.plupload.com/license
     4118 * Contributing: http://www.plupload.com/contributing
     4119 */
     4120
     4121define('moxie/core/utils/Url', [], function() {
     4122        /**
     4123        Parse url into separate components and fill in absent parts with parts from current url,
     4124        based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js
     4125
     4126        @method parseUrl
     4127        @for Utils
     4128        @static
     4129        @param {String} url Url to parse (defaults to empty string if undefined)
     4130        @return {Object} Hash containing extracted uri components
     4131        */
     4132        var parseUrl = function(url, currentUrl) {
     4133                var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment']
     4134                , i = key.length
     4135                , ports = {
     4136                        http: 80,
     4137                        https: 443
     4138                }
     4139                , uri = {}
     4140                , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@\/]*):?([^:@\/]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/
     4141                , m = regex.exec(url || '')
     4142                ;
     4143                                       
     4144                while (i--) {
     4145                        if (m[i]) {
     4146                                uri[key[i]] = m[i];
     4147                        }
     4148                }
     4149
     4150                // when url is relative, we set the origin and the path ourselves
     4151                if (!uri.scheme) {
     4152                        // come up with defaults
     4153                        if (!currentUrl || typeof(currentUrl) === 'string') {
     4154                                currentUrl = parseUrl(currentUrl || document.location.href);
     4155                        }
     4156
     4157                        uri.scheme = currentUrl.scheme;
     4158                        uri.host = currentUrl.host;
     4159                        uri.port = currentUrl.port;
     4160
     4161                        var path = '';
     4162                        // for urls without trailing slash we need to figure out the path
     4163                        if (/^[^\/]/.test(uri.path)) {
     4164                                path = currentUrl.path;
     4165                                // if path ends with a filename, strip it
     4166                                if (/\/[^\/]*\.[^\/]*$/.test(path)) {
     4167                                        path = path.replace(/\/[^\/]+$/, '/');
     4168                                } else {
     4169                                        // avoid double slash at the end (see #127)
     4170                                        path = path.replace(/\/?$/, '/');
     4171                                }
     4172                        }
     4173                        uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir
     4174                }
     4175
     4176                if (!uri.port) {
     4177                        uri.port = ports[uri.scheme] || 80;
     4178                }
     4179               
     4180                uri.port = parseInt(uri.port, 10);
     4181
     4182                if (!uri.path) {
     4183                        uri.path = "/";
     4184                }
     4185
     4186                delete uri.source;
     4187
     4188                return uri;
     4189        };
     4190
     4191        /**
     4192        Resolve url - among other things will turn relative url to absolute
     4193
     4194        @method resolveUrl
     4195        @static
     4196        @param {String|Object} url Either absolute or relative, or a result of parseUrl call
     4197        @return {String} Resolved, absolute url
     4198        */
     4199        var resolveUrl = function(url) {
     4200                var ports = { // we ignore default ports
     4201                        http: 80,
     4202                        https: 443
     4203                }
     4204                , urlp = typeof(url) === 'object' ? url : parseUrl(url);
     4205                ;
     4206
     4207                return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : '');
     4208        };
     4209
     4210        /**
     4211        Check if specified url has the same origin as the current document
     4212
     4213        @method hasSameOrigin
     4214        @param {String|Object} url
     4215        @return {Boolean}
     4216        */
     4217        var hasSameOrigin = function(url) {
     4218                function origin(url) {
     4219                        return [url.scheme, url.host, url.port].join('/');
     4220                }
     4221                       
     4222                if (typeof url === 'string') {
     4223                        url = parseUrl(url);
     4224                }       
     4225               
     4226                return origin(parseUrl()) === origin(url);
     4227        };
     4228
     4229        return {
     4230                parseUrl: parseUrl,
     4231                resolveUrl: resolveUrl,
     4232                hasSameOrigin: hasSameOrigin
     4233        };
     4234});
     4235
     4236// Included from: src/javascript/runtime/RuntimeTarget.js
     4237
     4238/**
     4239 * RuntimeTarget.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
     4248define('moxie/runtime/RuntimeTarget', [
     4249        'moxie/core/utils/Basic',
     4250        'moxie/runtime/RuntimeClient',
     4251        "moxie/core/EventTarget"
     4252], function(Basic, RuntimeClient, EventTarget) {
     4253        /**
     4254        Instance of this class can be used as a target for the events dispatched by shims,
     4255        when allowing them onto components is for either reason inappropriate
     4256
     4257        @class RuntimeTarget
     4258        @constructor
     4259        @protected
     4260        @extends EventTarget
     4261        */
     4262        function RuntimeTarget() {
     4263                this.uid = Basic.guid('uid_');
     4264               
     4265                RuntimeClient.call(this);
     4266
     4267                this.destroy = function() {
     4268                        this.disconnectRuntime();
     4269                        this.unbindAll();
     4270                };
     4271        }
     4272
     4273        RuntimeTarget.prototype = EventTarget.instance;
     4274
     4275        return RuntimeTarget;
     4276});
     4277
     4278// Included from: src/javascript/file/FileReaderSync.js
     4279
     4280/**
     4281 * FileReaderSync.js
     4282 *
     4283 * Copyright 2013, Moxiecode Systems AB
     4284 * Released under GPL License.
     4285 *
     4286 * License: http://www.plupload.com/license
     4287 * Contributing: http://www.plupload.com/contributing
     4288 */
     4289
     4290define('moxie/file/FileReaderSync', [
     4291        'moxie/core/utils/Basic',
     4292        'moxie/runtime/RuntimeClient',
     4293        'moxie/core/utils/Encode'
     4294], function(Basic, RuntimeClient, Encode) {
     4295        /**
     4296        Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here
     4297        it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be,
     4298        but probably < 1mb). Not meant to be used directly by user.
     4299
     4300        @class FileReaderSync
     4301        @private
     4302        @constructor
     4303        */
     4304        return function() {
     4305                RuntimeClient.call(this);
     4306
     4307                Basic.extend(this, {
     4308                        uid: Basic.guid('uid_'),
     4309
     4310                        readAsBinaryString: function(blob) {
     4311                                return _read.call(this, 'readAsBinaryString', blob);
     4312                        },
     4313                       
     4314                        readAsDataURL: function(blob) {
     4315                                return _read.call(this, 'readAsDataURL', blob);
     4316                        },
     4317                       
     4318                        /*readAsArrayBuffer: function(blob) {
     4319                                return _read.call(this, 'readAsArrayBuffer', blob);
     4320                        },*/
     4321                       
     4322                        readAsText: function(blob) {
     4323                                return _read.call(this, 'readAsText', blob);
     4324                        }
     4325                });
     4326
     4327                function _read(op, blob) {
     4328                        if (blob.isDetached()) {
     4329                                var src = blob.getSource();
     4330                                switch (op) {
     4331                                        case 'readAsBinaryString':
     4332                                                return src;
     4333                                        case 'readAsDataURL':
     4334                                                return 'data:' + blob.type + ';base64,' + Encode.btoa(src);
     4335                                        case 'readAsText':
     4336                                                var txt = '';
     4337                                                for (var i = 0, length = src.length; i < length; i++) {
     4338                                                        txt += String.fromCharCode(src[i]);
     4339                                                }
     4340                                                return txt;
     4341                                }
     4342                        } else {
     4343                                var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob);
     4344                                this.disconnectRuntime();
     4345                                return result;
     4346                        }
     4347                }
     4348        };
     4349});
     4350
     4351// Included from: src/javascript/xhr/FormData.js
     4352
     4353/**
     4354 * FormData.js
     4355 *
     4356 * Copyright 2013, Moxiecode Systems AB
     4357 * Released under GPL License.
     4358 *
     4359 * License: http://www.plupload.com/license
     4360 * Contributing: http://www.plupload.com/contributing
     4361 */
     4362
     4363define("moxie/xhr/FormData", [
     4364        "moxie/core/Exceptions",
     4365        "moxie/core/utils/Basic",
     4366        "moxie/file/Blob"
     4367], function(x, Basic, Blob) {
     4368        /**
     4369        FormData
     4370
     4371        @class FormData
     4372        @constructor
     4373        */
     4374        function FormData() {
     4375                var _blob, _fields = [];
     4376
     4377                Basic.extend(this, {
     4378                        /**
     4379                        Append another key-value pair to the FormData object
     4380
     4381                        @method append
     4382                        @param {String} name Name for the new field
     4383                        @param {String|Blob|Array|Object} value Value for the field
     4384                        */
     4385                        append: function(name, value) {
     4386                                var self = this, valueType = Basic.typeOf(value);
     4387
     4388                                // according to specs value might be either Blob or String
     4389                                if (value instanceof Blob) {
     4390                                        _blob = {
     4391                                                name: name,
     4392                                                value: value // unfortunately we can only send single Blob in one FormData
     4393                                        };
     4394                                } else if ('array' === valueType) {
     4395                                        name += '[]';
     4396
     4397                                        Basic.each(value, function(value) {
     4398                                                self.append(name, value);
     4399                                        });
     4400                                } else if ('object' === valueType) {
     4401                                        Basic.each(value, function(value, key) {
     4402                                                self.append(name + '[' + key + ']', value);
     4403                                        });
     4404                                } else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) {
     4405                                        self.append(name, "false");
     4406                                } else {
     4407                                        _fields.push({
     4408                                                name: name,
     4409                                                value: value.toString()
     4410                                        });
     4411                                }
     4412                        },
     4413
     4414                        /**
     4415                        Checks if FormData contains Blob.
     4416
     4417                        @method hasBlob
     4418                        @return {Boolean}
     4419                        */
     4420                        hasBlob: function() {
     4421                                return !!this.getBlob();
     4422                        },
     4423
     4424                        /**
     4425                        Retrieves blob.
     4426
     4427                        @method getBlob
     4428                        @return {Object} Either Blob if found or null
     4429                        */
     4430                        getBlob: function() {
     4431                                return _blob && _blob.value || null;
     4432                        },
     4433
     4434                        /**
     4435                        Retrieves blob field name.
     4436
     4437                        @method getBlobName
     4438                        @return {String} Either Blob field name or null
     4439                        */
     4440                        getBlobName: function() {
     4441                                return _blob && _blob.name || null;
     4442                        },
     4443
     4444                        /**
     4445                        Loop over the fields in FormData and invoke the callback for each of them.
     4446
     4447                        @method each
     4448                        @param {Function} cb Callback to call for each field
     4449                        */
     4450                        each: function(cb) {
     4451                                Basic.each(_fields, function(field) {
     4452                                        cb(field.value, field.name);
     4453                                });
     4454
     4455                                if (_blob) {
     4456                                        cb(_blob.value, _blob.name);
     4457                                }
     4458                        },
     4459
     4460                        destroy: function() {
     4461                                _blob = null;
     4462                                _fields = [];
     4463                        }
     4464                });
     4465        }
     4466
     4467        return FormData;
     4468});
     4469
     4470// Included from: src/javascript/xhr/XMLHttpRequest.js
     4471
     4472/**
     4473 * XMLHttpRequest.js
     4474 *
     4475 * Copyright 2013, Moxiecode Systems AB
     4476 * Released under GPL License.
     4477 *
     4478 * License: http://www.plupload.com/license
     4479 * Contributing: http://www.plupload.com/contributing
     4480 */
     4481
     4482define("moxie/xhr/XMLHttpRequest", [
     4483        "moxie/core/utils/Basic",
     4484        "moxie/core/Exceptions",
     4485        "moxie/core/EventTarget",
     4486        "moxie/core/utils/Encode",
     4487        "moxie/core/utils/Url",
     4488        "moxie/runtime/Runtime",
     4489        "moxie/runtime/RuntimeTarget",
     4490        "moxie/file/Blob",
     4491        "moxie/file/FileReaderSync",
     4492        "moxie/xhr/FormData",
     4493        "moxie/core/utils/Env",
     4494        "moxie/core/utils/Mime"
     4495], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) {
     4496
     4497        var httpCode = {
     4498                100: 'Continue',
     4499                101: 'Switching Protocols',
     4500                102: 'Processing',
     4501
     4502                200: 'OK',
     4503                201: 'Created',
     4504                202: 'Accepted',
     4505                203: 'Non-Authoritative Information',
     4506                204: 'No Content',
     4507                205: 'Reset Content',
     4508                206: 'Partial Content',
     4509                207: 'Multi-Status',
     4510                226: 'IM Used',
     4511
     4512                300: 'Multiple Choices',
     4513                301: 'Moved Permanently',
     4514                302: 'Found',
     4515                303: 'See Other',
     4516                304: 'Not Modified',
     4517                305: 'Use Proxy',
     4518                306: 'Reserved',
     4519                307: 'Temporary Redirect',
     4520
     4521                400: 'Bad Request',
     4522                401: 'Unauthorized',
     4523                402: 'Payment Required',
     4524                403: 'Forbidden',
     4525                404: 'Not Found',
     4526                405: 'Method Not Allowed',
     4527                406: 'Not Acceptable',
     4528                407: 'Proxy Authentication Required',
     4529                408: 'Request Timeout',
     4530                409: 'Conflict',
     4531                410: 'Gone',
     4532                411: 'Length Required',
     4533                412: 'Precondition Failed',
     4534                413: 'Request Entity Too Large',
     4535                414: 'Request-URI Too Long',
     4536                415: 'Unsupported Media Type',
     4537                416: 'Requested Range Not Satisfiable',
     4538                417: 'Expectation Failed',
     4539                422: 'Unprocessable Entity',
     4540                423: 'Locked',
     4541                424: 'Failed Dependency',
     4542                426: 'Upgrade Required',
     4543
     4544                500: 'Internal Server Error',
     4545                501: 'Not Implemented',
     4546                502: 'Bad Gateway',
     4547                503: 'Service Unavailable',
     4548                504: 'Gateway Timeout',
     4549                505: 'HTTP Version Not Supported',
     4550                506: 'Variant Also Negotiates',
     4551                507: 'Insufficient Storage',
     4552                510: 'Not Extended'
     4553        };
     4554
     4555        function XMLHttpRequestUpload() {
     4556                this.uid = Basic.guid('uid_');
     4557        }
     4558       
     4559        XMLHttpRequestUpload.prototype = EventTarget.instance;
     4560
     4561        /**
     4562        Implementation of XMLHttpRequest
     4563
     4564        @class XMLHttpRequest
     4565        @constructor
     4566        @uses RuntimeClient
     4567        @extends EventTarget
     4568        */
     4569        var dispatches = [
     4570                'loadstart',
     4571
     4572                'progress',
     4573
     4574                'abort',
     4575
     4576                'error',
     4577
     4578                'load',
     4579
     4580                'timeout',
     4581
     4582                'loadend'
     4583
     4584                // readystatechange (for historical reasons)
     4585        ];
     4586       
     4587        var NATIVE = 1, RUNTIME = 2;
     4588                                       
     4589        function XMLHttpRequest() {
     4590                var self = this,
     4591                        // this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible
     4592                        props = {
     4593                                /**
     4594                                The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout.
     4595
     4596                                @property timeout
     4597                                @type Number
     4598                                @default 0
     4599                                */
     4600                                timeout: 0,
     4601
     4602                                /**
     4603                                Current state, can take following values:
     4604                                UNSENT (numeric value 0)
     4605                                The object has been constructed.
     4606
     4607                                OPENED (numeric value 1)
     4608                                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.
     4609
     4610                                HEADERS_RECEIVED (numeric value 2)
     4611                                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.
     4612
     4613                                LOADING (numeric value 3)
     4614                                The response entity body is being received.
     4615
     4616                                DONE (numeric value 4)
     4617
     4618                                @property readyState
     4619                                @type Number
     4620                                @default 0 (UNSENT)
     4621                                */
     4622                                readyState: XMLHttpRequest.UNSENT,
     4623
     4624                                /**
     4625                                True when user credentials are to be included in a cross-origin request. False when they are to be excluded
     4626                                in a cross-origin request and when cookies are to be ignored in its response. Initially false.
     4627
     4628                                @property withCredentials
     4629                                @type Boolean
     4630                                @default false
     4631                                */
     4632                                withCredentials: false,
     4633
     4634                                /**
     4635                                Returns the HTTP status code.
     4636
     4637                                @property status
     4638                                @type Number
     4639                                @default 0
     4640                                */
     4641                                status: 0,
     4642
     4643                                /**
     4644                                Returns the HTTP status text.
     4645
     4646                                @property statusText
     4647                                @type String
     4648                                */
     4649                                statusText: "",
     4650
     4651                                /**
     4652                                Returns the response type. Can be set to change the response type. Values are:
     4653                                the empty string (default), "arraybuffer", "blob", "document", "json", and "text".
     4654                               
     4655                                @property responseType
     4656                                @type String
     4657                                */
     4658                                responseType: "",
     4659
     4660                                /**
     4661                                Returns the document response entity body.
     4662                               
     4663                                Throws an "InvalidStateError" exception if responseType is not the empty string or "document".
     4664
     4665                                @property responseXML
     4666                                @type Document
     4667                                */
     4668                                responseXML: null,
     4669
     4670                                /**
     4671                                Returns the text response entity body.
     4672                               
     4673                                Throws an "InvalidStateError" exception if responseType is not the empty string or "text".
     4674
     4675                                @property responseText
     4676                                @type String
     4677                                */
     4678                                responseText: null,
     4679
     4680                                /**
     4681                                Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body).
     4682                                Can become: ArrayBuffer, Blob, Document, JSON, Text
     4683                               
     4684                                @property response
     4685                                @type Mixed
     4686                                */
     4687                                response: null
     4688                        },
     4689
     4690                        _async = true,
     4691                        _url,
     4692                        _method,
     4693                        _headers = {},
     4694                        _user,
     4695                        _password,
     4696                        _encoding = null,
     4697                        _mimeType = null,
     4698
     4699                        // flags
     4700                        _sync_flag = false,
     4701                        _send_flag = false,
     4702                        _upload_events_flag = false,
     4703                        _upload_complete_flag = false,
     4704                        _error_flag = false,
     4705                        _same_origin_flag = false,
     4706
     4707                        // times
     4708                        _start_time,
     4709                        _timeoutset_time,
     4710
     4711                        _finalMime = null,
     4712                        _finalCharset = null,
     4713
     4714                        _options = {},
     4715                        _xhr,
     4716                        _responseHeaders = '',
     4717                        _responseHeadersBag
     4718                        ;
     4719
     4720               
     4721                Basic.extend(this, props, {
     4722                        /**
     4723                        Unique id of the component
     4724
     4725                        @property uid
     4726                        @type String
     4727                        */
     4728                        uid: Basic.guid('uid_'),
     4729                       
     4730                        /**
     4731                        Target for Upload events
     4732
     4733                        @property upload
     4734                        @type XMLHttpRequestUpload
     4735                        */
     4736                        upload: new XMLHttpRequestUpload(),
     4737                       
     4738
     4739                        /**
     4740                        Sets the request method, request URL, synchronous flag, request username, and request password.
     4741
     4742                        Throws a "SyntaxError" exception if one of the following is true:
     4743
     4744                        method is not a valid HTTP method.
     4745                        url cannot be resolved.
     4746                        url contains the "user:password" format in the userinfo production.
     4747                        Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK.
     4748
     4749                        Throws an "InvalidAccessError" exception if one of the following is true:
     4750
     4751                        Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin.
     4752                        There is an associated XMLHttpRequest document and either the timeout attribute is not zero,
     4753                        the withCredentials attribute is true, or the responseType attribute is not the empty string.
     4754
     4755
     4756                        @method open
     4757                        @param {String} method HTTP method to use on request
     4758                        @param {String} url URL to request
     4759                        @param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default.
     4760                        @param {String} [user] Username to use in HTTP authentication process on server-side
     4761                        @param {String} [password] Password to use in HTTP authentication process on server-side
     4762                        */
     4763                        open: function(method, url, async, user, password) {
     4764                                var urlp;
     4765                               
     4766                                // first two arguments are required
     4767                                if (!method || !url) {
     4768                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
     4769                                }
     4770                               
     4771                                // 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method
     4772                                if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) {
     4773                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
     4774                                }
     4775
     4776                                // 3
     4777                                if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) {
     4778                                        _method = method.toUpperCase();
     4779                                }
     4780                               
     4781                               
     4782                                // 4 - allowing these methods poses a security risk
     4783                                if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) {
     4784                                        throw new x.DOMException(x.DOMException.SECURITY_ERR);
     4785                                }
     4786
     4787                                // 5
     4788                                url = Encode.utf8_encode(url);
     4789                               
     4790                                // 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError".
     4791                                urlp = Url.parseUrl(url);
     4792
     4793                                _same_origin_flag = Url.hasSameOrigin(urlp);
     4794                                                                                                                               
     4795                                // 7 - manually build up absolute url
     4796                                _url = Url.resolveUrl(url);
     4797               
     4798                                // 9-10, 12-13
     4799                                if ((user || password) && !_same_origin_flag) {
     4800                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
     4801                                }
     4802
     4803                                _user = user || urlp.user;
     4804                                _password = password || urlp.pass;
     4805                               
     4806                                // 11
     4807                                _async = async || true;
     4808                               
     4809                                if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) {
     4810                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
     4811                                }
     4812                               
     4813                                // 14 - terminate abort()
     4814                               
     4815                                // 15 - terminate send()
     4816
     4817                                // 18
     4818                                _sync_flag = !_async;
     4819                                _send_flag = false;
     4820                                _headers = {};
     4821                                _reset.call(this);
     4822
     4823                                // 19
     4824                                _p('readyState', XMLHttpRequest.OPENED);
     4825                               
     4826                                // 20
     4827                                this.dispatchEvent('readystatechange');
     4828                        },
     4829                       
     4830                        /**
     4831                        Appends an header to the list of author request headers, or if header is already
     4832                        in the list of author request headers, combines its value with value.
     4833
     4834                        Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
     4835                        Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value
     4836                        is not a valid HTTP header field value.
     4837                       
     4838                        @method setRequestHeader
     4839                        @param {String} header
     4840                        @param {String|Number} value
     4841                        */
     4842                        setRequestHeader: function(header, value) {
     4843                                var uaHeaders = [ // these headers are controlled by the user agent
     4844                                                "accept-charset",
     4845                                                "accept-encoding",
     4846                                                "access-control-request-headers",
     4847                                                "access-control-request-method",
     4848                                                "connection",
     4849                                                "content-length",
     4850                                                "cookie",
     4851                                                "cookie2",
     4852                                                "content-transfer-encoding",
     4853                                                "date",
     4854                                                "expect",
     4855                                                "host",
     4856                                                "keep-alive",
     4857                                                "origin",
     4858                                                "referer",
     4859                                                "te",
     4860                                                "trailer",
     4861                                                "transfer-encoding",
     4862                                                "upgrade",
     4863                                                "user-agent",
     4864                                                "via"
     4865                                        ];
     4866                               
     4867                                // 1-2
     4868                                if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) {
     4869                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
     4870                                }
     4871
     4872                                // 3
     4873                                if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) {
     4874                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
     4875                                }
     4876
     4877                                // 4
     4878                                /* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values
     4879                                if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) {
     4880                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
     4881                                }*/
     4882
     4883                                header = Basic.trim(header).toLowerCase();
     4884                               
     4885                                // setting of proxy-* and sec-* headers is prohibited by spec
     4886                                if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) {
     4887                                        return false;
     4888                                }
     4889
     4890                                // camelize
     4891                                // browsers lowercase header names (at least for custom ones)
     4892                                // header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); });
     4893                               
     4894                                if (!_headers[header]) {
     4895                                        _headers[header] = value;
     4896                                } else {
     4897                                        // http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph)
     4898                                        _headers[header] += ', ' + value;
     4899                                }
     4900                                return true;
     4901                        },
     4902
     4903                        /**
     4904                        Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2.
     4905
     4906                        @method getAllResponseHeaders
     4907                        @return {String} reponse headers or empty string
     4908                        */
     4909                        getAllResponseHeaders: function() {
     4910                                return _responseHeaders || '';
     4911                        },
     4912
     4913                        /**
     4914                        Returns the header field value from the response of which the field name matches header,
     4915                        unless the field name is Set-Cookie or Set-Cookie2.
     4916
     4917                        @method getResponseHeader
     4918                        @param {String} header
     4919                        @return {String} value(s) for the specified header or null
     4920                        */
     4921                        getResponseHeader: function(header) {
     4922                                header = header.toLowerCase();
     4923
     4924                                if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) {
     4925                                        return null;
     4926                                }
     4927
     4928                                if (_responseHeaders && _responseHeaders !== '') {
     4929                                        // if we didn't parse response headers until now, do it and keep for later
     4930                                        if (!_responseHeadersBag) {
     4931                                                _responseHeadersBag = {};
     4932                                                Basic.each(_responseHeaders.split(/\r\n/), function(line) {
     4933                                                        var pair = line.split(/:\s+/);
     4934                                                        if (pair.length === 2) { // last line might be empty, omit
     4935                                                                pair[0] = Basic.trim(pair[0]); // just in case
     4936                                                                _responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form
     4937                                                                        header: pair[0],
     4938                                                                        value: Basic.trim(pair[1])
     4939                                                                };
     4940                                                        }
     4941                                                });
     4942                                        }
     4943                                        if (_responseHeadersBag.hasOwnProperty(header)) {
     4944                                                return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value;
     4945                                        }
     4946                                }
     4947                                return null;
     4948                        },
     4949                       
     4950                        /**
     4951                        Sets the Content-Type header for the response to mime.
     4952                        Throws an "InvalidStateError" exception if the state is LOADING or DONE.
     4953                        Throws a "SyntaxError" exception if mime is not a valid media type.
     4954
     4955                        @method overrideMimeType
     4956                        @param String mime Mime type to set
     4957                        */
     4958                        overrideMimeType: function(mime) {
     4959                                var matches, charset;
     4960                       
     4961                                // 1
     4962                                if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
     4963                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
     4964                                }
     4965
     4966                                // 2
     4967                                mime = Basic.trim(mime.toLowerCase());
     4968
     4969                                if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) {
     4970                                        mime = matches[1];
     4971                                        if (matches[2]) {
     4972                                                charset = matches[2];
     4973                                        }
     4974                                }
     4975
     4976                                if (!Mime.mimes[mime]) {
     4977                                        throw new x.DOMException(x.DOMException.SYNTAX_ERR);
     4978                                }
     4979
     4980                                // 3-4
     4981                                _finalMime = mime;
     4982                                _finalCharset = charset;
     4983                        },
     4984                       
     4985                        /**
     4986                        Initiates the request. The optional argument provides the request entity body.
     4987                        The argument is ignored if request method is GET or HEAD.
     4988
     4989                        Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set.
     4990
     4991                        @method send
     4992                        @param {Blob|Document|String|FormData} [data] Request entity body
     4993                        @param {Object} [options] Set of requirements and pre-requisities for runtime initialization
     4994                        */
     4995                        send: function(data, options) {                                 
     4996                                if (Basic.typeOf(options) === 'string') {
     4997                                        _options = { ruid: options };
     4998                                } else if (!options) {
     4999                                        _options = {};
     5000                                } else {
     5001                                        _options = options;
     5002                                }
     5003                                                                                                                       
     5004                                // 1-2
     5005                                if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) {
     5006                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
     5007                                }
     5008                               
     5009                                // 3                                   
     5010                                // sending Blob
     5011                                if (data instanceof Blob) {
     5012                                        _options.ruid = data.ruid;
     5013                                        _mimeType = data.type || 'application/octet-stream';
     5014                                }
     5015                               
     5016                                // FormData
     5017                                else if (data instanceof FormData) {
     5018                                        if (data.hasBlob()) {
     5019                                                var blob = data.getBlob();
     5020                                                _options.ruid = blob.ruid;
     5021                                                _mimeType = blob.type || 'application/octet-stream';
     5022                                        }
     5023                                }
     5024                               
     5025                                // DOMString
     5026                                else if (typeof data === 'string') {
     5027                                        _encoding = 'UTF-8';
     5028                                        _mimeType = 'text/plain;charset=UTF-8';
     5029                                       
     5030                                        // data should be converted to Unicode and encoded as UTF-8
     5031                                        data = Encode.utf8_encode(data);
     5032                                }
     5033
     5034                                // if withCredentials not set, but requested, set it automatically
     5035                                if (!this.withCredentials) {
     5036                                        this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag;
     5037                                }
     5038
     5039                                // 4 - storage mutex
     5040                                // 5
     5041                                _upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP
     5042                                // 6
     5043                                _error_flag = false;
     5044                                // 7
     5045                                _upload_complete_flag = !data;
     5046                                // 8 - Asynchronous steps
     5047                                if (!_sync_flag) {
     5048                                        // 8.1
     5049                                        _send_flag = true;
     5050                                        // 8.2
     5051                                        // this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr
     5052                                        // 8.3
     5053                                        //if (!_upload_complete_flag) {
     5054                                                // this.upload.dispatchEvent('loadstart');      // will be dispatched either by native or runtime xhr
     5055                                        //}
     5056                                }
     5057                                // 8.5 - Return the send() method call, but continue running the steps in this algorithm.
     5058                                _doXHR.call(this, data);
     5059                        },
     5060                       
     5061                        /**
     5062                        Cancels any network activity.
     5063                       
     5064                        @method abort
     5065                        */
     5066                        abort: function() {
     5067                                _error_flag = true;
     5068                                _sync_flag = false;
     5069
     5070                                if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) {
     5071                                        _p('readyState', XMLHttpRequest.DONE);
     5072                                        _send_flag = false;
     5073
     5074                                        if (_xhr) {
     5075                                                _xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag);
     5076                                        } else {
     5077                                                throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
     5078                                        }
     5079
     5080                                        _upload_complete_flag = true;
     5081                                } else {
     5082                                        _p('readyState', XMLHttpRequest.UNSENT);
     5083                                }
     5084                        },
     5085
     5086                        destroy: function() {
     5087                                if (_xhr) {
     5088                                        if (Basic.typeOf(_xhr.destroy) === 'function') {
     5089                                                _xhr.destroy();
     5090                                        }
     5091                                        _xhr = null;
     5092                                }
     5093
     5094                                this.unbindAll();
     5095
     5096                                if (this.upload) {
     5097                                        this.upload.unbindAll();
     5098                                        this.upload = null;
     5099                                }
     5100                        }
     5101                });
     5102
     5103                this.handleEventProps(dispatches.concat(['readystatechange'])); // for historical reasons
     5104                this.upload.handleEventProps(dispatches);
     5105
     5106                /* this is nice, but maybe too lengthy
     5107
     5108                // if supported by JS version, set getters/setters for specific properties
     5109                o.defineProperty(this, 'readyState', {
     5110                        configurable: false,
     5111
     5112                        get: function() {
     5113                                return _p('readyState');
     5114                        }
     5115                });
     5116
     5117                o.defineProperty(this, 'timeout', {
     5118                        configurable: false,
     5119
     5120                        get: function() {
     5121                                return _p('timeout');
     5122                        },
     5123
     5124                        set: function(value) {
     5125
     5126                                if (_sync_flag) {
     5127                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
     5128                                }
     5129
     5130                                // timeout still should be measured relative to the start time of request
     5131                                _timeoutset_time = (new Date).getTime();
     5132
     5133                                _p('timeout', value);
     5134                        }
     5135                });
     5136
     5137                // the withCredentials attribute has no effect when fetching same-origin resources
     5138                o.defineProperty(this, 'withCredentials', {
     5139                        configurable: false,
     5140
     5141                        get: function() {
     5142                                return _p('withCredentials');
     5143                        },
     5144
     5145                        set: function(value) {
     5146                                // 1-2
     5147                                if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) {
     5148                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
     5149                                }
     5150
     5151                                // 3-4
     5152                                if (_anonymous_flag || _sync_flag) {
     5153                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
     5154                                }
     5155
     5156                                // 5
     5157                                _p('withCredentials', value);
     5158                        }
     5159                });
     5160
     5161                o.defineProperty(this, 'status', {
     5162                        configurable: false,
     5163
     5164                        get: function() {
     5165                                return _p('status');
     5166                        }
     5167                });
     5168
     5169                o.defineProperty(this, 'statusText', {
     5170                        configurable: false,
     5171
     5172                        get: function() {
     5173                                return _p('statusText');
     5174                        }
     5175                });
     5176
     5177                o.defineProperty(this, 'responseType', {
     5178                        configurable: false,
     5179
     5180                        get: function() {
     5181                                return _p('responseType');
     5182                        },
     5183
     5184                        set: function(value) {
     5185                                // 1
     5186                                if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) {
     5187                                        throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
     5188                                }
     5189
     5190                                // 2
     5191                                if (_sync_flag) {
     5192                                        throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR);
     5193                                }
     5194
     5195                                // 3
     5196                                _p('responseType', value.toLowerCase());
     5197                        }
     5198                });
     5199
     5200                o.defineProperty(this, 'responseText', {
     5201                        configurable: false,
     5202