Make WordPress Core

Ticket #48277: 48277.3.diff

File 48277.3.diff, 414.6 KB (added by desrosj, 5 years ago)
  • Gruntfile.js

     
    167167                                                [ WORKING_DIR + 'wp-includes/js/jquery/jquery-migrate.min.js' ]: [ './node_modules/jquery-migrate/dist/jquery-migrate.min.js' ],
    168168                                                [ WORKING_DIR + 'wp-includes/js/jquery/jquery.form.js' ]: [ './node_modules/jquery-form/src/jquery.form.js' ],
    169169                                                [ WORKING_DIR + 'wp-includes/js/masonry.min.js' ]: [ './node_modules/masonry-layout/dist/masonry.pkgd.min.js' ],
     170                                                [ WORKING_DIR + 'wp-includes/js/plupload/license.txt' ]: [ './node_modules/plupload/license.txt' ],
     171                                                [ WORKING_DIR + 'wp-includes/js/plupload/moxie.js' ]: [ './node_modules/plupload/js/moxie.js' ],
     172                                                [ WORKING_DIR + 'wp-includes/js/plupload/plupload.js' ]: [ './node_modules/plupload/js/plupload.dev.js' ],
    170173                                                [ WORKING_DIR + 'wp-includes/js/twemoji.js' ]: [ './node_modules/twemoji/dist/twemoji.js' ],
    171174                                                [ WORKING_DIR + 'wp-includes/js/underscore.js' ]: [ './node_modules/underscore/underscore.js' ],
    172175                                        },
     
    294297                                        [ WORKING_DIR + 'wp-includes/js/heartbeat.js' ]: [ './src/js/_enqueues/wp/heartbeat.js' ],
    295298                                        [ WORKING_DIR + 'wp-includes/js/mce-view.js' ]: [ './src/js/_enqueues/wp/mce-view.js' ],
    296299                                        [ WORKING_DIR + 'wp-includes/js/media-editor.js' ]: [ './src/js/_enqueues/wp/media/editor.js' ],
     300                                        [ WORKING_DIR + 'wp-includes/js/plupload/handlers.js' ]: [ './src/js/_enqueues/wp/plupload/handlers.js' ],
     301                                        [ WORKING_DIR + 'wp-includes/js/plupload/wp-plupload.js' ]: [ './src/js/_enqueues/wp/plupload/wp-plupload.js' ],
    297302                                        [ WORKING_DIR + 'wp-includes/js/quicktags.js' ]: [ './src/js/_enqueues/lib/quicktags.js' ],
    298303                                        [ WORKING_DIR + 'wp-includes/js/shortcode.js' ]: [ './src/js/_enqueues/wp/shortcode.js' ],
    299304                                        [ WORKING_DIR + 'wp-includes/js/utils.js' ]: [ './src/js/_enqueues/lib/cookies.js' ],
     
    10751080                                                dest: SOURCE_DIR + 'wp-includes/'
    10761081                                        }
    10771082                                ]
     1083                        },
     1084                        plupload: {
     1085                                options: {
     1086                                        patterns: [
     1087                                                {
     1088                                                        match: /;var MXI_DEBUG = true;/g,
     1089                                                        replacement: function () {
     1090                                                                return ';var MXI_DEBUG = false;';
     1091                                                        }
     1092                                                }
     1093                                        ]
     1094                                },
     1095                                files: [
     1096                                        {
     1097                                                expand: true,
     1098                                                flatten: true,
     1099                                                src: [
     1100                                                        'build/wp-includes/js/plupload/moxie.js'
     1101                                                ],
     1102                                                dest: 'build/wp-includes/js/plupload/'
     1103                                        }
     1104                                ]
    10781105                        }
    10791106                },
    10801107                _watch: {
     
    13521379                'webpack:prod',
    13531380                'webpack:dev',
    13541381                'copy:js',
     1382                'replace:plupload',
    13551383                'file_append',
    13561384                'uglify:all',
    13571385                'concat:tinymce',
  • package-lock.json

     
    1578415784                                }
    1578515785                        }
    1578615786                },
     15787                "plupload": {
     15788                        "version": "2.3.6",
     15789                        "resolved": "https://registry.npmjs.org/plupload/-/plupload-2.3.6.tgz",
     15790                        "integrity": "sha1-Jgis9zXV6NuDJIck142BdXu0OGY="
     15791                },
    1578715792                "plur": {
    1578815793                        "version": "3.1.1",
    1578915794                        "resolved": "https://registry.npmjs.org/plur/-/plur-3.1.1.tgz",
  • package.json

     
    8383                "@wordpress/components": "8.3.2",
    8484                "@wordpress/compose": "3.7.2",
    8585                "@wordpress/core-data": "2.7.4",
    86                 "@wordpress/data-controls": "1.3.4",
    8786                "@wordpress/data": "4.9.2",
     87                "@wordpress/data-controls": "1.3.4",
    8888                "@wordpress/date": "3.5.0",
    8989                "@wordpress/deprecated": "2.6.1",
    90                 "@wordpress/dom-ready": "2.5.1",
    9190                "@wordpress/dom": "2.5.2",
     91                "@wordpress/dom-ready": "2.5.1",
    9292                "@wordpress/edit-post": "3.8.4",
    9393                "@wordpress/editor": "9.7.4",
    9494                "@wordpress/element": "2.8.2",
     
    125125                "lodash": "4.17.15",
    126126                "masonry-layout": "3.3.2",
    127127                "moment": "2.22.2",
     128                "plupload": "2.3.6",
    128129                "polyfill-library": "3.27.4",
    129130                "react": "16.9.0",
    130131                "react-dom": "16.9.0",
  • src/js/_enqueues/vendor/plupload/handlers.js

     
    1 /* global plupload, pluploadL10n, ajaxurl, post_id, wpUploaderInit, deleteUserSetting, setUserSetting, getUserSetting, shortform */
    2 var topWin = window.dialogArguments || opener || parent || top, uploader, uploader_init;
    3 
    4 // progress and success handlers for media multi uploads
    5 function fileQueued( fileObj ) {
    6         // Get rid of unused form
    7         jQuery( '.media-blank' ).remove();
    8 
    9         var items = jQuery( '#media-items' ).children(), postid = post_id || 0;
    10 
    11         // Collapse a single item
    12         if ( items.length == 1 ) {
    13                 items.removeClass( 'open' ).find( '.slidetoggle' ).slideUp( 200 );
    14         }
    15         // Create a progress bar containing the filename
    16         jQuery( '<div class="media-item">' )
    17                 .attr( 'id', 'media-item-' + fileObj.id )
    18                 .addClass( 'child-of-' + postid )
    19                 .append( '<div class="progress"><div class="percent">0%</div><div class="bar"></div></div>',
    20                         jQuery( '<div class="filename original">' ).text( ' ' + fileObj.name ) )
    21                 .appendTo( jQuery( '#media-items' ) );
    22 
    23         // Disable submit
    24         jQuery( '#insert-gallery' ).prop( 'disabled', true );
    25 }
    26 
    27 function uploadStart() {
    28         try {
    29                 if ( typeof topWin.tb_remove != 'undefined' )
    30                         topWin.jQuery( '#TB_overlay' ).unbind( 'click', topWin.tb_remove );
    31         } catch( e ){}
    32 
    33         return true;
    34 }
    35 
    36 function uploadProgress( up, file ) {
    37         var item = jQuery( '#media-item-' + file.id );
    38 
    39         jQuery( '.bar', item ).width( ( 200 * file.loaded ) / file.size );
    40         jQuery( '.percent', item ).html( file.percent + '%' );
    41 }
    42 
    43 // check to see if a large file failed to upload
    44 function fileUploading( up, file ) {
    45         var hundredmb = 100 * 1024 * 1024,
    46                 max = parseInt( up.settings.max_file_size, 10 );
    47 
    48         if ( max > hundredmb && file.size > hundredmb ) {
    49                 setTimeout( function() {
    50                         if ( file.status < 3 && file.loaded === 0 ) { // not uploading
    51                                 wpFileError( file, pluploadL10n.big_upload_failed.replace( '%1$s', '<a class="uploader-html" href="#">' ).replace( '%2$s', '</a>' ) );
    52                                 up.stop(); // stops the whole queue
    53                                 up.removeFile( file );
    54                                 up.start(); // restart the queue
    55                         }
    56                 }, 10000 ); // wait for 10 sec. for the file to start uploading
    57         }
    58 }
    59 
    60 function updateMediaForm() {
    61         var items = jQuery( '#media-items' ).children();
    62 
    63         // Just one file, no need for collapsible part
    64         if ( items.length == 1 ) {
    65                 items.addClass( 'open' ).find( '.slidetoggle' ).show();
    66                 jQuery( '.insert-gallery' ).hide();
    67         } else if ( items.length > 1 ) {
    68                 items.removeClass( 'open' );
    69                 // Only show Gallery/Playlist buttons when there are at least two files.
    70                 jQuery( '.insert-gallery' ).show();
    71         }
    72 
    73         // Only show Save buttons when there is at least one file.
    74         if ( items.not( '.media-blank' ).length > 0 )
    75                 jQuery( '.savebutton' ).show();
    76         else
    77                 jQuery( '.savebutton' ).hide();
    78 }
    79 
    80 function uploadSuccess( fileObj, serverData ) {
    81         var item = jQuery( '#media-item-' + fileObj.id );
    82 
    83         // on success serverData should be numeric, fix bug in html4 runtime returning the serverData wrapped in a <pre> tag
    84         if ( typeof serverData === 'string' ) {
    85                 serverData = serverData.replace( /^<pre>(\d+)<\/pre>$/, '$1' );
    86 
    87                 // if async-upload returned an error message, place it in the media item div and return
    88                 if ( /media-upload-error|error-div/.test( serverData ) ) {
    89                         item.html( serverData );
    90                         return;
    91                 }
    92         }
    93 
    94         item.find( '.percent' ).html( pluploadL10n.crunching );
    95 
    96         prepareMediaItem( fileObj, serverData );
    97         updateMediaForm();
    98 
    99         // Increment the counter.
    100         if ( post_id && item.hasClass( 'child-of-' + post_id ) ) {
    101                 jQuery( '#attachments-count' ).text( 1 * jQuery( '#attachments-count' ).text() + 1 );
    102         }
    103 }
    104 
    105 function setResize( arg ) {
    106         if ( arg ) {
    107                 if ( window.resize_width && window.resize_height ) {
    108                         uploader.settings.resize = {
    109                                 enabled: true,
    110                                 width: window.resize_width,
    111                                 height: window.resize_height,
    112                                 quality: 100
    113                         };
    114                 } else {
    115                         uploader.settings.multipart_params.image_resize = true;
    116                 }
    117         } else {
    118                 delete( uploader.settings.multipart_params.image_resize );
    119         }
    120 }
    121 
    122 function prepareMediaItem( fileObj, serverData ) {
    123         var f = ( typeof shortform == 'undefined' ) ? 1 : 2, item = jQuery( '#media-item-' + fileObj.id );
    124         if ( f == 2 && shortform > 2 )
    125                 f = shortform;
    126 
    127         try {
    128                 if ( typeof topWin.tb_remove != 'undefined' )
    129                         topWin.jQuery( '#TB_overlay' ).click( topWin.tb_remove );
    130         } catch( e ){}
    131 
    132         if ( isNaN( serverData ) || !serverData ) { // Old style: Append the HTML returned by the server -- thumbnail and form inputs
    133                 item.append( serverData );
    134                 prepareMediaItemInit( fileObj );
    135         } else { // New style: server data is just the attachment ID, fetch the thumbnail and form html from the server
    136                 item.load( 'async-upload.php', {attachment_id:serverData, fetch:f}, function(){prepareMediaItemInit( fileObj );updateMediaForm();});
    137         }
    138 }
    139 
    140 function prepareMediaItemInit( fileObj ) {
    141         var item = jQuery( '#media-item-' + fileObj.id );
    142         // Clone the thumbnail as a "pinkynail" -- a tiny image to the left of the filename
    143         jQuery( '.thumbnail', item ).clone().attr( 'class', 'pinkynail toggle' ).prependTo( item );
    144 
    145         // Replace the original filename with the new (unique) one assigned during upload
    146         jQuery( '.filename.original', item ).replaceWith( jQuery( '.filename.new', item ) );
    147 
    148         // Bind AJAX to the new Delete button
    149         jQuery( 'a.delete', item ).click( function(){
    150                 // Tell the server to delete it. TODO: handle exceptions
    151                 jQuery.ajax({
    152                         url: ajaxurl,
    153                         type: 'post',
    154                         success: deleteSuccess,
    155                         error: deleteError,
    156                         id: fileObj.id,
    157                         data: {
    158                                 id : this.id.replace(/[^0-9]/g, '' ),
    159                                 action : 'trash-post',
    160                                 _ajax_nonce : this.href.replace(/^.*wpnonce=/,'' )
    161                         }
    162                 });
    163                 return false;
    164         });
    165 
    166         // Bind AJAX to the new Undo button
    167         jQuery( 'a.undo', item ).click( function(){
    168                 // Tell the server to untrash it. TODO: handle exceptions
    169                 jQuery.ajax({
    170                         url: ajaxurl,
    171                         type: 'post',
    172                         id: fileObj.id,
    173                         data: {
    174                                 id : this.id.replace(/[^0-9]/g,'' ),
    175                                 action: 'untrash-post',
    176                                 _ajax_nonce: this.href.replace(/^.*wpnonce=/,'' )
    177                         },
    178                         success: function( ){
    179                                 var type,
    180                                         item = jQuery( '#media-item-' + fileObj.id );
    181 
    182                                 if ( type = jQuery( '#type-of-' + fileObj.id ).val() )
    183                                         jQuery( '#' + type + '-counter' ).text( jQuery( '#' + type + '-counter' ).text()-0+1 );
    184 
    185                                 if ( post_id && item.hasClass( 'child-of-'+post_id ) )
    186                                         jQuery( '#attachments-count' ).text( jQuery( '#attachments-count' ).text()-0+1 );
    187 
    188                                 jQuery( '.filename .trashnotice', item ).remove();
    189                                 jQuery( '.filename .title', item ).css( 'font-weight','normal' );
    190                                 jQuery( 'a.undo', item ).addClass( 'hidden' );
    191                                 jQuery( '.menu_order_input', item ).show();
    192                                 item.css( {backgroundColor:'#ceb'} ).animate( {backgroundColor: '#fff'}, { queue: false, duration: 500, complete: function(){ jQuery( this ).css({backgroundColor:''}); } }).removeClass( 'undo' );
    193                         }
    194                 });
    195                 return false;
    196         });
    197 
    198         // Open this item if it says to start open (e.g. to display an error)
    199         jQuery( '#media-item-' + fileObj.id + '.startopen' ).removeClass( 'startopen' ).addClass( 'open' ).find( 'slidetoggle' ).fadeIn();
    200 }
    201 
    202 // generic error message
    203 function wpQueueError( message ) {
    204         jQuery( '#media-upload-error' ).show().html( '<div class="error"><p>' + message + '</p></div>' );
    205 }
    206 
    207 // file-specific error messages
    208 function wpFileError( fileObj, message ) {
    209         itemAjaxError( fileObj.id, message );
    210 }
    211 
    212 function itemAjaxError( id, message ) {
    213         var item = jQuery( '#media-item-' + id ), filename = item.find( '.filename' ).text(), last_err = item.data( 'last-err' );
    214 
    215         if ( last_err == id ) // prevent firing an error for the same file twice
    216                 return;
    217 
    218         item.html( '<div class="error-div">' +
    219                                 '<a class="dismiss" href="#">' + pluploadL10n.dismiss + '</a>' +
    220                                 '<strong>' + pluploadL10n.error_uploading.replace( '%s', jQuery.trim( filename )) + '</strong> ' +
    221                                 message +
    222                                 '</div>' ).data( 'last-err', id );
    223 }
    224 
    225 function deleteSuccess( data ) {
    226         var type, id, item;
    227         if ( data == '-1' )
    228                 return itemAjaxError( this.id, 'You do not have permission. Has your session expired?' );
    229 
    230         if ( data == '0' )
    231                 return itemAjaxError( this.id, 'Could not be deleted. Has it been deleted already?' );
    232 
    233         id = this.id;
    234         item = jQuery( '#media-item-' + id );
    235 
    236         // Decrement the counters.
    237         if ( type = jQuery( '#type-of-' + id ).val() )
    238                 jQuery( '#' + type + '-counter' ).text( jQuery( '#' + type + '-counter' ).text() - 1 );
    239 
    240         if ( post_id && item.hasClass( 'child-of-'+post_id ) )
    241                 jQuery( '#attachments-count' ).text( jQuery( '#attachments-count' ).text() - 1 );
    242 
    243         if ( jQuery( 'form.type-form #media-items' ).children().length == 1 && jQuery( '.hidden', '#media-items' ).length > 0 ) {
    244                 jQuery( '.toggle' ).toggle();
    245                 jQuery( '.slidetoggle' ).slideUp( 200 ).siblings().removeClass( 'hidden' );
    246         }
    247 
    248         // Vanish it.
    249         jQuery( '.toggle', item ).toggle();
    250         jQuery( '.slidetoggle', item ).slideUp( 200 ).siblings().removeClass( 'hidden' );
    251         item.css( {backgroundColor:'#faa'} ).animate( {backgroundColor:'#f4f4f4'}, {queue:false, duration:500} ).addClass( 'undo' );
    252 
    253         jQuery( '.filename:empty', item ).remove();
    254         jQuery( '.filename .title', item ).css( 'font-weight','bold' );
    255         jQuery( '.filename', item ).append( '<span class="trashnotice"> ' + pluploadL10n.deleted + ' </span>' ).siblings( 'a.toggle' ).hide();
    256         jQuery( '.filename', item ).append( jQuery( 'a.undo', item ).removeClass( 'hidden' ) );
    257         jQuery( '.menu_order_input', item ).hide();
    258 
    259         return;
    260 }
    261 
    262 function deleteError() {
    263 }
    264 
    265 function uploadComplete() {
    266         jQuery( '#insert-gallery' ).prop( 'disabled', false );
    267 }
    268 
    269 function switchUploader( s ) {
    270         if ( s ) {
    271                 deleteUserSetting( 'uploader' );
    272                 jQuery( '.media-upload-form' ).removeClass( 'html-uploader' );
    273 
    274                 if ( typeof( uploader ) == 'object' )
    275                         uploader.refresh();
    276         } else {
    277                 setUserSetting( 'uploader', '1' ); // 1 == html uploader
    278                 jQuery( '.media-upload-form' ).addClass( 'html-uploader' );
    279         }
    280 }
    281 
    282 function uploadError( fileObj, errorCode, message, up ) {
    283         var hundredmb = 100 * 1024 * 1024, max;
    284 
    285         switch ( errorCode ) {
    286                 case plupload.FAILED:
    287                         wpFileError( fileObj, pluploadL10n.upload_failed );
    288                         break;
    289                 case plupload.FILE_EXTENSION_ERROR:
    290                         wpFileExtensionError( up, fileObj, pluploadL10n.invalid_filetype );
    291                         break;
    292                 case plupload.FILE_SIZE_ERROR:
    293                         uploadSizeError( up, fileObj );
    294                         break;
    295                 case plupload.IMAGE_FORMAT_ERROR:
    296                         wpFileError( fileObj, pluploadL10n.not_an_image );
    297                         break;
    298                 case plupload.IMAGE_MEMORY_ERROR:
    299                         wpFileError( fileObj, pluploadL10n.image_memory_exceeded );
    300                         break;
    301                 case plupload.IMAGE_DIMENSIONS_ERROR:
    302                         wpFileError( fileObj, pluploadL10n.image_dimensions_exceeded );
    303                         break;
    304                 case plupload.GENERIC_ERROR:
    305                         wpQueueError( pluploadL10n.upload_failed );
    306                         break;
    307                 case plupload.IO_ERROR:
    308                         max = parseInt( up.settings.filters.max_file_size, 10 );
    309 
    310                         if ( max > hundredmb && fileObj.size > hundredmb ) {
    311                                 wpFileError( fileObj, pluploadL10n.big_upload_failed.replace( '%1$s', '<a class="uploader-html" href="#">' ).replace( '%2$s', '</a>' ) );
    312                         } else {
    313                                 wpQueueError( pluploadL10n.io_error );
    314                         }
    315 
    316                         break;
    317                 case plupload.HTTP_ERROR:
    318                         wpQueueError( pluploadL10n.http_error );
    319                         break;
    320                 case plupload.INIT_ERROR:
    321                         jQuery( '.media-upload-form' ).addClass( 'html-uploader' );
    322                         break;
    323                 case plupload.SECURITY_ERROR:
    324                         wpQueueError( pluploadL10n.security_error );
    325                         break;
    326 /*              case plupload.UPLOAD_ERROR.UPLOAD_STOPPED:
    327                 case plupload.UPLOAD_ERROR.FILE_CANCELLED:
    328                         jQuery( '#media-item-' + fileObj.id ).remove();
    329                         break;*/
    330                 default:
    331                         wpFileError( fileObj, pluploadL10n.default_error );
    332         }
    333 }
    334 
    335 function uploadSizeError( up, file ) {
    336         var message, errorDiv;
    337 
    338         message = pluploadL10n.file_exceeds_size_limit.replace( '%s', file.name );
    339 
    340         // Construct the error div.
    341         errorDiv = jQuery( '<div />' )
    342                 .attr( {
    343                         'id':    'media-item-' + file.id,
    344                         'class': 'media-item error'
    345                 } )
    346                 .append(
    347                         jQuery( '<p />' )
    348                                 .text( message )
    349                 );
    350 
    351         // Append the error.
    352         jQuery( '#media-items' ).append( errorDiv );
    353         up.removeFile( file );
    354 }
    355 
    356 function wpFileExtensionError( up, file, message ) {
    357         jQuery( '#media-items' ).append( '<div id="media-item-' + file.id + '" class="media-item error"><p>' + message + '</p></div>' );
    358         up.removeFile( file );
    359 }
    360 
    361 jQuery( document ).ready( function( $ ) {
    362         var tryAgainCount = {};
    363         var tryAgain;
    364 
    365         $( '.media-upload-form' ).bind( 'click.uploader', function( e ) {
    366                 var target = $( e.target ), tr, c;
    367 
    368                 if ( target.is( 'input[type="radio"]' ) ) { // remember the last used image size and alignment
    369                         tr = target.closest( 'tr' );
    370 
    371                         if ( tr.hasClass( 'align' ) )
    372                                 setUserSetting( 'align', target.val() );
    373                         else if ( tr.hasClass( 'image-size' ) )
    374                                 setUserSetting( 'imgsize', target.val() );
    375 
    376                 } else if ( target.is( 'button.button' ) ) { // remember the last used image link url
    377                         c = e.target.className || '';
    378                         c = c.match( /url([^ '"]+)/ );
    379 
    380                         if ( c && c[1] ) {
    381                                 setUserSetting( 'urlbutton', c[1] );
    382                                 target.siblings( '.urlfield' ).val( target.data( 'link-url' ) );
    383                         }
    384                 } else if ( target.is( 'a.dismiss' ) ) {
    385                         target.parents( '.media-item' ).fadeOut( 200, function() {
    386                                 $( this ).remove();
    387                         } );
    388                 } else if ( target.is( '.upload-flash-bypass a' ) || target.is( 'a.uploader-html' ) ) { // switch uploader to html4
    389                         $( '#media-items, p.submit, span.big-file-warning' ).css( 'display', 'none' );
    390                         switchUploader( 0 );
    391                         e.preventDefault();
    392                 } else if ( target.is( '.upload-html-bypass a' ) ) { // switch uploader to multi-file
    393                         $( '#media-items, p.submit, span.big-file-warning' ).css( 'display', '' );
    394                         switchUploader( 1 );
    395                         e.preventDefault();
    396                 } else if ( target.is( 'a.describe-toggle-on' ) ) { // Show
    397                         target.parent().addClass( 'open' );
    398                         target.siblings( '.slidetoggle' ).fadeIn( 250, function() {
    399                                 var S = $( window ).scrollTop(),
    400                                         H = $( window ).height(),
    401                                         top = $( this ).offset().top,
    402                                         h = $( this ).height(),
    403                                         b,
    404                                         B;
    405 
    406                                 if ( H && top && h ) {
    407                                         b = top + h;
    408                                         B = S + H;
    409 
    410                                         if ( b > B ) {
    411                                                 if ( b - B < top - S )
    412                                                         window.scrollBy( 0, ( b - B ) + 10 );
    413                                                 else
    414                                                         window.scrollBy( 0, top - S - 40 );
    415                                         }
    416                                 }
    417                         } );
    418 
    419                         e.preventDefault();
    420                 } else if ( target.is( 'a.describe-toggle-off' ) ) { // Hide
    421                         target.siblings( '.slidetoggle' ).fadeOut( 250, function() {
    422                                 target.parent().removeClass( 'open' );
    423                         } );
    424 
    425                         e.preventDefault();
    426                 }
    427         });
    428 
    429         // Attempt to create image sub-sizes when an image was uploaded successfully
    430         // but the server responded with an HTTP 5xx error.
    431         tryAgain = function( up, error ) {
    432                 var file = error.file;
    433                 var times;
    434                 var id;
    435 
    436                 if ( ! error || ! error.responseHeaders ) {
    437                         wpQueueError( pluploadL10n.http_error_image );
    438                         return;
    439                 }
    440 
    441                 id = error.responseHeaders.match( /x-wp-upload-attachment-id:\s*(\d+)/i );
    442 
    443                 if ( id && id[1] ) {
    444                         id = id[1];
    445                 } else {
    446                         wpQueueError( pluploadL10n.http_error_image );
    447                         return;
    448                 }
    449 
    450                 times = tryAgainCount[ file.id ];
    451 
    452                 if ( times && times > 4 ) {
    453                         // The file may have been uploaded and attachment post created,
    454                         // but post-processing and resizing failed...
    455                         // Do a cleanup then tell the user to scale down the image and upload it again.
    456                         $.ajax({
    457                                 type: 'post',
    458                                 url: ajaxurl,
    459                                 dataType: 'json',
    460                                 data: {
    461                                         action: 'media-create-image-subsizes',
    462                                         _wpnonce: wpUploaderInit.multipart_params._wpnonce,
    463                                         attachment_id: id,
    464                                         _wp_upload_failed_cleanup: true,
    465                                 }
    466                         });
    467 
    468                         if ( error.message && ( error.status < 500 || error.status >= 600 ) ) {
    469                                 wpQueueError( error.message );
    470                         } else {
    471                                 wpQueueError( pluploadL10n.http_error_image );
    472                         }
    473 
    474                         return;
    475                 }
    476 
    477                 if ( ! times ) {
    478                         tryAgainCount[ file.id ] = 1;
    479                 } else {
    480                         tryAgainCount[ file.id ] = ++times;
    481                 }
    482 
    483                 // Try to create the missing image sizes.
    484                 $.ajax({
    485                         type: 'post',
    486                         url: ajaxurl,
    487                         dataType: 'json',
    488                         data: {
    489                                 action: 'media-create-image-subsizes',
    490                                 _wpnonce: wpUploaderInit.multipart_params._wpnonce,
    491                                 attachment_id: id,
    492                                 _legacy_support: 'true',
    493                         }
    494                 }).done( function( response ) {
    495                         var message;
    496 
    497                         if ( response.success ) {
    498                                 uploadSuccess( file, response.data.id );
    499                         } else {
    500                                 if ( response.data && response.data.message ) {
    501                                         message = response.data.message;
    502                                 }
    503 
    504                                 wpQueueError( message || pluploadL10n.http_error_image );
    505                         }
    506                 }).fail( function( jqXHR ) {
    507                         // If another HTTP 5xx error, try try again...
    508                         if ( jqXHR.status >= 500 && jqXHR.status < 600 ) {
    509                                 tryAgain( up, error );
    510                                 return;
    511                         }
    512 
    513                         wpQueueError( pluploadL10n.http_error_image );
    514                 });
    515         }
    516 
    517         // init and set the uploader
    518         uploader_init = function() {
    519                 uploader = new plupload.Uploader( wpUploaderInit );
    520 
    521                 $( '#image_resize' ).bind( 'change', function() {
    522                         var arg = $( this ).prop( 'checked' );
    523 
    524                         setResize( arg );
    525 
    526                         if ( arg )
    527                                 setUserSetting( 'upload_resize', '1' );
    528                         else
    529                                 deleteUserSetting( 'upload_resize' );
    530                 });
    531 
    532                 uploader.bind( 'Init', function( up ) {
    533                         var uploaddiv = $( '#plupload-upload-ui' );
    534 
    535                         setResize( getUserSetting( 'upload_resize', false ) );
    536 
    537                         if ( up.features.dragdrop && ! $( document.body ).hasClass( 'mobile' ) ) {
    538                                 uploaddiv.addClass( 'drag-drop' );
    539 
    540                                 $( '#drag-drop-area' ).on( 'dragover.wp-uploader', function() { // dragenter doesn't fire right :(
    541                                         uploaddiv.addClass( 'drag-over' );
    542                                 }).on( 'dragleave.wp-uploader, drop.wp-uploader', function() {
    543                                         uploaddiv.removeClass( 'drag-over' );
    544                                 });
    545                         } else {
    546                                 uploaddiv.removeClass( 'drag-drop' );
    547                                 $( '#drag-drop-area' ).off( '.wp-uploader' );
    548                         }
    549 
    550                         if ( up.runtime === 'html4' ) {
    551                                 $( '.upload-flash-bypass' ).hide();
    552                         }
    553                 });
    554 
    555                 uploader.bind( 'postinit', function( up ) {
    556                         up.refresh();
    557                 });
    558 
    559                 uploader.init();
    560 
    561                 uploader.bind( 'FilesAdded', function( up, files ) {
    562                         $( '#media-upload-error' ).empty();
    563                         uploadStart();
    564 
    565                         plupload.each( files, function( file ) {
    566                                 fileQueued( file );
    567                         });
    568 
    569                         up.refresh();
    570                         up.start();
    571                 });
    572 
    573                 uploader.bind( 'UploadFile', function( up, file ) {
    574                         fileUploading( up, file );
    575                 });
    576 
    577                 uploader.bind( 'UploadProgress', function( up, file ) {
    578                         uploadProgress( up, file );
    579                 });
    580 
    581                 uploader.bind( 'Error', function( up, error ) {
    582                         var isImage = error.file && error.file.type && error.file.type.indexOf( 'image/' ) === 0;
    583                         var status  = error && error.status;
    584 
    585                         // If the file is an image and the error is HTTP 5xx try to create sub-sizes again.
    586                         if ( isImage && status >= 500 && status < 600 ) {
    587                                 tryAgain( up, error );
    588                                 return;
    589                         }
    590 
    591                         uploadError( error.file, error.code, error.message, up );
    592                         up.refresh();
    593                 });
    594 
    595                 uploader.bind( 'FileUploaded', function( up, file, response ) {
    596                         uploadSuccess( file, response.response );
    597                 });
    598 
    599                 uploader.bind( 'UploadComplete', function() {
    600                         uploadComplete();
    601                 });
    602         };
    603 
    604         if ( typeof( wpUploaderInit ) == 'object' ) {
    605                 uploader_init();
    606         }
    607 
    608 });
  • src/js/_enqueues/vendor/plupload/license.txt

    Property changes on: src/js/_enqueues/vendor/plupload/handlers.js
    ___________________________________________________________________
    Deleted: svn:eol-style
    ## -1 +0,0 ##
    -native
    \ No newline at end of property
     
    1                     GNU GENERAL PUBLIC LICENSE
    2                        Version 2, June 1991
    3 
    4  Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
    5  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
    6  Everyone is permitted to copy and distribute verbatim copies
    7  of this license document, but changing it is not allowed.
    8 
    9                             Preamble
    10 
    11   The licenses for most software are designed to take away your
    12 freedom to share and change it.  By contrast, the GNU General Public
    13 License is intended to guarantee your freedom to share and change free
    14 software--to make sure the software is free for all its users.  This
    15 General Public License applies to most of the Free Software
    16 Foundation's software and to any other program whose authors commit to
    17 using it.  (Some other Free Software Foundation software is covered by
    18 the GNU Lesser General Public License instead.)  You can apply it to
    19 your programs, too.
    20 
    21   When we speak of free software, we are referring to freedom, not
    22 price.  Our General Public Licenses are designed to make sure that you
    23 have the freedom to distribute copies of free software (and charge for
    24 this service if you wish), that you receive source code or can get it
    25 if you want it, that you can change the software or use pieces of it
    26 in new free programs; and that you know you can do these things.
    27 
    28   To protect your rights, we need to make restrictions that forbid
    29 anyone to deny you these rights or to ask you to surrender the rights.
    30 These restrictions translate to certain responsibilities for you if you
    31 distribute copies of the software, or if you modify it.
    32 
    33   For example, if you distribute copies of such a program, whether
    34 gratis or for a fee, you must give the recipients all the rights that
    35 you have.  You must make sure that they, too, receive or can get the
    36 source code.  And you must show them these terms so they know their
    37 rights.
    38 
    39   We protect your rights with two steps: (1) copyright the software, and
    40 (2) offer you this license which gives you legal permission to copy,
    41 distribute and/or modify the software.
    42 
    43   Also, for each author's protection and ours, we want to make certain
    44 that everyone understands that there is no warranty for this free
    45 software.  If the software is modified by someone else and passed on, we
    46 want its recipients to know that what they have is not the original, so
    47 that any problems introduced by others will not reflect on the original
    48 authors' reputations.
    49 
    50   Finally, any free program is threatened constantly by software
    51 patents.  We wish to avoid the danger that redistributors of a free
    52 program will individually obtain patent licenses, in effect making the
    53 program proprietary.  To prevent this, we have made it clear that any
    54 patent must be licensed for everyone's free use or not licensed at all.
    55 
    56   The precise terms and conditions for copying, distribution and
    57 modification follow.
    58 
    59                     GNU GENERAL PUBLIC LICENSE
    60    TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
    61 
    62   0. This License applies to any program or other work which contains
    63 a notice placed by the copyright holder saying it may be distributed
    64 under the terms of this General Public License.  The "Program", below,
    65 refers to any such program or work, and a "work based on the Program"
    66 means either the Program or any derivative work under copyright law:
    67 that is to say, a work containing the Program or a portion of it,
    68 either verbatim or with modifications and/or translated into another
    69 language.  (Hereinafter, translation is included without limitation in
    70 the term "modification".)  Each licensee is addressed as "you".
    71 
    72 Activities other than copying, distribution and modification are not
    73 covered by this License; they are outside its scope.  The act of
    74 running the Program is not restricted, and the output from the Program
    75 is covered only if its contents constitute a work based on the
    76 Program (independent of having been made by running the Program).
    77 Whether that is true depends on what the Program does.
    78 
    79   1. You may copy and distribute verbatim copies of the Program's
    80 source code as you receive it, in any medium, provided that you
    81 conspicuously and appropriately publish on each copy an appropriate
    82 copyright notice and disclaimer of warranty; keep intact all the
    83 notices that refer to this License and to the absence of any warranty;
    84 and give any other recipients of the Program a copy of this License
    85 along with the Program.
    86 
    87 You may charge a fee for the physical act of transferring a copy, and
    88 you may at your option offer warranty protection in exchange for a fee.
    89 
    90   2. You may modify your copy or copies of the Program or any portion
    91 of it, thus forming a work based on the Program, and copy and
    92 distribute such modifications or work under the terms of Section 1
    93 above, provided that you also meet all of these conditions:
    94 
    95     a) You must cause the modified files to carry prominent notices
    96     stating that you changed the files and the date of any change.
    97 
    98     b) You must cause any work that you distribute or publish, that in
    99     whole or in part contains or is derived from the Program or any
    100     part thereof, to be licensed as a whole at no charge to all third
    101     parties under the terms of this License.
    102 
    103     c) If the modified program normally reads commands interactively
    104     when run, you must cause it, when started running for such
    105     interactive use in the most ordinary way, to print or display an
    106     announcement including an appropriate copyright notice and a
    107     notice that there is no warranty (or else, saying that you provide
    108     a warranty) and that users may redistribute the program under
    109     these conditions, and telling the user how to view a copy of this
    110     License.  (Exception: if the Program itself is interactive but
    111     does not normally print such an announcement, your work based on
    112     the Program is not required to print an announcement.)
    113 
    114 These requirements apply to the modified work as a whole.  If
    115 identifiable sections of that work are not derived from the Program,
    116 and can be reasonably considered independent and separate works in
    117 themselves, then this License, and its terms, do not apply to those
    118 sections when you distribute them as separate works.  But when you
    119 distribute the same sections as part of a whole which is a work based
    120 on the Program, the distribution of the whole must be on the terms of
    121 this License, whose permissions for other licensees extend to the
    122 entire whole, and thus to each and every part regardless of who wrote it.
    123 
    124 Thus, it is not the intent of this section to claim rights or contest
    125 your rights to work written entirely by you; rather, the intent is to
    126 exercise the right to control the distribution of derivative or
    127 collective works based on the Program.
    128 
    129 In addition, mere aggregation of another work not based on the Program
    130 with the Program (or with a work based on the Program) on a volume of
    131 a storage or distribution medium does not bring the other work under
    132 the scope of this License.
    133 
    134   3. You may copy and distribute the Program (or a work based on it,
    135 under Section 2) in object code or executable form under the terms of
    136 Sections 1 and 2 above provided that you also do one of the following:
    137 
    138     a) Accompany it with the complete corresponding machine-readable
    139     source code, which must be distributed under the terms of Sections
    140     1 and 2 above on a medium customarily used for software interchange; or,
    141 
    142     b) Accompany it with a written offer, valid for at least three
    143     years, to give any third party, for a charge no more than your
    144     cost of physically performing source distribution, a complete
    145     machine-readable copy of the corresponding source code, to be
    146     distributed under the terms of Sections 1 and 2 above on a medium
    147     customarily used for software interchange; or,
    148 
    149     c) Accompany it with the information you received as to the offer
    150     to distribute corresponding source code.  (This alternative is
    151     allowed only for noncommercial distribution and only if you
    152     received the program in object code or executable form with such
    153     an offer, in accord with Subsection b above.)
    154 
    155 The source code for a work means the preferred form of the work for
    156 making modifications to it.  For an executable work, complete source
    157 code means all the source code for all modules it contains, plus any
    158 associated interface definition files, plus the scripts used to
    159 control compilation and installation of the executable.  However, as a
    160 special exception, the source code distributed need not include
    161 anything that is normally distributed (in either source or binary
    162 form) with the major components (compiler, kernel, and so on) of the
    163 operating system on which the executable runs, unless that component
    164 itself accompanies the executable.
    165 
    166 If distribution of executable or object code is made by offering
    167 access to copy from a designated place, then offering equivalent
    168 access to copy the source code from the same place counts as
    169 distribution of the source code, even though third parties are not
    170 compelled to copy the source along with the object code.
    171 
    172   4. You may not copy, modify, sublicense, or distribute the Program
    173 except as expressly provided under this License.  Any attempt
    174 otherwise to copy, modify, sublicense or distribute the Program is
    175 void, and will automatically terminate your rights under this License.
    176 However, parties who have received copies, or rights, from you under
    177 this License will not have their licenses terminated so long as such
    178 parties remain in full compliance.
    179 
    180   5. You are not required to accept this License, since you have not
    181 signed it.  However, nothing else grants you permission to modify or
    182 distribute the Program or its derivative works.  These actions are
    183 prohibited by law if you do not accept this License.  Therefore, by
    184 modifying or distributing the Program (or any work based on the
    185 Program), you indicate your acceptance of this License to do so, and
    186 all its terms and conditions for copying, distributing or modifying
    187 the Program or works based on it.
    188 
    189   6. Each time you redistribute the Program (or any work based on the
    190 Program), the recipient automatically receives a license from the
    191 original licensor to copy, distribute or modify the Program subject to
    192 these terms and conditions.  You may not impose any further
    193 restrictions on the recipients' exercise of the rights granted herein.
    194 You are not responsible for enforcing compliance by third parties to
    195 this License.
    196 
    197   7. If, as a consequence of a court judgment or allegation of patent
    198 infringement or for any other reason (not limited to patent issues),
    199 conditions are imposed on you (whether by court order, agreement or
    200 otherwise) that contradict the conditions of this License, they do not
    201 excuse you from the conditions of this License.  If you cannot
    202 distribute so as to satisfy simultaneously your obligations under this
    203 License and any other pertinent obligations, then as a consequence you
    204 may not distribute the Program at all.  For example, if a patent
    205 license would not permit royalty-free redistribution of the Program by
    206 all those who receive copies directly or indirectly through you, then
    207 the only way you could satisfy both it and this License would be to
    208 refrain entirely from distribution of the Program.
    209 
    210 If any portion of this section is held invalid or unenforceable under
    211 any particular circumstance, the balance of the section is intended to
    212 apply and the section as a whole is intended to apply in other
    213 circumstances.
    214 
    215 It is not the purpose of this section to induce you to infringe any
    216 patents or other property right claims or to contest validity of any
    217 such claims; this section has the sole purpose of protecting the
    218 integrity of the free software distribution system, which is
    219 implemented by public license practices.  Many people have made
    220 generous contributions to the wide range of software distributed
    221 through that system in reliance on consistent application of that
    222 system; it is up to the author/donor to decide if he or she is willing
    223 to distribute software through any other system and a licensee cannot
    224 impose that choice.
    225 
    226 This section is intended to make thoroughly clear what is believed to
    227 be a consequence of the rest of this License.
    228 
    229   8. If the distribution and/or use of the Program is restricted in
    230 certain countries either by patents or by copyrighted interfaces, the
    231 original copyright holder who places the Program under this License
    232 may add an explicit geographical distribution limitation excluding
    233 those countries, so that distribution is permitted only in or among
    234 countries not thus excluded.  In such case, this License incorporates
    235 the limitation as if written in the body of this License.
    236 
    237   9. The Free Software Foundation may publish revised and/or new versions
    238 of the General Public License from time to time.  Such new versions will
    239 be similar in spirit to the present version, but may differ in detail to
    240 address new problems or concerns.
    241 
    242 Each version is given a distinguishing version number.  If the Program
    243 specifies a version number of this License which applies to it and "any
    244 later version", you have the option of following the terms and conditions
    245 either of that version or of any later version published by the Free
    246 Software Foundation.  If the Program does not specify a version number of
    247 this License, you may choose any version ever published by the Free Software
    248 Foundation.
    249 
    250   10. If you wish to incorporate parts of the Program into other free
    251 programs whose distribution conditions are different, write to the author
    252 to ask for permission.  For software which is copyrighted by the Free
    253 Software Foundation, write to the Free Software Foundation; we sometimes
    254 make exceptions for this.  Our decision will be guided by the two goals
    255 of preserving the free status of all derivatives of our free software and
    256 of promoting the sharing and reuse of software generally.
    257 
    258                             NO WARRANTY
    259 
    260   11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
    261 FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
    262 OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
    263 PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
    264 OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    265 MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
    266 TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
    267 PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
    268 REPAIR OR CORRECTION.
    269 
    270   12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
    271 WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
    272 REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
    273 INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
    274 OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
    275 TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
    276 YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
    277 PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
    278 POSSIBILITY OF SUCH DAMAGES.
    279 
    280                      END OF TERMS AND CONDITIONS
    281 
    282             How to Apply These Terms to Your New Programs
    283 
    284   If you develop a new program, and you want it to be of the greatest
    285 possible use to the public, the best way to achieve this is to make it
    286 free software which everyone can redistribute and change under these terms.
    287 
    288   To do so, attach the following notices to the program.  It is safest
    289 to attach them to the start of each source file to most effectively
    290 convey the exclusion of warranty; and each file should have at least
    291 the "copyright" line and a pointer to where the full notice is found.
    292 
    293     <one line to give the program's name and a brief idea of what it does.>
    294     Copyright (C) <year>  <name of author>
    295 
    296     This program is free software; you can redistribute it and/or modify
    297     it under the terms of the GNU General Public License as published by
    298     the Free Software Foundation; either version 2 of the License, or
    299     (at your option) any later version.
    300 
    301     This program is distributed in the hope that it will be useful,
    302     but WITHOUT ANY WARRANTY; without even the implied warranty of
    303     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    304     GNU General Public License for more details.
    305 
    306     You should have received a copy of the GNU General Public License along
    307     with this program; if not, write to the Free Software Foundation, Inc.,
    308     51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
    309 
    310 Also add information on how to contact you by electronic and paper mail.
    311 
    312 If the program is interactive, make it output a short notice like this
    313 when it starts in an interactive mode:
    314 
    315     Gnomovision version 69, Copyright (C) year name of author
    316     Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
    317     This is free software, and you are welcome to redistribute it
    318     under certain conditions; type `show c' for details.
    319 
    320 The hypothetical commands `show w' and `show c' should show the appropriate
    321 parts of the General Public License.  Of course, the commands you use may
    322 be called something other than `show w' and `show c'; they could even be
    323 mouse-clicks or menu items--whatever suits your program.
    324 
    325 You should also get your employer (if you work as a programmer) or your
    326 school, if any, to sign a "copyright disclaimer" for the program, if
    327 necessary.  Here is a sample; alter the names:
    328 
    329   Yoyodyne, Inc., hereby disclaims all copyright interest in the program
    330   `Gnomovision' (which makes passes at compilers) written by James Hacker.
    331 
    332   <signature of Ty Coon>, 1 April 1989
    333   Ty Coon, President of Vice
    334 
    335 This General Public License does not permit incorporating your program into
    336 proprietary programs.  If your program is a subroutine library, you may
    337 consider it more useful to permit linking proprietary applications with the
    338 library.  If this is what you want to do, use the GNU Lesser General
    339 Public License instead of this License.
  • src/js/_enqueues/vendor/plupload/moxie.js

    Property changes on: src/js/_enqueues/vendor/plupload/license.txt
    ___________________________________________________________________
    Deleted: svn:eol-style
    ## -1 +0,0 ##
    -native
    \ No newline at end of property
     
    1 ;var MXI_DEBUG = false;
    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 
    113 define('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 
    508 define("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 
    1213 define("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 
    1278 define("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 
    1473 define('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 
    1656 define('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 
    1815 define('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 
    2119 define('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 
    2722 define('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 
    2898 define('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 
    3227 define('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 
    3407 define('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 
    3585 define('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 
    3670 define('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