Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 1 | espaco | 1 | /** |
| 2 | * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill |
||
| 3 | * v1.2.1 |
||
| 4 | * |
||
| 5 | * Copyright 2013, Moxiecode Systems AB |
||
| 6 | * Released under GPL License. |
||
| 7 | * |
||
| 8 | * License: http://www.plupload.com/license |
||
| 9 | * Contributing: http://www.plupload.com/contributing |
||
| 10 | * |
||
| 11 | * Date: 2014-05-14 |
||
| 12 | */ |
||
| 13 | /** |
||
| 14 | * Compiled inline version. (Library mode) |
||
| 15 | */ |
||
| 16 | |||
| 17 | /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */ |
||
| 18 | /*globals $code */ |
||
| 19 | |||
| 20 | (function(exports, undefined) { |
||
| 21 | "use strict"; |
||
| 22 | |||
| 23 | var modules = {}; |
||
| 24 | |||
| 25 | function require(ids, callback) { |
||
| 26 | var module, defs = []; |
||
| 27 | |||
| 28 | for (var i = 0; i < ids.length; ++i) { |
||
| 29 | module = modules[ids[i]] || resolve(ids[i]); |
||
| 30 | if (!module) { |
||
| 31 | throw 'module definition dependecy not found: ' + ids[i]; |
||
| 32 | } |
||
| 33 | |||
| 34 | defs.push(module); |
||
| 35 | } |
||
| 36 | |||
| 37 | callback.apply(null, defs); |
||
| 38 | } |
||
| 39 | |||
| 40 | function define(id, dependencies, definition) { |
||
| 41 | if (typeof id !== 'string') { |
||
| 42 | throw 'invalid module definition, module id must be defined and be a string'; |
||
| 43 | } |
||
| 44 | |||
| 45 | if (dependencies === undefined) { |
||
| 46 | throw 'invalid module definition, dependencies must be specified'; |
||
| 47 | } |
||
| 48 | |||
| 49 | if (definition === undefined) { |
||
| 50 | throw 'invalid module definition, definition function must be specified'; |
||
| 51 | } |
||
| 52 | |||
| 53 | require(dependencies, function() { |
||
| 54 | modules[id] = definition.apply(null, arguments); |
||
| 55 | }); |
||
| 56 | } |
||
| 57 | |||
| 58 | function defined(id) { |
||
| 59 | return !!modules[id]; |
||
| 60 | } |
||
| 61 | |||
| 62 | function resolve(id) { |
||
| 63 | var target = exports; |
||
| 64 | var fragments = id.split(/[.\/]/); |
||
| 65 | |||
| 66 | for (var fi = 0; fi < fragments.length; ++fi) { |
||
| 67 | if (!target[fragments[fi]]) { |
||
| 68 | return; |
||
| 69 | } |
||
| 70 | |||
| 71 | target = target[fragments[fi]]; |
||
| 72 | } |
||
| 73 | |||
| 74 | return target; |
||
| 75 | } |
||
| 76 | |||
| 77 | function expose(ids) { |
||
| 78 | for (var i = 0; i < ids.length; i++) { |
||
| 79 | var target = exports; |
||
| 80 | var id = ids[i]; |
||
| 81 | var fragments = id.split(/[.\/]/); |
||
| 82 | |||
| 83 | for (var fi = 0; fi < fragments.length - 1; ++fi) { |
||
| 84 | if (target[fragments[fi]] === undefined) { |
||
| 85 | target[fragments[fi]] = {}; |
||
| 86 | } |
||
| 87 | |||
| 88 | target = target[fragments[fi]]; |
||
| 89 | } |
||
| 90 | |||
| 91 | target[fragments[fragments.length - 1]] = modules[id]; |
||
| 92 | } |
||
| 93 | } |
||
| 94 | |||
| 95 | // Included from: src/javascript/core/utils/Basic.js |
||
| 96 | |||
| 97 | /** |
||
| 98 | * Basic.js |
||
| 99 | * |
||
| 100 | * Copyright 2013, Moxiecode Systems AB |
||
| 101 | * Released under GPL License. |
||
| 102 | * |
||
| 103 | * License: http://www.plupload.com/license |
||
| 104 | * Contributing: http://www.plupload.com/contributing |
||
| 105 | */ |
||
| 106 | |||
| 107 | define('moxie/core/utils/Basic', [], function() { |
||
| 108 | /** |
||
| 109 | Gets the true type of the built-in object (better version of typeof). |
||
| 110 | @author Angus Croll (http://javascriptweblog.wordpress.com/) |
||
| 111 | |||
| 112 | @method typeOf |
||
| 113 | @for Utils |
||
| 114 | @static |
||
| 115 | @param {Object} o Object to check. |
||
| 116 | @return {String} Object [[Class]] |
||
| 117 | */ |
||
| 118 | var typeOf = function(o) { |
||
| 119 | var undef; |
||
| 120 | |||
| 121 | if (o === undef) { |
||
| 122 | return 'undefined'; |
||
| 123 | } else if (o === null) { |
||
| 124 | return 'null'; |
||
| 125 | } else if (o.nodeType) { |
||
| 126 | return 'node'; |
||
| 127 | } |
||
| 128 | |||
| 129 | // the snippet below is awesome, however it fails to detect null, undefined and arguments types in IE lte 8 |
||
| 130 | return ({}).toString.call(o).match(/\s([a-z|A-Z]+)/)[1].toLowerCase(); |
||
| 131 | }; |
||
| 132 | |||
| 133 | /** |
||
| 134 | Extends the specified object with another object. |
||
| 135 | |||
| 136 | @method extend |
||
| 137 | @static |
||
| 138 | @param {Object} target Object to extend. |
||
| 139 | @param {Object} [obj]* Multiple objects to extend with. |
||
| 140 | @return {Object} Same as target, the extended object. |
||
| 141 | */ |
||
| 142 | var extend = function(target) { |
||
| 143 | var undef; |
||
| 144 | |||
| 145 | each(arguments, function(arg, i) { |
||
| 146 | if (i > 0) { |
||
| 147 | each(arg, function(value, key) { |
||
| 148 | if (value !== undef) { |
||
| 149 | if (typeOf(target[key]) === typeOf(value) && !!~inArray(typeOf(value), ['array', 'object'])) { |
||
| 150 | extend(target[key], value); |
||
| 151 | } else { |
||
| 152 | target[key] = value; |
||
| 153 | } |
||
| 154 | } |
||
| 155 | }); |
||
| 156 | } |
||
| 157 | }); |
||
| 158 | return target; |
||
| 159 | }; |
||
| 160 | |||
| 161 | /** |
||
| 162 | Executes the callback function for each item in array/object. If you return false in the |
||
| 163 | callback it will break the loop. |
||
| 164 | |||
| 165 | @method each |
||
| 166 | @static |
||
| 167 | @param {Object} obj Object to iterate. |
||
| 168 | @param {function} callback Callback function to execute for each item. |
||
| 169 | */ |
||
| 170 | var each = function(obj, callback) { |
||
| 171 | var length, key, i, undef; |
||
| 172 | |||
| 173 | if (obj) { |
||
| 174 | try { |
||
| 175 | length = obj.length; |
||
| 176 | } catch(ex) { |
||
| 177 | length = undef; |
||
| 178 | } |
||
| 179 | |||
| 180 | if (length === undef) { |
||
| 181 | // Loop object items |
||
| 182 | for (key in obj) { |
||
| 183 | if (obj.hasOwnProperty(key)) { |
||
| 184 | if (callback(obj[key], key) === false) { |
||
| 185 | return; |
||
| 186 | } |
||
| 187 | } |
||
| 188 | } |
||
| 189 | } else { |
||
| 190 | // Loop array items |
||
| 191 | for (i = 0; i < length; i++) { |
||
| 192 | if (callback(obj[i], i) === false) { |
||
| 193 | return; |
||
| 194 | } |
||
| 195 | } |
||
| 196 | } |
||
| 197 | } |
||
| 198 | }; |
||
| 199 | |||
| 200 | /** |
||
| 201 | Checks if object is empty. |
||
| 202 | |||
| 203 | @method isEmptyObj |
||
| 204 | @static |
||
| 205 | @param {Object} o Object to check. |
||
| 206 | @return {Boolean} |
||
| 207 | */ |
||
| 208 | var isEmptyObj = function(obj) { |
||
| 209 | var prop; |
||
| 210 | |||
| 211 | if (!obj || typeOf(obj) !== 'object') { |
||
| 212 | return true; |
||
| 213 | } |
||
| 214 | |||
| 215 | for (prop in obj) { |
||
| 216 | return false; |
||
| 217 | } |
||
| 218 | |||
| 219 | return true; |
||
| 220 | }; |
||
| 221 | |||
| 222 | /** |
||
| 223 | Recieve an array of functions (usually async) to call in sequence, each function |
||
| 224 | receives a callback as first argument that it should call, when it completes. Finally, |
||
| 225 | after everything is complete, main callback is called. Passing truthy value to the |
||
| 226 | callback as a first argument will interrupt the sequence and invoke main callback |
||
| 227 | immediately. |
||
| 228 | |||
| 229 | @method inSeries |
||
| 230 | @static |
||
| 231 | @param {Array} queue Array of functions to call in sequence |
||
| 232 | @param {Function} cb Main callback that is called in the end, or in case of error |
||
| 233 | */ |
||
| 234 | var inSeries = function(queue, cb) { |
||
| 235 | var i = 0, length = queue.length; |
||
| 236 | |||
| 237 | if (typeOf(cb) !== 'function') { |
||
| 238 | cb = function() {}; |
||
| 239 | } |
||
| 240 | |||
| 241 | if (!queue || !queue.length) { |
||
| 242 | cb(); |
||
| 243 | } |
||
| 244 | |||
| 245 | function callNext(i) { |
||
| 246 | if (typeOf(queue[i]) === 'function') { |
||
| 247 | queue[i](function(error) { |
||
| 248 | /*jshint expr:true */ |
||
| 249 | ++i < length && !error ? callNext(i) : cb(error); |
||
| 250 | }); |
||
| 251 | } |
||
| 252 | } |
||
| 253 | callNext(i); |
||
| 254 | }; |
||
| 255 | |||
| 256 | |||
| 257 | /** |
||
| 258 | Recieve an array of functions (usually async) to call in parallel, each function |
||
| 259 | receives a callback as first argument that it should call, when it completes. After |
||
| 260 | everything is complete, main callback is called. Passing truthy value to the |
||
| 261 | callback as a first argument will interrupt the process and invoke main callback |
||
| 262 | immediately. |
||
| 263 | |||
| 264 | @method inParallel |
||
| 265 | @static |
||
| 266 | @param {Array} queue Array of functions to call in sequence |
||
| 267 | @param {Function} cb Main callback that is called in the end, or in case of erro |
||
| 268 | */ |
||
| 269 | var inParallel = function(queue, cb) { |
||
| 270 | var count = 0, num = queue.length, cbArgs = new Array(num); |
||
| 271 | |||
| 272 | each(queue, function(fn, i) { |
||
| 273 | fn(function(error) { |
||
| 274 | if (error) { |
||
| 275 | return cb(error); |
||
| 276 | } |
||
| 277 | |||
| 278 | var args = [].slice.call(arguments); |
||
| 279 | args.shift(); // strip error - undefined or not |
||
| 280 | |||
| 281 | cbArgs[i] = args; |
||
| 282 | count++; |
||
| 283 | |||
| 284 | if (count === num) { |
||
| 285 | cbArgs.unshift(null); |
||
| 286 | cb.apply(this, cbArgs); |
||
| 287 | } |
||
| 288 | }); |
||
| 289 | }); |
||
| 290 | }; |
||
| 291 | |||
| 292 | |||
| 293 | /** |
||
| 294 | Find an element in array and return it's index if present, otherwise return -1. |
||
| 295 | |||
| 296 | @method inArray |
||
| 297 | @static |
||
| 298 | @param {Mixed} needle Element to find |
||
| 299 | @param {Array} array |
||
| 300 | @return {Int} Index of the element, or -1 if not found |
||
| 301 | */ |
||
| 302 | var inArray = function(needle, array) { |
||
| 303 | if (array) { |
||
| 304 | if (Array.prototype.indexOf) { |
||
| 305 | return Array.prototype.indexOf.call(array, needle); |
||
| 306 | } |
||
| 307 | |||
| 308 | for (var i = 0, length = array.length; i < length; i++) { |
||
| 309 | if (array[i] === needle) { |
||
| 310 | return i; |
||
| 311 | } |
||
| 312 | } |
||
| 313 | } |
||
| 314 | return -1; |
||
| 315 | }; |
||
| 316 | |||
| 317 | |||
| 318 | /** |
||
| 319 | Returns elements of first array if they are not present in second. And false - otherwise. |
||
| 320 | |||
| 321 | @private |
||
| 322 | @method arrayDiff |
||
| 323 | @param {Array} needles |
||
| 324 | @param {Array} array |
||
| 325 | @return {Array|Boolean} |
||
| 326 | */ |
||
| 327 | var arrayDiff = function(needles, array) { |
||
| 328 | var diff = []; |
||
| 329 | |||
| 330 | if (typeOf(needles) !== 'array') { |
||
| 331 | needles = [needles]; |
||
| 332 | } |
||
| 333 | |||
| 334 | if (typeOf(array) !== 'array') { |
||
| 335 | array = [array]; |
||
| 336 | } |
||
| 337 | |||
| 338 | for (var i in needles) { |
||
| 339 | if (inArray(needles[i], array) === -1) { |
||
| 340 | diff.push(needles[i]); |
||
| 341 | } |
||
| 342 | } |
||
| 343 | return diff.length ? diff : false; |
||
| 344 | }; |
||
| 345 | |||
| 346 | |||
| 347 | /** |
||
| 348 | Find intersection of two arrays. |
||
| 349 | |||
| 350 | @private |
||
| 351 | @method arrayIntersect |
||
| 352 | @param {Array} array1 |
||
| 353 | @param {Array} array2 |
||
| 354 | @return {Array} Intersection of two arrays or null if there is none |
||
| 355 | */ |
||
| 356 | var arrayIntersect = function(array1, array2) { |
||
| 357 | var result = []; |
||
| 358 | each(array1, function(item) { |
||
| 359 | if (inArray(item, array2) !== -1) { |
||
| 360 | result.push(item); |
||
| 361 | } |
||
| 362 | }); |
||
| 363 | return result.length ? result : null; |
||
| 364 | }; |
||
| 365 | |||
| 366 | |||
| 367 | /** |
||
| 368 | Forces anything into an array. |
||
| 369 | |||
| 370 | @method toArray |
||
| 371 | @static |
||
| 372 | @param {Object} obj Object with length field. |
||
| 373 | @return {Array} Array object containing all items. |
||
| 374 | */ |
||
| 375 | var toArray = function(obj) { |
||
| 376 | var i, arr = []; |
||
| 377 | |||
| 378 | for (i = 0; i < obj.length; i++) { |
||
| 379 | arr[i] = obj[i]; |
||
| 380 | } |
||
| 381 | |||
| 382 | return arr; |
||
| 383 | }; |
||
| 384 | |||
| 385 | |||
| 386 | /** |
||
| 387 | Generates an unique ID. This is 99.99% unique since it takes the current time and 5 random numbers. |
||
| 388 | The only way a user would be able to get the same ID is if the two persons at the same exact milisecond manages |
||
| 389 | to get 5 the same random numbers between 0-65535 it also uses a counter so each call will be guaranteed to be page unique. |
||
| 390 | It's more probable for the earth to be hit with an ansteriod. Y |
||
| 391 | |||
| 392 | @method guid |
||
| 393 | @static |
||
| 394 | @param {String} prefix to prepend (by default 'o' will be prepended). |
||
| 395 | @method guid |
||
| 396 | @return {String} Virtually unique id. |
||
| 397 | */ |
||
| 398 | var guid = (function() { |
||
| 399 | var counter = 0; |
||
| 400 | |||
| 401 | return function(prefix) { |
||
| 402 | var guid = new Date().getTime().toString(32), i; |
||
| 403 | |||
| 404 | for (i = 0; i < 5; i++) { |
||
| 405 | guid += Math.floor(Math.random() * 65535).toString(32); |
||
| 406 | } |
||
| 407 | |||
| 408 | return (prefix || 'o_') + guid + (counter++).toString(32); |
||
| 409 | }; |
||
| 410 | }()); |
||
| 411 | |||
| 412 | |||
| 413 | /** |
||
| 414 | Trims white spaces around the string |
||
| 415 | |||
| 416 | @method trim |
||
| 417 | @static |
||
| 418 | @param {String} str |
||
| 419 | @return {String} |
||
| 420 | */ |
||
| 421 | var trim = function(str) { |
||
| 422 | if (!str) { |
||
| 423 | return str; |
||
| 424 | } |
||
| 425 | return String.prototype.trim ? String.prototype.trim.call(str) : str.toString().replace(/^\s*/, '').replace(/\s*$/, ''); |
||
| 426 | }; |
||
| 427 | |||
| 428 | |||
| 429 | /** |
||
| 430 | Parses the specified size string into a byte value. For example 10kb becomes 10240. |
||
| 431 | |||
| 432 | @method parseSizeStr |
||
| 433 | @static |
||
| 434 | @param {String/Number} size String to parse or number to just pass through. |
||
| 435 | @return {Number} Size in bytes. |
||
| 436 | */ |
||
| 437 | var parseSizeStr = function(size) { |
||
| 438 | if (typeof(size) !== 'string') { |
||
| 439 | return size; |
||
| 440 | } |
||
| 441 | |||
| 442 | var muls = { |
||
| 443 | t: 1099511627776, |
||
| 444 | g: 1073741824, |
||
| 445 | m: 1048576, |
||
| 446 | k: 1024 |
||
| 447 | }, |
||
| 448 | mul; |
||
| 449 | |||
| 450 | size = /^([0-9]+)([mgk]?)$/.exec(size.toLowerCase().replace(/[^0-9mkg]/g, '')); |
||
| 451 | mul = size[2]; |
||
| 452 | size = +size[1]; |
||
| 453 | |||
| 454 | if (muls.hasOwnProperty(mul)) { |
||
| 455 | size *= muls[mul]; |
||
| 456 | } |
||
| 457 | return size; |
||
| 458 | }; |
||
| 459 | |||
| 460 | |||
| 461 | return { |
||
| 462 | guid: guid, |
||
| 463 | typeOf: typeOf, |
||
| 464 | extend: extend, |
||
| 465 | each: each, |
||
| 466 | isEmptyObj: isEmptyObj, |
||
| 467 | inSeries: inSeries, |
||
| 468 | inParallel: inParallel, |
||
| 469 | inArray: inArray, |
||
| 470 | arrayDiff: arrayDiff, |
||
| 471 | arrayIntersect: arrayIntersect, |
||
| 472 | toArray: toArray, |
||
| 473 | trim: trim, |
||
| 474 | parseSizeStr: parseSizeStr |
||
| 475 | }; |
||
| 476 | }); |
||
| 477 | |||
| 478 | // Included from: src/javascript/core/I18n.js |
||
| 479 | |||
| 480 | /** |
||
| 481 | * I18n.js |
||
| 482 | * |
||
| 483 | * Copyright 2013, Moxiecode Systems AB |
||
| 484 | * Released under GPL License. |
||
| 485 | * |
||
| 486 | * License: http://www.plupload.com/license |
||
| 487 | * Contributing: http://www.plupload.com/contributing |
||
| 488 | */ |
||
| 489 | |||
| 490 | define("moxie/core/I18n", [ |
||
| 491 | "moxie/core/utils/Basic" |
||
| 492 | ], function(Basic) { |
||
| 493 | var i18n = {}; |
||
| 494 | |||
| 495 | return { |
||
| 496 | /** |
||
| 497 | * Extends the language pack object with new items. |
||
| 498 | * |
||
| 499 | * @param {Object} pack Language pack items to add. |
||
| 500 | * @return {Object} Extended language pack object. |
||
| 501 | */ |
||
| 502 | addI18n: function(pack) { |
||
| 503 | return Basic.extend(i18n, pack); |
||
| 504 | }, |
||
| 505 | |||
| 506 | /** |
||
| 507 | * Translates the specified string by checking for the english string in the language pack lookup. |
||
| 508 | * |
||
| 509 | * @param {String} str String to look for. |
||
| 510 | * @return {String} Translated string or the input string if it wasn't found. |
||
| 511 | */ |
||
| 512 | translate: function(str) { |
||
| 513 | return i18n[str] || str; |
||
| 514 | }, |
||
| 515 | |||
| 516 | /** |
||
| 517 | * Shortcut for translate function |
||
| 518 | * |
||
| 519 | * @param {String} str String to look for. |
||
| 520 | * @return {String} Translated string or the input string if it wasn't found. |
||
| 521 | */ |
||
| 522 | _: function(str) { |
||
| 523 | return this.translate(str); |
||
| 524 | }, |
||
| 525 | |||
| 526 | /** |
||
| 527 | * Pseudo sprintf implementation - simple way to replace tokens with specified values. |
||
| 528 | * |
||
| 529 | * @param {String} str String with tokens |
||
| 530 | * @return {String} String with replaced tokens |
||
| 531 | */ |
||
| 532 | sprintf: function(str) { |
||
| 533 | var args = [].slice.call(arguments, 1); |
||
| 534 | |||
| 535 | return str.replace(/%[a-z]/g, function() { |
||
| 536 | var value = args.shift(); |
||
| 537 | return Basic.typeOf(value) !== 'undefined' ? value : ''; |
||
| 538 | }); |
||
| 539 | } |
||
| 540 | }; |
||
| 541 | }); |
||
| 542 | |||
| 543 | // Included from: src/javascript/core/utils/Mime.js |
||
| 544 | |||
| 545 | /** |
||
| 546 | * Mime.js |
||
| 547 | * |
||
| 548 | * Copyright 2013, Moxiecode Systems AB |
||
| 549 | * Released under GPL License. |
||
| 550 | * |
||
| 551 | * License: http://www.plupload.com/license |
||
| 552 | * Contributing: http://www.plupload.com/contributing |
||
| 553 | */ |
||
| 554 | |||
| 555 | define("moxie/core/utils/Mime", [ |
||
| 556 | "moxie/core/utils/Basic", |
||
| 557 | "moxie/core/I18n" |
||
| 558 | ], function(Basic, I18n) { |
||
| 559 | |||
| 560 | var mimeData = "" + |
||
| 561 | "application/msword,doc dot," + |
||
| 562 | "application/pdf,pdf," + |
||
| 563 | "application/pgp-signature,pgp," + |
||
| 564 | "application/postscript,ps ai eps," + |
||
| 565 | "application/rtf,rtf," + |
||
| 566 | "application/vnd.ms-excel,xls xlb," + |
||
| 567 | "application/vnd.ms-powerpoint,ppt pps pot," + |
||
| 568 | "application/zip,zip," + |
||
| 569 | "application/x-shockwave-flash,swf swfl," + |
||
| 570 | "application/vnd.openxmlformats-officedocument.wordprocessingml.document,docx," + |
||
| 571 | "application/vnd.openxmlformats-officedocument.wordprocessingml.template,dotx," + |
||
| 572 | "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet,xlsx," + |
||
| 573 | "application/vnd.openxmlformats-officedocument.presentationml.presentation,pptx," + |
||
| 574 | "application/vnd.openxmlformats-officedocument.presentationml.template,potx," + |
||
| 575 | "application/vnd.openxmlformats-officedocument.presentationml.slideshow,ppsx," + |
||
| 576 | "application/x-javascript,js," + |
||
| 577 | "application/json,json," + |
||
| 578 | "audio/mpeg,mp3 mpga mpega mp2," + |
||
| 579 | "audio/x-wav,wav," + |
||
| 580 | "audio/x-m4a,m4a," + |
||
| 581 | "audio/ogg,oga ogg," + |
||
| 582 | "audio/aiff,aiff aif," + |
||
| 583 | "audio/flac,flac," + |
||
| 584 | "audio/aac,aac," + |
||
| 585 | "audio/ac3,ac3," + |
||
| 586 | "audio/x-ms-wma,wma," + |
||
| 587 | "image/bmp,bmp," + |
||
| 588 | "image/gif,gif," + |
||
| 589 | "image/jpeg,jpg jpeg jpe," + |
||
| 590 | "image/photoshop,psd," + |
||
| 591 | "image/png,png," + |
||
| 592 | "image/svg+xml,svg svgz," + |
||
| 593 | "image/tiff,tiff tif," + |
||
| 594 | "text/plain,asc txt text diff log," + |
||
| 595 | "text/html,htm html xhtml," + |
||
| 596 | "text/css,css," + |
||
| 597 | "text/csv,csv," + |
||
| 598 | "text/rtf,rtf," + |
||
| 599 | "video/mpeg,mpeg mpg mpe m2v," + |
||
| 600 | "video/quicktime,qt mov," + |
||
| 601 | "video/mp4,mp4," + |
||
| 602 | "video/x-m4v,m4v," + |
||
| 603 | "video/x-flv,flv," + |
||
| 604 | "video/x-ms-wmv,wmv," + |
||
| 605 | "video/avi,avi," + |
||
| 606 | "video/webm,webm," + |
||
| 607 | "video/3gpp,3gpp 3gp," + |
||
| 608 | "video/3gpp2,3g2," + |
||
| 609 | "video/vnd.rn-realvideo,rv," + |
||
| 610 | "video/ogg,ogv," + |
||
| 611 | "video/x-matroska,mkv," + |
||
| 612 | "application/vnd.oasis.opendocument.formula-template,otf," + |
||
| 613 | "application/octet-stream,exe"; |
||
| 614 | |||
| 615 | |||
| 616 | var Mime = { |
||
| 617 | |||
| 618 | mimes: {}, |
||
| 619 | |||
| 620 | extensions: {}, |
||
| 621 | |||
| 622 | // Parses the default mime types string into a mimes and extensions lookup maps |
||
| 623 | addMimeType: function (mimeData) { |
||
| 624 | var items = mimeData.split(/,/), i, ii, ext; |
||
| 625 | |||
| 626 | for (i = 0; i < items.length; i += 2) { |
||
| 627 | ext = items[i + 1].split(/ /); |
||
| 628 | |||
| 629 | // extension to mime lookup |
||
| 630 | for (ii = 0; ii < ext.length; ii++) { |
||
| 631 | this.mimes[ext[ii]] = items[i]; |
||
| 632 | } |
||
| 633 | // mime to extension lookup |
||
| 634 | this.extensions[items[i]] = ext; |
||
| 635 | } |
||
| 636 | }, |
||
| 637 | |||
| 638 | |||
| 639 | extList2mimes: function (filters, addMissingExtensions) { |
||
| 640 | var self = this, ext, i, ii, type, mimes = []; |
||
| 641 | |||
| 642 | // convert extensions to mime types list |
||
| 643 | for (i = 0; i < filters.length; i++) { |
||
| 644 | ext = filters[i].extensions.split(/\s*,\s*/); |
||
| 645 | |||
| 646 | for (ii = 0; ii < ext.length; ii++) { |
||
| 647 | |||
| 648 | // if there's an asterisk in the list, then accept attribute is not required |
||
| 649 | if (ext[ii] === '*') { |
||
| 650 | return []; |
||
| 651 | } |
||
| 652 | |||
| 653 | type = self.mimes[ext[ii]]; |
||
| 654 | if (!type) { |
||
| 655 | if (addMissingExtensions && /^\w+$/.test(ext[ii])) { |
||
| 656 | mimes.push('.' + ext[ii]); |
||
| 657 | } else { |
||
| 658 | return []; // accept all |
||
| 659 | } |
||
| 660 | } else if (Basic.inArray(type, mimes) === -1) { |
||
| 661 | mimes.push(type); |
||
| 662 | } |
||
| 663 | } |
||
| 664 | } |
||
| 665 | return mimes; |
||
| 666 | }, |
||
| 667 | |||
| 668 | |||
| 669 | mimes2exts: function(mimes) { |
||
| 670 | var self = this, exts = []; |
||
| 671 | |||
| 672 | Basic.each(mimes, function(mime) { |
||
| 673 | if (mime === '*') { |
||
| 674 | exts = []; |
||
| 675 | return false; |
||
| 676 | } |
||
| 677 | |||
| 678 | // check if this thing looks like mime type |
||
| 679 | var m = mime.match(/^(\w+)\/(\*|\w+)$/); |
||
| 680 | if (m) { |
||
| 681 | if (m[2] === '*') { |
||
| 682 | // wildcard mime type detected |
||
| 683 | Basic.each(self.extensions, function(arr, mime) { |
||
| 684 | if ((new RegExp('^' + m[1] + '/')).test(mime)) { |
||
| 685 | [].push.apply(exts, self.extensions[mime]); |
||
| 686 | } |
||
| 687 | }); |
||
| 688 | } else if (self.extensions[mime]) { |
||
| 689 | [].push.apply(exts, self.extensions[mime]); |
||
| 690 | } |
||
| 691 | } |
||
| 692 | }); |
||
| 693 | return exts; |
||
| 694 | }, |
||
| 695 | |||
| 696 | |||
| 697 | mimes2extList: function(mimes) { |
||
| 698 | var accept = [], exts = []; |
||
| 699 | |||
| 700 | if (Basic.typeOf(mimes) === 'string') { |
||
| 701 | mimes = Basic.trim(mimes).split(/\s*,\s*/); |
||
| 702 | } |
||
| 703 | |||
| 704 | exts = this.mimes2exts(mimes); |
||
| 705 | |||
| 706 | accept.push({ |
||
| 707 | title: I18n.translate('Files'), |
||
| 708 | extensions: exts.length ? exts.join(',') : '*' |
||
| 709 | }); |
||
| 710 | |||
| 711 | // save original mimes string |
||
| 712 | accept.mimes = mimes; |
||
| 713 | |||
| 714 | return accept; |
||
| 715 | }, |
||
| 716 | |||
| 717 | |||
| 718 | getFileExtension: function(fileName) { |
||
| 719 | var matches = fileName && fileName.match(/\.([^.]+)$/); |
||
| 720 | if (matches) { |
||
| 721 | return matches[1].toLowerCase(); |
||
| 722 | } |
||
| 723 | return ''; |
||
| 724 | }, |
||
| 725 | |||
| 726 | getFileMime: function(fileName) { |
||
| 727 | return this.mimes[this.getFileExtension(fileName)] || ''; |
||
| 728 | } |
||
| 729 | }; |
||
| 730 | |||
| 731 | Mime.addMimeType(mimeData); |
||
| 732 | |||
| 733 | return Mime; |
||
| 734 | }); |
||
| 735 | |||
| 736 | // Included from: src/javascript/core/utils/Env.js |
||
| 737 | |||
| 738 | /** |
||
| 739 | * Env.js |
||
| 740 | * |
||
| 741 | * Copyright 2013, Moxiecode Systems AB |
||
| 742 | * Released under GPL License. |
||
| 743 | * |
||
| 744 | * License: http://www.plupload.com/license |
||
| 745 | * Contributing: http://www.plupload.com/contributing |
||
| 746 | */ |
||
| 747 | |||
| 748 | define("moxie/core/utils/Env", [ |
||
| 749 | "moxie/core/utils/Basic" |
||
| 750 | ], function(Basic) { |
||
| 751 | |||
| 752 | // UAParser.js v0.6.2 |
||
| 753 | // Lightweight JavaScript-based User-Agent string parser |
||
| 754 | // https://github.com/faisalman/ua-parser-js |
||
| 755 | // |
||
| 756 | // Copyright © 2012-2013 Faisalman <fyzlman@gmail.com> |
||
| 757 | // Dual licensed under GPLv2 & MIT |
||
| 758 | |||
| 759 | var UAParser = (function (undefined) { |
||
| 760 | |||
| 761 | ////////////// |
||
| 762 | // Constants |
||
| 763 | ///////////// |
||
| 764 | |||
| 765 | |||
| 766 | var EMPTY = '', |
||
| 767 | UNKNOWN = '?', |
||
| 768 | FUNC_TYPE = 'function', |
||
| 769 | UNDEF_TYPE = 'undefined', |
||
| 770 | OBJ_TYPE = 'object', |
||
| 771 | MAJOR = 'major', |
||
| 772 | MODEL = 'model', |
||
| 773 | NAME = 'name', |
||
| 774 | TYPE = 'type', |
||
| 775 | VENDOR = 'vendor', |
||
| 776 | VERSION = 'version', |
||
| 777 | ARCHITECTURE= 'architecture', |
||
| 778 | CONSOLE = 'console', |
||
| 779 | MOBILE = 'mobile', |
||
| 780 | TABLET = 'tablet'; |
||
| 781 | |||
| 782 | |||
| 783 | /////////// |
||
| 784 | // Helper |
||
| 785 | ////////// |
||
| 786 | |||
| 787 | |||
| 788 | var util = { |
||
| 789 | has : function (str1, str2) { |
||
| 790 | return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1; |
||
| 791 | }, |
||
| 792 | lowerize : function (str) { |
||
| 793 | return str.toLowerCase(); |
||
| 794 | } |
||
| 795 | }; |
||
| 796 | |||
| 797 | |||
| 798 | /////////////// |
||
| 799 | // Map helper |
||
| 800 | ////////////// |
||
| 801 | |||
| 802 | |||
| 803 | var mapper = { |
||
| 804 | |||
| 805 | rgx : function () { |
||
| 806 | |||
| 807 | // loop through all regexes maps |
||
| 808 | for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) { |
||
| 809 | |||
| 810 | var regex = args[i], // even sequence (0,2,4,..) |
||
| 811 | props = args[i + 1]; // odd sequence (1,3,5,..) |
||
| 812 | |||
| 813 | // construct object barebones |
||
| 814 | if (typeof(result) === UNDEF_TYPE) { |
||
| 815 | result = {}; |
||
| 816 | for (p in props) { |
||
| 817 | q = props[p]; |
||
| 818 | if (typeof(q) === OBJ_TYPE) { |
||
| 819 | result[q[0]] = undefined; |
||
| 820 | } else { |
||
| 821 | result[q] = undefined; |
||
| 822 | } |
||
| 823 | } |
||
| 824 | } |
||
| 825 | |||
| 826 | // try matching uastring with regexes |
||
| 827 | for (j = k = 0; j < regex.length; j++) { |
||
| 828 | matches = regex[j].exec(this.getUA()); |
||
| 829 | if (!!matches) { |
||
| 830 | for (p = 0; p < props.length; p++) { |
||
| 831 | match = matches[++k]; |
||
| 832 | q = props[p]; |
||
| 833 | // check if given property is actually array |
||
| 834 | if (typeof(q) === OBJ_TYPE && q.length > 0) { |
||
| 835 | if (q.length == 2) { |
||
| 836 | if (typeof(q[1]) == FUNC_TYPE) { |
||
| 837 | // assign modified match |
||
| 838 | result[q[0]] = q[1].call(this, match); |
||
| 839 | } else { |
||
| 840 | // assign given value, ignore regex match |
||
| 841 | result[q[0]] = q[1]; |
||
| 842 | } |
||
| 843 | } else if (q.length == 3) { |
||
| 844 | // check whether function or regex |
||
| 845 | if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) { |
||
| 846 | // call function (usually string mapper) |
||
| 847 | result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined; |
||
| 848 | } else { |
||
| 849 | // sanitize match using given regex |
||
| 850 | result[q[0]] = match ? match.replace(q[1], q[2]) : undefined; |
||
| 851 | } |
||
| 852 | } else if (q.length == 4) { |
||
| 853 | result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined; |
||
| 854 | } |
||
| 855 | } else { |
||
| 856 | result[q] = match ? match : undefined; |
||
| 857 | } |
||
| 858 | } |
||
| 859 | break; |
||
| 860 | } |
||
| 861 | } |
||
| 862 | |||
| 863 | if(!!matches) break; // break the loop immediately if match found |
||
| 864 | } |
||
| 865 | return result; |
||
| 866 | }, |
||
| 867 | |||
| 868 | str : function (str, map) { |
||
| 869 | |||
| 870 | for (var i in map) { |
||
| 871 | // check if array |
||
| 872 | if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) { |
||
| 873 | for (var j = 0; j < map[i].length; j++) { |
||
| 874 | if (util.has(map[i][j], str)) { |
||
| 875 | return (i === UNKNOWN) ? undefined : i; |
||
| 876 | } |
||
| 877 | } |
||
| 878 | } else if (util.has(map[i], str)) { |
||
| 879 | return (i === UNKNOWN) ? undefined : i; |
||
| 880 | } |
||
| 881 | } |
||
| 882 | return str; |
||
| 883 | } |
||
| 884 | }; |
||
| 885 | |||
| 886 | |||
| 887 | /////////////// |
||
| 888 | // String map |
||
| 889 | ////////////// |
||
| 890 | |||
| 891 | |||
| 892 | var maps = { |
||
| 893 | |||
| 894 | browser : { |
||
| 895 | oldsafari : { |
||
| 896 | major : { |
||
| 897 | '1' : ['/8', '/1', '/3'], |
||
| 898 | '2' : '/4', |
||
| 899 | '?' : '/' |
||
| 900 | }, |
||
| 901 | version : { |
||
| 902 | '1.0' : '/8', |
||
| 903 | '1.2' : '/1', |
||
| 904 | '1.3' : '/3', |
||
| 905 | '2.0' : '/412', |
||
| 906 | '2.0.2' : '/416', |
||
| 907 | '2.0.3' : '/417', |
||
| 908 | '2.0.4' : '/419', |
||
| 909 | '?' : '/' |
||
| 910 | } |
||
| 911 | } |
||
| 912 | }, |
||
| 913 | |||
| 914 | device : { |
||
| 915 | sprint : { |
||
| 916 | model : { |
||
| 917 | 'Evo Shift 4G' : '7373KT' |
||
| 918 | }, |
||
| 919 | vendor : { |
||
| 920 | 'HTC' : 'APA', |
||
| 921 | 'Sprint' : 'Sprint' |
||
| 922 | } |
||
| 923 | } |
||
| 924 | }, |
||
| 925 | |||
| 926 | os : { |
||
| 927 | windows : { |
||
| 928 | version : { |
||
| 929 | 'ME' : '4.90', |
||
| 930 | 'NT 3.11' : 'NT3.51', |
||
| 931 | 'NT 4.0' : 'NT4.0', |
||
| 932 | '2000' : 'NT 5.0', |
||
| 933 | 'XP' : ['NT 5.1', 'NT 5.2'], |
||
| 934 | 'Vista' : 'NT 6.0', |
||
| 935 | '7' : 'NT 6.1', |
||
| 936 | '8' : 'NT 6.2', |
||
| 937 | '8.1' : 'NT 6.3', |
||
| 938 | 'RT' : 'ARM' |
||
| 939 | } |
||
| 940 | } |
||
| 941 | } |
||
| 942 | }; |
||
| 943 | |||
| 944 | |||
| 945 | ////////////// |
||
| 946 | // Regex map |
||
| 947 | ///////////// |
||
| 948 | |||
| 949 | |||
| 950 | var regexes = { |
||
| 951 | |||
| 952 | browser : [[ |
||
| 953 | |||
| 954 | // Presto based |
||
| 955 | /(opera\smini)\/((\d+)?[\w\.-]+)/i, // Opera Mini |
||
| 956 | /(opera\s[mobiletab]+).+version\/((\d+)?[\w\.-]+)/i, // Opera Mobi/Tablet |
||
| 957 | /(opera).+version\/((\d+)?[\w\.]+)/i, // Opera > 9.80 |
||
| 958 | /(opera)[\/\s]+((\d+)?[\w\.]+)/i // Opera < 9.80 |
||
| 959 | |||
| 960 | ], [NAME, VERSION, MAJOR], [ |
||
| 961 | |||
| 962 | /\s(opr)\/((\d+)?[\w\.]+)/i // Opera Webkit |
||
| 963 | ], [[NAME, 'Opera'], VERSION, MAJOR], [ |
||
| 964 | |||
| 965 | // Mixed |
||
| 966 | /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle |
||
| 967 | /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)*/i, |
||
| 968 | // Lunascape/Maxthon/Netfront/Jasmine/Blazer |
||
| 969 | |||
| 970 | // Trident based |
||
| 971 | /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?((\d+)?[\w\.]*)/i, |
||
| 972 | // Avant/IEMobile/SlimBrowser/Baidu |
||
| 973 | /(?:ms|\()(ie)\s((\d+)?[\w\.]+)/i, // Internet Explorer |
||
| 974 | |||
| 975 | // Webkit/KHTML based |
||
| 976 | /(rekonq)((?:\/)[\w\.]+)*/i, // Rekonq |
||
| 977 | /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron)\/((\d+)?[\w\.-]+)/i |
||
| 978 | // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron |
||
| 979 | ], [NAME, VERSION, MAJOR], [ |
||
| 980 | |||
| 981 | /(trident).+rv[:\s]((\d+)?[\w\.]+).+like\sgecko/i // IE11 |
||
| 982 | ], [[NAME, 'IE'], VERSION, MAJOR], [ |
||
| 983 | |||
| 984 | /(yabrowser)\/((\d+)?[\w\.]+)/i // Yandex |
||
| 985 | ], [[NAME, 'Yandex'], VERSION, MAJOR], [ |
||
| 986 | |||
| 987 | /(comodo_dragon)\/((\d+)?[\w\.]+)/i // Comodo Dragon |
||
| 988 | ], [[NAME, /_/g, ' '], VERSION, MAJOR], [ |
||
| 989 | |||
| 990 | /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?((\d+)?[\w\.]+)/i |
||
| 991 | // Chrome/OmniWeb/Arora/Tizen/Nokia |
||
| 992 | ], [NAME, VERSION, MAJOR], [ |
||
| 993 | |||
| 994 | /(dolfin)\/((\d+)?[\w\.]+)/i // Dolphin |
||
| 995 | ], [[NAME, 'Dolphin'], VERSION, MAJOR], [ |
||
| 996 | |||
| 997 | /((?:android.+)crmo|crios)\/((\d+)?[\w\.]+)/i // Chrome for Android/iOS |
||
| 998 | ], [[NAME, 'Chrome'], VERSION, MAJOR], [ |
||
| 999 | |||
| 1000 | /((?:android.+))version\/((\d+)?[\w\.]+)\smobile\ssafari/i // Android Browser |
||
| 1001 | ], [[NAME, 'Android Browser'], VERSION, MAJOR], [ |
||
| 1002 | |||
| 1003 | /version\/((\d+)?[\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari |
||
| 1004 | ], [VERSION, MAJOR, [NAME, 'Mobile Safari']], [ |
||
| 1005 | |||
| 1006 | /version\/((\d+)?[\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile |
||
| 1007 | ], [VERSION, MAJOR, NAME], [ |
||
| 1008 | |||
| 1009 | /webkit.+?(mobile\s?safari|safari)((\/[\w\.]+))/i // Safari < 3.0 |
||
| 1010 | ], [NAME, [MAJOR, mapper.str, maps.browser.oldsafari.major], [VERSION, mapper.str, maps.browser.oldsafari.version]], [ |
||
| 1011 | |||
| 1012 | /(konqueror)\/((\d+)?[\w\.]+)/i, // Konqueror |
||
| 1013 | /(webkit|khtml)\/((\d+)?[\w\.]+)/i |
||
| 1014 | ], [NAME, VERSION, MAJOR], [ |
||
| 1015 | |||
| 1016 | // Gecko based |
||
| 1017 | /(navigator|netscape)\/((\d+)?[\w\.-]+)/i // Netscape |
||
| 1018 | ], [[NAME, 'Netscape'], VERSION, MAJOR], [ |
||
| 1019 | /(swiftfox)/i, // Swiftfox |
||
| 1020 | /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?((\d+)?[\w\.\+]+)/i, |
||
| 1021 | // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror |
||
| 1022 | /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/((\d+)?[\w\.-]+)/i, |
||
| 1023 | // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix |
||
| 1024 | /(mozilla)\/((\d+)?[\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla |
||
| 1025 | |||
| 1026 | // Other |
||
| 1027 | /(uc\s?browser|polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|qqbrowser)[\/\s]?((\d+)?[\w\.]+)/i, |
||
| 1028 | // UCBrowser/Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/QQBrowser |
||
| 1029 | /(links)\s\(((\d+)?[\w\.]+)/i, // Links |
||
| 1030 | /(gobrowser)\/?((\d+)?[\w\.]+)*/i, // GoBrowser |
||
| 1031 | /(ice\s?browser)\/v?((\d+)?[\w\._]+)/i, // ICE Browser |
||
| 1032 | /(mosaic)[\/\s]((\d+)?[\w\.]+)/i // Mosaic |
||
| 1033 | ], [NAME, VERSION, MAJOR] |
||
| 1034 | ], |
||
| 1035 | |||
| 1036 | engine : [[ |
||
| 1037 | |||
| 1038 | /(presto)\/([\w\.]+)/i, // Presto |
||
| 1039 | /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m |
||
| 1040 | /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links |
||
| 1041 | /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab |
||
| 1042 | ], [NAME, VERSION], [ |
||
| 1043 | |||
| 1044 | /rv\:([\w\.]+).*(gecko)/i // Gecko |
||
| 1045 | ], [VERSION, NAME] |
||
| 1046 | ], |
||
| 1047 | |||
| 1048 | os : [[ |
||
| 1049 | |||
| 1050 | // Windows based |
||
| 1051 | /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT |
||
| 1052 | /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i |
||
| 1053 | ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [ |
||
| 1054 | /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i |
||
| 1055 | ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [ |
||
| 1056 | |||
| 1057 | // Mobile/Embedded OS |
||
| 1058 | /\((bb)(10);/i // BlackBerry 10 |
||
| 1059 | ], [[NAME, 'BlackBerry'], VERSION], [ |
||
| 1060 | /(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry |
||
| 1061 | /(tizen)\/([\w\.]+)/i, // Tizen |
||
| 1062 | /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego)[\/\s-]?([\w\.]+)*/i |
||
| 1063 | // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo |
||
| 1064 | ], [NAME, VERSION], [ |
||
| 1065 | /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian |
||
| 1066 | ], [[NAME, 'Symbian'], VERSION],[ |
||
| 1067 | /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS |
||
| 1068 | ], [[NAME, 'Firefox OS'], VERSION], [ |
||
| 1069 | |||
| 1070 | // Console |
||
| 1071 | /(nintendo|playstation)\s([wids3portablevu]+)/i, // Nintendo/Playstation |
||
| 1072 | |||
| 1073 | // GNU/Linux based |
||
| 1074 | /(mint)[\/\s\(]?(\w+)*/i, // Mint |
||
| 1075 | /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i, |
||
| 1076 | // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware |
||
| 1077 | // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk |
||
| 1078 | /(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux |
||
| 1079 | /(gnu)\s?([\w\.]+)*/i // GNU |
||
| 1080 | ], [NAME, VERSION], [ |
||
| 1081 | |||
| 1082 | /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS |
||
| 1083 | ], [[NAME, 'Chromium OS'], VERSION],[ |
||
| 1084 | |||
| 1085 | // Solaris |
||
| 1086 | /(sunos)\s?([\w\.]+\d)*/i // Solaris |
||
| 1087 | ], [[NAME, 'Solaris'], VERSION], [ |
||
| 1088 | |||
| 1089 | // BSD based |
||
| 1090 | /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly |
||
| 1091 | ], [NAME, VERSION],[ |
||
| 1092 | |||
| 1093 | /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i // iOS |
||
| 1094 | ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [ |
||
| 1095 | |||
| 1096 | /(mac\sos\sx)\s?([\w\s\.]+\w)*/i // Mac OS |
||
| 1097 | ], [NAME, [VERSION, /_/g, '.']], [ |
||
| 1098 | |||
| 1099 | // Other |
||
| 1100 | /(haiku)\s(\w+)/i, // Haiku |
||
| 1101 | /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX |
||
| 1102 | /(macintosh|mac(?=_powerpc)|plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos)/i, |
||
| 1103 | // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS |
||
| 1104 | /(unix)\s?([\w\.]+)*/i // UNIX |
||
| 1105 | ], [NAME, VERSION] |
||
| 1106 | ] |
||
| 1107 | }; |
||
| 1108 | |||
| 1109 | |||
| 1110 | ///////////////// |
||
| 1111 | // Constructor |
||
| 1112 | //////////////// |
||
| 1113 | |||
| 1114 | |||
| 1115 | var UAParser = function (uastring) { |
||
| 1116 | |||
| 1117 | var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY); |
||
| 1118 | |||
| 1119 | this.getBrowser = function () { |
||
| 1120 | return mapper.rgx.apply(this, regexes.browser); |
||
| 1121 | }; |
||
| 1122 | this.getEngine = function () { |
||
| 1123 | return mapper.rgx.apply(this, regexes.engine); |
||
| 1124 | }; |
||
| 1125 | this.getOS = function () { |
||
| 1126 | return mapper.rgx.apply(this, regexes.os); |
||
| 1127 | }; |
||
| 1128 | this.getResult = function() { |
||
| 1129 | return { |
||
| 1130 | ua : this.getUA(), |
||
| 1131 | browser : this.getBrowser(), |
||
| 1132 | engine : this.getEngine(), |
||
| 1133 | os : this.getOS() |
||
| 1134 | }; |
||
| 1135 | }; |
||
| 1136 | this.getUA = function () { |
||
| 1137 | return ua; |
||
| 1138 | }; |
||
| 1139 | this.setUA = function (uastring) { |
||
| 1140 | ua = uastring; |
||
| 1141 | return this; |
||
| 1142 | }; |
||
| 1143 | this.setUA(ua); |
||
| 1144 | }; |
||
| 1145 | |||
| 1146 | return new UAParser().getResult(); |
||
| 1147 | })(); |
||
| 1148 | |||
| 1149 | |||
| 1150 | function version_compare(v1, v2, operator) { |
||
| 1151 | // From: http://phpjs.org/functions |
||
| 1152 | // + original by: Philippe Jausions (http://pear.php.net/user/jausions) |
||
| 1153 | // + original by: Aidan Lister (http://aidanlister.com/) |
||
| 1154 | // + reimplemented by: Kankrelune (http://www.webfaktory.info/) |
||
| 1155 | // + improved by: Brett Zamir (http://brett-zamir.me) |
||
| 1156 | // + improved by: Scott Baker |
||
| 1157 | // + improved by: Theriault |
||
| 1158 | // * example 1: version_compare('8.2.5rc', '8.2.5a'); |
||
| 1159 | // * returns 1: 1 |
||
| 1160 | // * example 2: version_compare('8.2.50', '8.2.52', '<'); |
||
| 1161 | // * returns 2: true |
||
| 1162 | // * example 3: version_compare('5.3.0-dev', '5.3.0'); |
||
| 1163 | // * returns 3: -1 |
||
| 1164 | // * example 4: version_compare('4.1.0.52','4.01.0.51'); |
||
| 1165 | // * returns 4: 1 |
||
| 1166 | |||
| 1167 | // Important: compare must be initialized at 0. |
||
| 1168 | var i = 0, |
||
| 1169 | x = 0, |
||
| 1170 | compare = 0, |
||
| 1171 | // vm maps textual PHP versions to negatives so they're less than 0. |
||
| 1172 | // PHP currently defines these as CASE-SENSITIVE. It is important to |
||
| 1173 | // leave these as negatives so that they can come before numerical versions |
||
| 1174 | // and as if no letters were there to begin with. |
||
| 1175 | // (1alpha is < 1 and < 1.1 but > 1dev1) |
||
| 1176 | // If a non-numerical value can't be mapped to this table, it receives |
||
| 1177 | // -7 as its value. |
||
| 1178 | vm = { |
||
| 1179 | 'dev': -6, |
||
| 1180 | 'alpha': -5, |
||
| 1181 | 'a': -5, |
||
| 1182 | 'beta': -4, |
||
| 1183 | 'b': -4, |
||
| 1184 | 'RC': -3, |
||
| 1185 | 'rc': -3, |
||
| 1186 | '#': -2, |
||
| 1187 | 'p': 1, |
||
| 1188 | 'pl': 1 |
||
| 1189 | }, |
||
| 1190 | // This function will be called to prepare each version argument. |
||
| 1191 | // It replaces every _, -, and + with a dot. |
||
| 1192 | // It surrounds any nonsequence of numbers/dots with dots. |
||
| 1193 | // It replaces sequences of dots with a single dot. |
||
| 1194 | // version_compare('4..0', '4.0') == 0 |
||
| 1195 | // Important: A string of 0 length needs to be converted into a value |
||
| 1196 | // even less than an unexisting value in vm (-7), hence [-8]. |
||
| 1197 | // It's also important to not strip spaces because of this. |
||
| 1198 | // version_compare('', ' ') == 1 |
||
| 1199 | prepVersion = function (v) { |
||
| 1200 | v = ('' + v).replace(/[_\-+]/g, '.'); |
||
| 1201 | v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.'); |
||
| 1202 | return (!v.length ? [-8] : v.split('.')); |
||
| 1203 | }, |
||
| 1204 | // This converts a version component to a number. |
||
| 1205 | // Empty component becomes 0. |
||
| 1206 | // Non-numerical component becomes a negative number. |
||
| 1207 | // Numerical component becomes itself as an integer. |
||
| 1208 | numVersion = function (v) { |
||
| 1209 | return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10)); |
||
| 1210 | }; |
||
| 1211 | |||
| 1212 | v1 = prepVersion(v1); |
||
| 1213 | v2 = prepVersion(v2); |
||
| 1214 | x = Math.max(v1.length, v2.length); |
||
| 1215 | for (i = 0; i < x; i++) { |
||
| 1216 | if (v1[i] == v2[i]) { |
||
| 1217 | continue; |
||
| 1218 | } |
||
| 1219 | v1[i] = numVersion(v1[i]); |
||
| 1220 | v2[i] = numVersion(v2[i]); |
||
| 1221 | if (v1[i] < v2[i]) { |
||
| 1222 | compare = -1; |
||
| 1223 | break; |
||
| 1224 | } else if (v1[i] > v2[i]) { |
||
| 1225 | compare = 1; |
||
| 1226 | break; |
||
| 1227 | } |
||
| 1228 | } |
||
| 1229 | if (!operator) { |
||
| 1230 | return compare; |
||
| 1231 | } |
||
| 1232 | |||
| 1233 | // Important: operator is CASE-SENSITIVE. |
||
| 1234 | // "No operator" seems to be treated as "<." |
||
| 1235 | // Any other values seem to make the function return null. |
||
| 1236 | switch (operator) { |
||
| 1237 | case '>': |
||
| 1238 | case 'gt': |
||
| 1239 | return (compare > 0); |
||
| 1240 | case '>=': |
||
| 1241 | case 'ge': |
||
| 1242 | return (compare >= 0); |
||
| 1243 | case '<=': |
||
| 1244 | case 'le': |
||
| 1245 | return (compare <= 0); |
||
| 1246 | case '==': |
||
| 1247 | case '=': |
||
| 1248 | case 'eq': |
||
| 1249 | return (compare === 0); |
||
| 1250 | case '<>': |
||
| 1251 | case '!=': |
||
| 1252 | case 'ne': |
||
| 1253 | return (compare !== 0); |
||
| 1254 | case '': |
||
| 1255 | case '<': |
||
| 1256 | case 'lt': |
||
| 1257 | return (compare < 0); |
||
| 1258 | default: |
||
| 1259 | return null; |
||
| 1260 | } |
||
| 1261 | } |
||
| 1262 | |||
| 1263 | |||
| 1264 | var can = (function() { |
||
| 1265 | var caps = { |
||
| 1266 | define_property: (function() { |
||
| 1267 | /* // currently too much extra code required, not exactly worth it |
||
| 1268 | try { // as of IE8, getters/setters are supported only on DOM elements |
||
| 1269 | var obj = {}; |
||
| 1270 | if (Object.defineProperty) { |
||
| 1271 | Object.defineProperty(obj, 'prop', { |
||
| 1272 | enumerable: true, |
||
| 1273 | configurable: true |
||
| 1274 | }); |
||
| 1275 | return true; |
||
| 1276 | } |
||
| 1277 | } catch(ex) {} |
||
| 1278 | |||
| 1279 | if (Object.prototype.__defineGetter__ && Object.prototype.__defineSetter__) { |
||
| 1280 | return true; |
||
| 1281 | }*/ |
||
| 1282 | return false; |
||
| 1283 | }()), |
||
| 1284 | |||
| 1285 | create_canvas: (function() { |
||
| 1286 | // On the S60 and BB Storm, getContext exists, but always returns undefined |
||
| 1287 | // so we actually have to call getContext() to verify |
||
| 1288 | // github.com/Modernizr/Modernizr/issues/issue/97/ |
||
| 1289 | var el = document.createElement('canvas'); |
||
| 1290 | return !!(el.getContext && el.getContext('2d')); |
||
| 1291 | }()), |
||
| 1292 | |||
| 1293 | return_response_type: function(responseType) { |
||
| 1294 | try { |
||
| 1295 | if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) { |
||
| 1296 | return true; |
||
| 1297 | } else if (window.XMLHttpRequest) { |
||
| 1298 | var xhr = new XMLHttpRequest(); |
||
| 1299 | xhr.open('get', '/'); // otherwise Gecko throws an exception |
||
| 1300 | if ('responseType' in xhr) { |
||
| 1301 | xhr.responseType = responseType; |
||
| 1302 | // as of 23.0.1271.64, Chrome switched from throwing exception to merely logging it to the console (why? o why?) |
||
| 1303 | if (xhr.responseType !== responseType) { |
||
| 1304 | return false; |
||
| 1305 | } |
||
| 1306 | return true; |
||
| 1307 | } |
||
| 1308 | } |
||
| 1309 | } catch (ex) {} |
||
| 1310 | return false; |
||
| 1311 | }, |
||
| 1312 | |||
| 1313 | // ideas for this heavily come from Modernizr (http://modernizr.com/) |
||
| 1314 | use_data_uri: (function() { |
||
| 1315 | var du = new Image(); |
||
| 1316 | |||
| 1317 | du.onload = function() { |
||
| 1318 | caps.use_data_uri = (du.width === 1 && du.height === 1); |
||
| 1319 | }; |
||
| 1320 | |||
| 1321 | setTimeout(function() { |
||
| 1322 | du.src = "data:image/gif;base64,R0lGODlhAQABAIAAAP8AAAAAACH5BAAAAAAALAAAAAABAAEAAAICRAEAOw=="; |
||
| 1323 | }, 1); |
||
| 1324 | return false; |
||
| 1325 | }()), |
||
| 1326 | |||
| 1327 | use_data_uri_over32kb: function() { // IE8 |
||
| 1328 | return caps.use_data_uri && (Env.browser !== 'IE' || Env.version >= 9); |
||
| 1329 | }, |
||
| 1330 | |||
| 1331 | use_data_uri_of: function(bytes) { |
||
| 1332 | return (caps.use_data_uri && bytes < 33000 || caps.use_data_uri_over32kb()); |
||
| 1333 | }, |
||
| 1334 | |||
| 1335 | use_fileinput: function() { |
||
| 1336 | var el = document.createElement('input'); |
||
| 1337 | el.setAttribute('type', 'file'); |
||
| 1338 | return !el.disabled; |
||
| 1339 | } |
||
| 1340 | }; |
||
| 1341 | |||
| 1342 | return function(cap) { |
||
| 1343 | var args = [].slice.call(arguments); |
||
| 1344 | args.shift(); // shift of cap |
||
| 1345 | return Basic.typeOf(caps[cap]) === 'function' ? caps[cap].apply(this, args) : !!caps[cap]; |
||
| 1346 | }; |
||
| 1347 | }()); |
||
| 1348 | |||
| 1349 | |||
| 1350 | var Env = { |
||
| 1351 | can: can, |
||
| 1352 | |||
| 1353 | browser: UAParser.browser.name, |
||
| 1354 | version: parseFloat(UAParser.browser.major), |
||
| 1355 | os: UAParser.os.name, // everybody intuitively types it in a lowercase for some reason |
||
| 1356 | osVersion: UAParser.os.version, |
||
| 1357 | |||
| 1358 | verComp: version_compare, |
||
| 1359 | |||
| 1360 | swf_url: "../flash/Moxie.swf", |
||
| 1361 | xap_url: "../silverlight/Moxie.xap", |
||
| 1362 | global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent" |
||
| 1363 | }; |
||
| 1364 | |||
| 1365 | // for backward compatibility |
||
| 1366 | // @deprecated Use `Env.os` instead |
||
| 1367 | Env.OS = Env.os; |
||
| 1368 | |||
| 1369 | return Env; |
||
| 1370 | }); |
||
| 1371 | |||
| 1372 | // Included from: src/javascript/core/utils/Dom.js |
||
| 1373 | |||
| 1374 | /** |
||
| 1375 | * Dom.js |
||
| 1376 | * |
||
| 1377 | * Copyright 2013, Moxiecode Systems AB |
||
| 1378 | * Released under GPL License. |
||
| 1379 | * |
||
| 1380 | * License: http://www.plupload.com/license |
||
| 1381 | * Contributing: http://www.plupload.com/contributing |
||
| 1382 | */ |
||
| 1383 | |||
| 1384 | define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) { |
||
| 1385 | |||
| 1386 | /** |
||
| 1387 | Get DOM Element by it's id. |
||
| 1388 | |||
| 1389 | @method get |
||
| 1390 | @for Utils |
||
| 1391 | @param {String} id Identifier of the DOM Element |
||
| 1392 | @return {DOMElement} |
||
| 1393 | */ |
||
| 1394 | var get = function(id) { |
||
| 1395 | if (typeof id !== 'string') { |
||
| 1396 | return id; |
||
| 1397 | } |
||
| 1398 | return document.getElementById(id); |
||
| 1399 | }; |
||
| 1400 | |||
| 1401 | /** |
||
| 1402 | Checks if specified DOM element has specified class. |
||
| 1403 | |||
| 1404 | @method hasClass |
||
| 1405 | @static |
||
| 1406 | @param {Object} obj DOM element like object to add handler to. |
||
| 1407 | @param {String} name Class name |
||
| 1408 | */ |
||
| 1409 | var hasClass = function(obj, name) { |
||
| 1410 | if (!obj.className) { |
||
| 1411 | return false; |
||
| 1412 | } |
||
| 1413 | |||
| 1414 | var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); |
||
| 1415 | return regExp.test(obj.className); |
||
| 1416 | }; |
||
| 1417 | |||
| 1418 | /** |
||
| 1419 | Adds specified className to specified DOM element. |
||
| 1420 | |||
| 1421 | @method addClass |
||
| 1422 | @static |
||
| 1423 | @param {Object} obj DOM element like object to add handler to. |
||
| 1424 | @param {String} name Class name |
||
| 1425 | */ |
||
| 1426 | var addClass = function(obj, name) { |
||
| 1427 | if (!hasClass(obj, name)) { |
||
| 1428 | obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name; |
||
| 1429 | } |
||
| 1430 | }; |
||
| 1431 | |||
| 1432 | /** |
||
| 1433 | Removes specified className from specified DOM element. |
||
| 1434 | |||
| 1435 | @method removeClass |
||
| 1436 | @static |
||
| 1437 | @param {Object} obj DOM element like object to add handler to. |
||
| 1438 | @param {String} name Class name |
||
| 1439 | */ |
||
| 1440 | var removeClass = function(obj, name) { |
||
| 1441 | if (obj.className) { |
||
| 1442 | var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)"); |
||
| 1443 | obj.className = obj.className.replace(regExp, function($0, $1, $2) { |
||
| 1444 | return $1 === ' ' && $2 === ' ' ? ' ' : ''; |
||
| 1445 | }); |
||
| 1446 | } |
||
| 1447 | }; |
||
| 1448 | |||
| 1449 | /** |
||
| 1450 | Returns a given computed style of a DOM element. |
||
| 1451 | |||
| 1452 | @method getStyle |
||
| 1453 | @static |
||
| 1454 | @param {Object} obj DOM element like object. |
||
| 1455 | @param {String} name Style you want to get from the DOM element |
||
| 1456 | */ |
||
| 1457 | var getStyle = function(obj, name) { |
||
| 1458 | if (obj.currentStyle) { |
||
| 1459 | return obj.currentStyle[name]; |
||
| 1460 | } else if (window.getComputedStyle) { |
||
| 1461 | return window.getComputedStyle(obj, null)[name]; |
||
| 1462 | } |
||
| 1463 | }; |
||
| 1464 | |||
| 1465 | |||
| 1466 | /** |
||
| 1467 | Returns the absolute x, y position of an Element. The position will be returned in a object with x, y fields. |
||
| 1468 | |||
| 1469 | @method getPos |
||
| 1470 | @static |
||
| 1471 | @param {Element} node HTML element or element id to get x, y position from. |
||
| 1472 | @param {Element} root Optional root element to stop calculations at. |
||
| 1473 | @return {object} Absolute position of the specified element object with x, y fields. |
||
| 1474 | */ |
||
| 1475 | var getPos = function(node, root) { |
||
| 1476 | var x = 0, y = 0, parent, doc = document, nodeRect, rootRect; |
||
| 1477 | |||
| 1478 | node = node; |
||
| 1479 | root = root || doc.body; |
||
| 1480 | |||
| 1481 | // Returns the x, y cordinate for an element on IE 6 and IE 7 |
||
| 1482 | function getIEPos(node) { |
||
| 1483 | var bodyElm, rect, x = 0, y = 0; |
||
| 1484 | |||
| 1485 | if (node) { |
||
| 1486 | rect = node.getBoundingClientRect(); |
||
| 1487 | bodyElm = doc.compatMode === "CSS1Compat" ? doc.documentElement : doc.body; |
||
| 1488 | x = rect.left + bodyElm.scrollLeft; |
||
| 1489 | y = rect.top + bodyElm.scrollTop; |
||
| 1490 | } |
||
| 1491 | |||
| 1492 | return { |
||
| 1493 | x : x, |
||
| 1494 | y : y |
||
| 1495 | }; |
||
| 1496 | } |
||
| 1497 | |||
| 1498 | // Use getBoundingClientRect on IE 6 and IE 7 but not on IE 8 in standards mode |
||
| 1499 | if (node && node.getBoundingClientRect && Env.browser === 'IE' && (!doc.documentMode || doc.documentMode < 8)) { |
||
| 1500 | nodeRect = getIEPos(node); |
||
| 1501 | rootRect = getIEPos(root); |
||
| 1502 | |||
| 1503 | return { |
||
| 1504 | x : nodeRect.x - rootRect.x, |
||
| 1505 | y : nodeRect.y - rootRect.y |
||
| 1506 | }; |
||
| 1507 | } |
||
| 1508 | |||
| 1509 | parent = node; |
||
| 1510 | while (parent && parent != root && parent.nodeType) { |
||
| 1511 | x += parent.offsetLeft || 0; |
||
| 1512 | y += parent.offsetTop || 0; |
||
| 1513 | parent = parent.offsetParent; |
||
| 1514 | } |
||
| 1515 | |||
| 1516 | parent = node.parentNode; |
||
| 1517 | while (parent && parent != root && parent.nodeType) { |
||
| 1518 | x -= parent.scrollLeft || 0; |
||
| 1519 | y -= parent.scrollTop || 0; |
||
| 1520 | parent = parent.parentNode; |
||
| 1521 | } |
||
| 1522 | |||
| 1523 | return { |
||
| 1524 | x : x, |
||
| 1525 | y : y |
||
| 1526 | }; |
||
| 1527 | }; |
||
| 1528 | |||
| 1529 | /** |
||
| 1530 | Returns the size of the specified node in pixels. |
||
| 1531 | |||
| 1532 | @method getSize |
||
| 1533 | @static |
||
| 1534 | @param {Node} node Node to get the size of. |
||
| 1535 | @return {Object} Object with a w and h property. |
||
| 1536 | */ |
||
| 1537 | var getSize = function(node) { |
||
| 1538 | return { |
||
| 1539 | w : node.offsetWidth || node.clientWidth, |
||
| 1540 | h : node.offsetHeight || node.clientHeight |
||
| 1541 | }; |
||
| 1542 | }; |
||
| 1543 | |||
| 1544 | return { |
||
| 1545 | get: get, |
||
| 1546 | hasClass: hasClass, |
||
| 1547 | addClass: addClass, |
||
| 1548 | removeClass: removeClass, |
||
| 1549 | getStyle: getStyle, |
||
| 1550 | getPos: getPos, |
||
| 1551 | getSize: getSize |
||
| 1552 | }; |
||
| 1553 | }); |
||
| 1554 | |||
| 1555 | // Included from: src/javascript/core/Exceptions.js |
||
| 1556 | |||
| 1557 | /** |
||
| 1558 | * Exceptions.js |
||
| 1559 | * |
||
| 1560 | * Copyright 2013, Moxiecode Systems AB |
||
| 1561 | * Released under GPL License. |
||
| 1562 | * |
||
| 1563 | * License: http://www.plupload.com/license |
||
| 1564 | * Contributing: http://www.plupload.com/contributing |
||
| 1565 | */ |
||
| 1566 | |||
| 1567 | define('moxie/core/Exceptions', [ |
||
| 1568 | 'moxie/core/utils/Basic' |
||
| 1569 | ], function(Basic) { |
||
| 1570 | function _findKey(obj, value) { |
||
| 1571 | var key; |
||
| 1572 | for (key in obj) { |
||
| 1573 | if (obj[key] === value) { |
||
| 1574 | return key; |
||
| 1575 | } |
||
| 1576 | } |
||
| 1577 | return null; |
||
| 1578 | } |
||
| 1579 | |||
| 1580 | return { |
||
| 1581 | RuntimeError: (function() { |
||
| 1582 | var namecodes = { |
||
| 1583 | NOT_INIT_ERR: 1, |
||
| 1584 | NOT_SUPPORTED_ERR: 9, |
||
| 1585 | JS_ERR: 4 |
||
| 1586 | }; |
||
| 1587 | |||
| 1588 | function RuntimeError(code) { |
||
| 1589 | this.code = code; |
||
| 1590 | this.name = _findKey(namecodes, code); |
||
| 1591 | this.message = this.name + ": RuntimeError " + this.code; |
||
| 1592 | } |
||
| 1593 | |||
| 1594 | Basic.extend(RuntimeError, namecodes); |
||
| 1595 | RuntimeError.prototype = Error.prototype; |
||
| 1596 | return RuntimeError; |
||
| 1597 | }()), |
||
| 1598 | |||
| 1599 | OperationNotAllowedException: (function() { |
||
| 1600 | |||
| 1601 | function OperationNotAllowedException(code) { |
||
| 1602 | this.code = code; |
||
| 1603 | this.name = 'OperationNotAllowedException'; |
||
| 1604 | } |
||
| 1605 | |||
| 1606 | Basic.extend(OperationNotAllowedException, { |
||
| 1607 | NOT_ALLOWED_ERR: 1 |
||
| 1608 | }); |
||
| 1609 | |||
| 1610 | OperationNotAllowedException.prototype = Error.prototype; |
||
| 1611 | |||
| 1612 | return OperationNotAllowedException; |
||
| 1613 | }()), |
||
| 1614 | |||
| 1615 | ImageError: (function() { |
||
| 1616 | var namecodes = { |
||
| 1617 | WRONG_FORMAT: 1, |
||
| 1618 | MAX_RESOLUTION_ERR: 2 |
||
| 1619 | }; |
||
| 1620 | |||
| 1621 | function ImageError(code) { |
||
| 1622 | this.code = code; |
||
| 1623 | this.name = _findKey(namecodes, code); |
||
| 1624 | this.message = this.name + ": ImageError " + this.code; |
||
| 1625 | } |
||
| 1626 | |||
| 1627 | Basic.extend(ImageError, namecodes); |
||
| 1628 | ImageError.prototype = Error.prototype; |
||
| 1629 | |||
| 1630 | return ImageError; |
||
| 1631 | }()), |
||
| 1632 | |||
| 1633 | FileException: (function() { |
||
| 1634 | var namecodes = { |
||
| 1635 | NOT_FOUND_ERR: 1, |
||
| 1636 | SECURITY_ERR: 2, |
||
| 1637 | ABORT_ERR: 3, |
||
| 1638 | NOT_READABLE_ERR: 4, |
||
| 1639 | ENCODING_ERR: 5, |
||
| 1640 | NO_MODIFICATION_ALLOWED_ERR: 6, |
||
| 1641 | INVALID_STATE_ERR: 7, |
||
| 1642 | SYNTAX_ERR: 8 |
||
| 1643 | }; |
||
| 1644 | |||
| 1645 | function FileException(code) { |
||
| 1646 | this.code = code; |
||
| 1647 | this.name = _findKey(namecodes, code); |
||
| 1648 | this.message = this.name + ": FileException " + this.code; |
||
| 1649 | } |
||
| 1650 | |||
| 1651 | Basic.extend(FileException, namecodes); |
||
| 1652 | FileException.prototype = Error.prototype; |
||
| 1653 | return FileException; |
||
| 1654 | }()), |
||
| 1655 | |||
| 1656 | DOMException: (function() { |
||
| 1657 | var namecodes = { |
||
| 1658 | INDEX_SIZE_ERR: 1, |
||
| 1659 | DOMSTRING_SIZE_ERR: 2, |
||
| 1660 | HIERARCHY_REQUEST_ERR: 3, |
||
| 1661 | WRONG_DOCUMENT_ERR: 4, |
||
| 1662 | INVALID_CHARACTER_ERR: 5, |
||
| 1663 | NO_DATA_ALLOWED_ERR: 6, |
||
| 1664 | NO_MODIFICATION_ALLOWED_ERR: 7, |
||
| 1665 | NOT_FOUND_ERR: 8, |
||
| 1666 | NOT_SUPPORTED_ERR: 9, |
||
| 1667 | INUSE_ATTRIBUTE_ERR: 10, |
||
| 1668 | INVALID_STATE_ERR: 11, |
||
| 1669 | SYNTAX_ERR: 12, |
||
| 1670 | INVALID_MODIFICATION_ERR: 13, |
||
| 1671 | NAMESPACE_ERR: 14, |
||
| 1672 | INVALID_ACCESS_ERR: 15, |
||
| 1673 | VALIDATION_ERR: 16, |
||
| 1674 | TYPE_MISMATCH_ERR: 17, |
||
| 1675 | SECURITY_ERR: 18, |
||
| 1676 | NETWORK_ERR: 19, |
||
| 1677 | ABORT_ERR: 20, |
||
| 1678 | URL_MISMATCH_ERR: 21, |
||
| 1679 | QUOTA_EXCEEDED_ERR: 22, |
||
| 1680 | TIMEOUT_ERR: 23, |
||
| 1681 | INVALID_NODE_TYPE_ERR: 24, |
||
| 1682 | DATA_CLONE_ERR: 25 |
||
| 1683 | }; |
||
| 1684 | |||
| 1685 | function DOMException(code) { |
||
| 1686 | this.code = code; |
||
| 1687 | this.name = _findKey(namecodes, code); |
||
| 1688 | this.message = this.name + ": DOMException " + this.code; |
||
| 1689 | } |
||
| 1690 | |||
| 1691 | Basic.extend(DOMException, namecodes); |
||
| 1692 | DOMException.prototype = Error.prototype; |
||
| 1693 | return DOMException; |
||
| 1694 | }()), |
||
| 1695 | |||
| 1696 | EventException: (function() { |
||
| 1697 | function EventException(code) { |
||
| 1698 | this.code = code; |
||
| 1699 | this.name = 'EventException'; |
||
| 1700 | } |
||
| 1701 | |||
| 1702 | Basic.extend(EventException, { |
||
| 1703 | UNSPECIFIED_EVENT_TYPE_ERR: 0 |
||
| 1704 | }); |
||
| 1705 | |||
| 1706 | EventException.prototype = Error.prototype; |
||
| 1707 | |||
| 1708 | return EventException; |
||
| 1709 | }()) |
||
| 1710 | }; |
||
| 1711 | }); |
||
| 1712 | |||
| 1713 | // Included from: src/javascript/core/EventTarget.js |
||
| 1714 | |||
| 1715 | /** |
||
| 1716 | * EventTarget.js |
||
| 1717 | * |
||
| 1718 | * Copyright 2013, Moxiecode Systems AB |
||
| 1719 | * Released under GPL License. |
||
| 1720 | * |
||
| 1721 | * License: http://www.plupload.com/license |
||
| 1722 | * Contributing: http://www.plupload.com/contributing |
||
| 1723 | */ |
||
| 1724 | |||
| 1725 | define('moxie/core/EventTarget', [ |
||
| 1726 | 'moxie/core/Exceptions', |
||
| 1727 | 'moxie/core/utils/Basic' |
||
| 1728 | ], function(x, Basic) { |
||
| 1729 | /** |
||
| 1730 | Parent object for all event dispatching components and objects |
||
| 1731 | |||
| 1732 | @class EventTarget |
||
| 1733 | @constructor EventTarget |
||
| 1734 | */ |
||
| 1735 | function EventTarget() { |
||
| 1736 | // hash of event listeners by object uid |
||
| 1737 | var eventpool = {}; |
||
| 1738 | |||
| 1739 | Basic.extend(this, { |
||
| 1740 | |||
| 1741 | /** |
||
| 1742 | Unique id of the event dispatcher, usually overriden by children |
||
| 1743 | |||
| 1744 | @property uid |
||
| 1745 | @type String |
||
| 1746 | */ |
||
| 1747 | uid: null, |
||
| 1748 | |||
| 1749 | /** |
||
| 1750 | Can be called from within a child in order to acquire uniqie id in automated manner |
||
| 1751 | |||
| 1752 | @method init |
||
| 1753 | */ |
||
| 1754 | init: function() { |
||
| 1755 | if (!this.uid) { |
||
| 1756 | this.uid = Basic.guid('uid_'); |
||
| 1757 | } |
||
| 1758 | }, |
||
| 1759 | |||
| 1760 | /** |
||
| 1761 | Register a handler to a specific event dispatched by the object |
||
| 1762 | |||
| 1763 | @method addEventListener |
||
| 1764 | @param {String} type Type or basically a name of the event to subscribe to |
||
| 1765 | @param {Function} fn Callback function that will be called when event happens |
||
| 1766 | @param {Number} [priority=0] Priority of the event handler - handlers with higher priorities will be called first |
||
| 1767 | @param {Object} [scope=this] A scope to invoke event handler in |
||
| 1768 | */ |
||
| 1769 | addEventListener: function(type, fn, priority, scope) { |
||
| 1770 | var self = this, list; |
||
| 1771 | |||
| 1772 | type = Basic.trim(type); |
||
| 1773 | |||
| 1774 | if (/\s/.test(type)) { |
||
| 1775 | // multiple event types were passed for one handler |
||
| 1776 | Basic.each(type.split(/\s+/), function(type) { |
||
| 1777 | self.addEventListener(type, fn, priority, scope); |
||
| 1778 | }); |
||
| 1779 | return; |
||
| 1780 | } |
||
| 1781 | |||
| 1782 | type = type.toLowerCase(); |
||
| 1783 | priority = parseInt(priority, 10) || 0; |
||
| 1784 | |||
| 1785 | list = eventpool[this.uid] && eventpool[this.uid][type] || []; |
||
| 1786 | list.push({fn : fn, priority : priority, scope : scope || this}); |
||
| 1787 | |||
| 1788 | if (!eventpool[this.uid]) { |
||
| 1789 | eventpool[this.uid] = {}; |
||
| 1790 | } |
||
| 1791 | eventpool[this.uid][type] = list; |
||
| 1792 | }, |
||
| 1793 | |||
| 1794 | /** |
||
| 1795 | Check if any handlers were registered to the specified event |
||
| 1796 | |||
| 1797 | @method hasEventListener |
||
| 1798 | @param {String} type Type or basically a name of the event to check |
||
| 1799 | @return {Mixed} Returns a handler if it was found and false, if - not |
||
| 1800 | */ |
||
| 1801 | hasEventListener: function(type) { |
||
| 1802 | return type ? !!(eventpool[this.uid] && eventpool[this.uid][type]) : !!eventpool[this.uid]; |
||
| 1803 | }, |
||
| 1804 | |||
| 1805 | /** |
||
| 1806 | Unregister the handler from the event, or if former was not specified - unregister all handlers |
||
| 1807 | |||
| 1808 | @method removeEventListener |
||
| 1809 | @param {String} type Type or basically a name of the event |
||
| 1810 | @param {Function} [fn] Handler to unregister |
||
| 1811 | */ |
||
| 1812 | removeEventListener: function(type, fn) { |
||
| 1813 | type = type.toLowerCase(); |
||
| 1814 | |||
| 1815 | var list = eventpool[this.uid] && eventpool[this.uid][type], i; |
||
| 1816 | |||
| 1817 | if (list) { |
||
| 1818 | if (fn) { |
||
| 1819 | for (i = list.length - 1; i >= 0; i--) { |
||
| 1820 | if (list[i].fn === fn) { |
||
| 1821 | list.splice(i, 1); |
||
| 1822 | break; |
||
| 1823 | } |
||
| 1824 | } |
||
| 1825 | } else { |
||
| 1826 | list = []; |
||
| 1827 | } |
||
| 1828 | |||
| 1829 | // delete event list if it has become empty |
||
| 1830 | if (!list.length) { |
||
| 1831 | delete eventpool[this.uid][type]; |
||
| 1832 | |||
| 1833 | // and object specific entry in a hash if it has no more listeners attached |
||
| 1834 | if (Basic.isEmptyObj(eventpool[this.uid])) { |
||
| 1835 | delete eventpool[this.uid]; |
||
| 1836 | } |
||
| 1837 | } |
||
| 1838 | } |
||
| 1839 | }, |
||
| 1840 | |||
| 1841 | /** |
||
| 1842 | Remove all event handlers from the object |
||
| 1843 | |||
| 1844 | @method removeAllEventListeners |
||
| 1845 | */ |
||
| 1846 | removeAllEventListeners: function() { |
||
| 1847 | if (eventpool[this.uid]) { |
||
| 1848 | delete eventpool[this.uid]; |
||
| 1849 | } |
||
| 1850 | }, |
||
| 1851 | |||
| 1852 | /** |
||
| 1853 | Dispatch the event |
||
| 1854 | |||
| 1855 | @method dispatchEvent |
||
| 1856 | @param {String/Object} Type of event or event object to dispatch |
||
| 1857 | @param {Mixed} [...] Variable number of arguments to be passed to a handlers |
||
| 1858 | @return {Boolean} true by default and false if any handler returned false |
||
| 1859 | */ |
||
| 1860 | dispatchEvent: function(type) { |
||
| 1861 | var uid, list, args, tmpEvt, evt = {}, result = true, undef; |
||
| 1862 | |||
| 1863 | if (Basic.typeOf(type) !== 'string') { |
||
| 1864 | // we can't use original object directly (because of Silverlight) |
||
| 1865 | tmpEvt = type; |
||
| 1866 | |||
| 1867 | if (Basic.typeOf(tmpEvt.type) === 'string') { |
||
| 1868 | type = tmpEvt.type; |
||
| 1869 | |||
| 1870 | if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event |
||
| 1871 | evt.total = tmpEvt.total; |
||
| 1872 | evt.loaded = tmpEvt.loaded; |
||
| 1873 | } |
||
| 1874 | evt.async = tmpEvt.async || false; |
||
| 1875 | } else { |
||
| 1876 | throw new x.EventException(x.EventException.UNSPECIFIED_EVENT_TYPE_ERR); |
||
| 1877 | } |
||
| 1878 | } |
||
| 1879 | |||
| 1880 | // check if event is meant to be dispatched on an object having specific uid |
||
| 1881 | if (type.indexOf('::') !== -1) { |
||
| 1882 | (function(arr) { |
||
| 1883 | uid = arr[0]; |
||
| 1884 | type = arr[1]; |
||
| 1885 | }(type.split('::'))); |
||
| 1886 | } else { |
||
| 1887 | uid = this.uid; |
||
| 1888 | } |
||
| 1889 | |||
| 1890 | type = type.toLowerCase(); |
||
| 1891 | |||
| 1892 | list = eventpool[uid] && eventpool[uid][type]; |
||
| 1893 | |||
| 1894 | if (list) { |
||
| 1895 | // sort event list by prority |
||
| 1896 | list.sort(function(a, b) { return b.priority - a.priority; }); |
||
| 1897 | |||
| 1898 | args = [].slice.call(arguments); |
||
| 1899 | |||
| 1900 | // first argument will be pseudo-event object |
||
| 1901 | args.shift(); |
||
| 1902 | evt.type = type; |
||
| 1903 | args.unshift(evt); |
||
| 1904 | |||
| 1905 | // Dispatch event to all listeners |
||
| 1906 | var queue = []; |
||
| 1907 | Basic.each(list, function(handler) { |
||
| 1908 | // explicitly set the target, otherwise events fired from shims do not get it |
||
| 1909 | args[0].target = handler.scope; |
||
| 1910 | // if event is marked as async, detach the handler |
||
| 1911 | if (evt.async) { |
||
| 1912 | queue.push(function(cb) { |
||
| 1913 | setTimeout(function() { |
||
| 1914 | cb(handler.fn.apply(handler.scope, args) === false); |
||
| 1915 | }, 1); |
||
| 1916 | }); |
||
| 1917 | } else { |
||
| 1918 | queue.push(function(cb) { |
||
| 1919 | cb(handler.fn.apply(handler.scope, args) === false); // if handler returns false stop propagation |
||
| 1920 | }); |
||
| 1921 | } |
||
| 1922 | }); |
||
| 1923 | if (queue.length) { |
||
| 1924 | Basic.inSeries(queue, function(err) { |
||
| 1925 | result = !err; |
||
| 1926 | }); |
||
| 1927 | } |
||
| 1928 | } |
||
| 1929 | return result; |
||
| 1930 | }, |
||
| 1931 | |||
| 1932 | /** |
||
| 1933 | Alias for addEventListener |
||
| 1934 | |||
| 1935 | @method bind |
||
| 1936 | @protected |
||
| 1937 | */ |
||
| 1938 | bind: function() { |
||
| 1939 | this.addEventListener.apply(this, arguments); |
||
| 1940 | }, |
||
| 1941 | |||
| 1942 | /** |
||
| 1943 | Alias for removeEventListener |
||
| 1944 | |||
| 1945 | @method unbind |
||
| 1946 | @protected |
||
| 1947 | */ |
||
| 1948 | unbind: function() { |
||
| 1949 | this.removeEventListener.apply(this, arguments); |
||
| 1950 | }, |
||
| 1951 | |||
| 1952 | /** |
||
| 1953 | Alias for removeAllEventListeners |
||
| 1954 | |||
| 1955 | @method unbindAll |
||
| 1956 | @protected |
||
| 1957 | */ |
||
| 1958 | unbindAll: function() { |
||
| 1959 | this.removeAllEventListeners.apply(this, arguments); |
||
| 1960 | }, |
||
| 1961 | |||
| 1962 | /** |
||
| 1963 | Alias for dispatchEvent |
||
| 1964 | |||
| 1965 | @method trigger |
||
| 1966 | @protected |
||
| 1967 | */ |
||
| 1968 | trigger: function() { |
||
| 1969 | return this.dispatchEvent.apply(this, arguments); |
||
| 1970 | }, |
||
| 1971 | |||
| 1972 | |||
| 1973 | /** |
||
| 1974 | Converts properties of on[event] type to corresponding event handlers, |
||
| 1975 | is used to avoid extra hassle around the process of calling them back |
||
| 1976 | |||
| 1977 | @method convertEventPropsToHandlers |
||
| 1978 | @private |
||
| 1979 | */ |
||
| 1980 | convertEventPropsToHandlers: function(handlers) { |
||
| 1981 | var h; |
||
| 1982 | |||
| 1983 | if (Basic.typeOf(handlers) !== 'array') { |
||
| 1984 | handlers = [handlers]; |
||
| 1985 | } |
||
| 1986 | |||
| 1987 | for (var i = 0; i < handlers.length; i++) { |
||
| 1988 | h = 'on' + handlers[i]; |
||
| 1989 | |||
| 1990 | if (Basic.typeOf(this[h]) === 'function') { |
||
| 1991 | this.addEventListener(handlers[i], this[h]); |
||
| 1992 | } else if (Basic.typeOf(this[h]) === 'undefined') { |
||
| 1993 | this[h] = null; // object must have defined event properties, even if it doesn't make use of them |
||
| 1994 | } |
||
| 1995 | } |
||
| 1996 | } |
||
| 1997 | |||
| 1998 | }); |
||
| 1999 | } |
||
| 2000 | |||
| 2001 | EventTarget.instance = new EventTarget(); |
||
| 2002 | |||
| 2003 | return EventTarget; |
||
| 2004 | }); |
||
| 2005 | |||
| 2006 | // Included from: src/javascript/core/utils/Encode.js |
||
| 2007 | |||
| 2008 | /** |
||
| 2009 | * Encode.js |
||
| 2010 | * |
||
| 2011 | * Copyright 2013, Moxiecode Systems AB |
||
| 2012 | * Released under GPL License. |
||
| 2013 | * |
||
| 2014 | * License: http://www.plupload.com/license |
||
| 2015 | * Contributing: http://www.plupload.com/contributing |
||
| 2016 | */ |
||
| 2017 | |||
| 2018 | define('moxie/core/utils/Encode', [], function() { |
||
| 2019 | |||
| 2020 | /** |
||
| 2021 | Encode string with UTF-8 |
||
| 2022 | |||
| 2023 | @method utf8_encode |
||
| 2024 | @for Utils |
||
| 2025 | @static |
||
| 2026 | @param {String} str String to encode |
||
| 2027 | @return {String} UTF-8 encoded string |
||
| 2028 | */ |
||
| 2029 | var utf8_encode = function(str) { |
||
| 2030 | return unescape(encodeURIComponent(str)); |
||
| 2031 | }; |
||
| 2032 | |||
| 2033 | /** |
||
| 2034 | Decode UTF-8 encoded string |
||
| 2035 | |||
| 2036 | @method utf8_decode |
||
| 2037 | @static |
||
| 2038 | @param {String} str String to decode |
||
| 2039 | @return {String} Decoded string |
||
| 2040 | */ |
||
| 2041 | var utf8_decode = function(str_data) { |
||
| 2042 | return decodeURIComponent(escape(str_data)); |
||
| 2043 | }; |
||
| 2044 | |||
| 2045 | /** |
||
| 2046 | Decode Base64 encoded string (uses browser's default method if available), |
||
| 2047 | from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_decode.js |
||
| 2048 | |||
| 2049 | @method atob |
||
| 2050 | @static |
||
| 2051 | @param {String} data String to decode |
||
| 2052 | @return {String} Decoded string |
||
| 2053 | */ |
||
| 2054 | var atob = function(data, utf8) { |
||
| 2055 | if (typeof(window.atob) === 'function') { |
||
| 2056 | return utf8 ? utf8_decode(window.atob(data)) : window.atob(data); |
||
| 2057 | } |
||
| 2058 | |||
| 2059 | // http://kevin.vanzonneveld.net |
||
| 2060 | // + original by: Tyler Akins (http://rumkin.com) |
||
| 2061 | // + improved by: Thunder.m |
||
| 2062 | // + input by: Aman Gupta |
||
| 2063 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
||
| 2064 | // + bugfixed by: Onno Marsman |
||
| 2065 | // + bugfixed by: Pellentesque Malesuada |
||
| 2066 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
||
| 2067 | // + input by: Brett Zamir (http://brett-zamir.me) |
||
| 2068 | // + bugfixed by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
||
| 2069 | // * example 1: base64_decode('S2V2aW4gdmFuIFpvbm5ldmVsZA=='); |
||
| 2070 | // * returns 1: 'Kevin van Zonneveld' |
||
| 2071 | // mozilla has this native |
||
| 2072 | // - but breaks in 2.0.0.12! |
||
| 2073 | //if (typeof this.window.atob == 'function') { |
||
| 2074 | // return atob(data); |
||
| 2075 | //} |
||
| 2076 | var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; |
||
| 2077 | var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, |
||
| 2078 | ac = 0, |
||
| 2079 | dec = "", |
||
| 2080 | tmp_arr = []; |
||
| 2081 | |||
| 2082 | if (!data) { |
||
| 2083 | return data; |
||
| 2084 | } |
||
| 2085 | |||
| 2086 | data += ''; |
||
| 2087 | |||
| 2088 | do { // unpack four hexets into three octets using index points in b64 |
||
| 2089 | h1 = b64.indexOf(data.charAt(i++)); |
||
| 2090 | h2 = b64.indexOf(data.charAt(i++)); |
||
| 2091 | h3 = b64.indexOf(data.charAt(i++)); |
||
| 2092 | h4 = b64.indexOf(data.charAt(i++)); |
||
| 2093 | |||
| 2094 | bits = h1 << 18 | h2 << 12 | h3 << 6 | h4; |
||
| 2095 | |||
| 2096 | o1 = bits >> 16 & 0xff; |
||
| 2097 | o2 = bits >> 8 & 0xff; |
||
| 2098 | o3 = bits & 0xff; |
||
| 2099 | |||
| 2100 | if (h3 == 64) { |
||
| 2101 | tmp_arr[ac++] = String.fromCharCode(o1); |
||
| 2102 | } else if (h4 == 64) { |
||
| 2103 | tmp_arr[ac++] = String.fromCharCode(o1, o2); |
||
| 2104 | } else { |
||
| 2105 | tmp_arr[ac++] = String.fromCharCode(o1, o2, o3); |
||
| 2106 | } |
||
| 2107 | } while (i < data.length); |
||
| 2108 | |||
| 2109 | dec = tmp_arr.join(''); |
||
| 2110 | |||
| 2111 | return utf8 ? utf8_decode(dec) : dec; |
||
| 2112 | }; |
||
| 2113 | |||
| 2114 | /** |
||
| 2115 | Base64 encode string (uses browser's default method if available), |
||
| 2116 | from: https://raw.github.com/kvz/phpjs/master/functions/url/base64_encode.js |
||
| 2117 | |||
| 2118 | @method btoa |
||
| 2119 | @static |
||
| 2120 | @param {String} data String to encode |
||
| 2121 | @return {String} Base64 encoded string |
||
| 2122 | */ |
||
| 2123 | var btoa = function(data, utf8) { |
||
| 2124 | if (utf8) { |
||
| 2125 | utf8_encode(data); |
||
| 2126 | } |
||
| 2127 | |||
| 2128 | if (typeof(window.btoa) === 'function') { |
||
| 2129 | return window.btoa(data); |
||
| 2130 | } |
||
| 2131 | |||
| 2132 | // http://kevin.vanzonneveld.net |
||
| 2133 | // + original by: Tyler Akins (http://rumkin.com) |
||
| 2134 | // + improved by: Bayron Guevara |
||
| 2135 | // + improved by: Thunder.m |
||
| 2136 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
||
| 2137 | // + bugfixed by: Pellentesque Malesuada |
||
| 2138 | // + improved by: Kevin van Zonneveld (http://kevin.vanzonneveld.net) |
||
| 2139 | // + improved by: Rafał Kukawski (http://kukawski.pl) |
||
| 2140 | // * example 1: base64_encode('Kevin van Zonneveld'); |
||
| 2141 | // * returns 1: 'S2V2aW4gdmFuIFpvbm5ldmVsZA==' |
||
| 2142 | // mozilla has this native |
||
| 2143 | // - but breaks in 2.0.0.12! |
||
| 2144 | var b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="; |
||
| 2145 | var o1, o2, o3, h1, h2, h3, h4, bits, i = 0, |
||
| 2146 | ac = 0, |
||
| 2147 | enc = "", |
||
| 2148 | tmp_arr = []; |
||
| 2149 | |||
| 2150 | if (!data) { |
||
| 2151 | return data; |
||
| 2152 | } |
||
| 2153 | |||
| 2154 | do { // pack three octets into four hexets |
||
| 2155 | o1 = data.charCodeAt(i++); |
||
| 2156 | o2 = data.charCodeAt(i++); |
||
| 2157 | o3 = data.charCodeAt(i++); |
||
| 2158 | |||
| 2159 | bits = o1 << 16 | o2 << 8 | o3; |
||
| 2160 | |||
| 2161 | h1 = bits >> 18 & 0x3f; |
||
| 2162 | h2 = bits >> 12 & 0x3f; |
||
| 2163 | h3 = bits >> 6 & 0x3f; |
||
| 2164 | h4 = bits & 0x3f; |
||
| 2165 | |||
| 2166 | // use hexets to index into b64, and append result to encoded string |
||
| 2167 | tmp_arr[ac++] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4); |
||
| 2168 | } while (i < data.length); |
||
| 2169 | |||
| 2170 | enc = tmp_arr.join(''); |
||
| 2171 | |||
| 2172 | var r = data.length % 3; |
||
| 2173 | |||
| 2174 | return (r ? enc.slice(0, r - 3) : enc) + '==='.slice(r || 3); |
||
| 2175 | }; |
||
| 2176 | |||
| 2177 | |||
| 2178 | return { |
||
| 2179 | utf8_encode: utf8_encode, |
||
| 2180 | utf8_decode: utf8_decode, |
||
| 2181 | atob: atob, |
||
| 2182 | btoa: btoa |
||
| 2183 | }; |
||
| 2184 | }); |
||
| 2185 | |||
| 2186 | // Included from: src/javascript/runtime/Runtime.js |
||
| 2187 | |||
| 2188 | /** |
||
| 2189 | * Runtime.js |
||
| 2190 | * |
||
| 2191 | * Copyright 2013, Moxiecode Systems AB |
||
| 2192 | * Released under GPL License. |
||
| 2193 | * |
||
| 2194 | * License: http://www.plupload.com/license |
||
| 2195 | * Contributing: http://www.plupload.com/contributing |
||
| 2196 | */ |
||
| 2197 | |||
| 2198 | define('moxie/runtime/Runtime', [ |
||
| 2199 | "moxie/core/utils/Basic", |
||
| 2200 | "moxie/core/utils/Dom", |
||
| 2201 | "moxie/core/EventTarget" |
||
| 2202 | ], function(Basic, Dom, EventTarget) { |
||
| 2203 | var runtimeConstructors = {}, runtimes = {}; |
||
| 2204 | |||
| 2205 | /** |
||
| 2206 | Common set of methods and properties for every runtime instance |
||
| 2207 | |||
| 2208 | @class Runtime |
||
| 2209 | |||
| 2210 | @param {Object} options |
||
| 2211 | @param {String} type Sanitized name of the runtime |
||
| 2212 | @param {Object} [caps] Set of capabilities that differentiate specified runtime |
||
| 2213 | @param {Object} [modeCaps] Set of capabilities that do require specific operational mode |
||
| 2214 | @param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested |
||
| 2215 | */ |
||
| 2216 | function Runtime(options, type, caps, modeCaps, preferredMode) { |
||
| 2217 | /** |
||
| 2218 | Dispatched when runtime is initialized and ready. |
||
| 2219 | Results in RuntimeInit on a connected component. |
||
| 2220 | |||
| 2221 | @event Init |
||
| 2222 | */ |
||
| 2223 | |||
| 2224 | /** |
||
| 2225 | Dispatched when runtime fails to initialize. |
||
| 2226 | Results in RuntimeError on a connected component. |
||
| 2227 | |||
| 2228 | @event Error |
||
| 2229 | */ |
||
| 2230 | |||
| 2231 | var self = this |
||
| 2232 | , _shim |
||
| 2233 | , _uid = Basic.guid(type + '_') |
||
| 2234 | , defaultMode = preferredMode || 'browser' |
||
| 2235 | ; |
||
| 2236 | |||
| 2237 | options = options || {}; |
||
| 2238 | |||
| 2239 | // register runtime in private hash |
||
| 2240 | runtimes[_uid] = this; |
||
| 2241 | |||
| 2242 | /** |
||
| 2243 | Default set of capabilities, which can be redifined later by specific runtime |
||
| 2244 | |||
| 2245 | @private |
||
| 2246 | @property caps |
||
| 2247 | @type Object |
||
| 2248 | */ |
||
| 2249 | caps = Basic.extend({ |
||
| 2250 | // Runtime can: |
||
| 2251 | // provide access to raw binary data of the file |
||
| 2252 | access_binary: false, |
||
| 2253 | // provide access to raw binary data of the image (image extension is optional) |
||
| 2254 | access_image_binary: false, |
||
| 2255 | // display binary data as thumbs for example |
||
| 2256 | display_media: false, |
||
| 2257 | // make cross-domain requests |
||
| 2258 | do_cors: false, |
||
| 2259 | // accept files dragged and dropped from the desktop |
||
| 2260 | drag_and_drop: false, |
||
| 2261 | // filter files in selection dialog by their extensions |
||
| 2262 | filter_by_extension: true, |
||
| 2263 | // resize image (and manipulate it raw data of any file in general) |
||
| 2264 | resize_image: false, |
||
| 2265 | // periodically report how many bytes of total in the file were uploaded (loaded) |
||
| 2266 | report_upload_progress: false, |
||
| 2267 | // provide access to the headers of http response |
||
| 2268 | return_response_headers: false, |
||
| 2269 | // support response of specific type, which should be passed as an argument |
||
| 2270 | // e.g. runtime.can('return_response_type', 'blob') |
||
| 2271 | return_response_type: false, |
||
| 2272 | // return http status code of the response |
||
| 2273 | return_status_code: true, |
||
| 2274 | // send custom http header with the request |
||
| 2275 | send_custom_headers: false, |
||
| 2276 | // pick up the files from a dialog |
||
| 2277 | select_file: false, |
||
| 2278 | // select whole folder in file browse dialog |
||
| 2279 | select_folder: false, |
||
| 2280 | // select multiple files at once in file browse dialog |
||
| 2281 | select_multiple: true, |
||
| 2282 | // send raw binary data, that is generated after image resizing or manipulation of other kind |
||
| 2283 | send_binary_string: false, |
||
| 2284 | // send cookies with http request and therefore retain session |
||
| 2285 | send_browser_cookies: true, |
||
| 2286 | // send data formatted as multipart/form-data |
||
| 2287 | send_multipart: true, |
||
| 2288 | // slice the file or blob to smaller parts |
||
| 2289 | slice_blob: false, |
||
| 2290 | // upload file without preloading it to memory, stream it out directly from disk |
||
| 2291 | stream_upload: false, |
||
| 2292 | // programmatically trigger file browse dialog |
||
| 2293 | summon_file_dialog: false, |
||
| 2294 | // upload file of specific size, size should be passed as argument |
||
| 2295 | // e.g. runtime.can('upload_filesize', '500mb') |
||
| 2296 | upload_filesize: true, |
||
| 2297 | // initiate http request with specific http method, method should be passed as argument |
||
| 2298 | // e.g. runtime.can('use_http_method', 'put') |
||
| 2299 | use_http_method: true |
||
| 2300 | }, caps); |
||
| 2301 | |||
| 2302 | |||
| 2303 | // default to the mode that is compatible with preferred caps |
||
| 2304 | if (options.preferred_caps) { |
||
| 2305 | defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode); |
||
| 2306 | } |
||
| 2307 | |||
| 2308 | // small extension factory here (is meant to be extended with actual extensions constructors) |
||
| 2309 | _shim = (function() { |
||
| 2310 | var objpool = {}; |
||
| 2311 | return { |
||
| 2312 | exec: function(uid, comp, fn, args) { |
||
| 2313 | if (_shim[comp]) { |
||
| 2314 | if (!objpool[uid]) { |
||
| 2315 | objpool[uid] = { |
||
| 2316 | context: this, |
||
| 2317 | instance: new _shim[comp]() |
||
| 2318 | }; |
||
| 2319 | } |
||
| 2320 | if (objpool[uid].instance[fn]) { |
||
| 2321 | return objpool[uid].instance[fn].apply(this, args); |
||
| 2322 | } |
||
| 2323 | } |
||
| 2324 | }, |
||
| 2325 | |||
| 2326 | removeInstance: function(uid) { |
||
| 2327 | delete objpool[uid]; |
||
| 2328 | }, |
||
| 2329 | |||
| 2330 | removeAllInstances: function() { |
||
| 2331 | var self = this; |
||
| 2332 | Basic.each(objpool, function(obj, uid) { |
||
| 2333 | if (Basic.typeOf(obj.instance.destroy) === 'function') { |
||
| 2334 | obj.instance.destroy.call(obj.context); |
||
| 2335 | } |
||
| 2336 | self.removeInstance(uid); |
||
| 2337 | }); |
||
| 2338 | } |
||
| 2339 | }; |
||
| 2340 | }()); |
||
| 2341 | |||
| 2342 | |||
| 2343 | // public methods |
||
| 2344 | Basic.extend(this, { |
||
| 2345 | /** |
||
| 2346 | Specifies whether runtime instance was initialized or not |
||
| 2347 | |||
| 2348 | @property initialized |
||
| 2349 | @type {Boolean} |
||
| 2350 | @default false |
||
| 2351 | */ |
||
| 2352 | initialized: false, // shims require this flag to stop initialization retries |
||
| 2353 | |||
| 2354 | /** |
||
| 2355 | Unique ID of the runtime |
||
| 2356 | |||
| 2357 | @property uid |
||
| 2358 | @type {String} |
||
| 2359 | */ |
||
| 2360 | uid: _uid, |
||
| 2361 | |||
| 2362 | /** |
||
| 2363 | Runtime type (e.g. flash, html5, etc) |
||
| 2364 | |||
| 2365 | @property type |
||
| 2366 | @type {String} |
||
| 2367 | */ |
||
| 2368 | type: type, |
||
| 2369 | |||
| 2370 | /** |
||
| 2371 | Runtime (not native one) may operate in browser or client mode. |
||
| 2372 | |||
| 2373 | @property mode |
||
| 2374 | @private |
||
| 2375 | @type {String|Boolean} current mode or false, if none possible |
||
| 2376 | */ |
||
| 2377 | mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode), |
||
| 2378 | |||
| 2379 | /** |
||
| 2380 | id of the DOM container for the runtime (if available) |
||
| 2381 | |||
| 2382 | @property shimid |
||
| 2383 | @type {String} |
||
| 2384 | */ |
||
| 2385 | shimid: _uid + '_container', |
||
| 2386 | |||
| 2387 | /** |
||
| 2388 | Number of connected clients. If equal to zero, runtime can be destroyed |
||
| 2389 | |||
| 2390 | @property clients |
||
| 2391 | @type {Number} |
||
| 2392 | */ |
||
| 2393 | clients: 0, |
||
| 2394 | |||
| 2395 | /** |
||
| 2396 | Runtime initialization options |
||
| 2397 | |||
| 2398 | @property options |
||
| 2399 | @type {Object} |
||
| 2400 | */ |
||
| 2401 | options: options, |
||
| 2402 | |||
| 2403 | /** |
||
| 2404 | Checks if the runtime has specific capability |
||
| 2405 | |||
| 2406 | @method can |
||
| 2407 | @param {String} cap Name of capability to check |
||
| 2408 | @param {Mixed} [value] If passed, capability should somehow correlate to the value |
||
| 2409 | @param {Object} [refCaps] Set of capabilities to check the specified cap against (defaults to internal set) |
||
| 2410 | @return {Boolean} true if runtime has such capability and false, if - not |
||
| 2411 | */ |
||
| 2412 | can: function(cap, value) { |
||
| 2413 | var refCaps = arguments[2] || caps; |
||
| 2414 | |||
| 2415 | // if cap var is a comma-separated list of caps, convert it to object (key/value) |
||
| 2416 | if (Basic.typeOf(cap) === 'string' && Basic.typeOf(value) === 'undefined') { |
||
| 2417 | cap = Runtime.parseCaps(cap); |
||
| 2418 | } |
||
| 2419 | |||
| 2420 | if (Basic.typeOf(cap) === 'object') { |
||
| 2421 | for (var key in cap) { |
||
| 2422 | if (!this.can(key, cap[key], refCaps)) { |
||
| 2423 | return false; |
||
| 2424 | } |
||
| 2425 | } |
||
| 2426 | return true; |
||
| 2427 | } |
||
| 2428 | |||
| 2429 | // check the individual cap |
||
| 2430 | if (Basic.typeOf(refCaps[cap]) === 'function') { |
||
| 2431 | return refCaps[cap].call(this, value); |
||
| 2432 | } else { |
||
| 2433 | return (value === refCaps[cap]); |
||
| 2434 | } |
||
| 2435 | }, |
||
| 2436 | |||
| 2437 | /** |
||
| 2438 | Returns container for the runtime as DOM element |
||
| 2439 | |||
| 2440 | @method getShimContainer |
||
| 2441 | @return {DOMElement} |
||
| 2442 | */ |
||
| 2443 | getShimContainer: function() { |
||
| 2444 | var container, shimContainer = Dom.get(this.shimid); |
||
| 2445 | |||
| 2446 | // if no container for shim, create one |
||
| 2447 | if (!shimContainer) { |
||
| 2448 | container = this.options.container ? Dom.get(this.options.container) : document.body; |
||
| 2449 | |||
| 2450 | // create shim container and insert it at an absolute position into the outer container |
||
| 2451 | shimContainer = document.createElement('div'); |
||
| 2452 | shimContainer.id = this.shimid; |
||
| 2453 | shimContainer.className = 'moxie-shim moxie-shim-' + this.type; |
||
| 2454 | |||
| 2455 | Basic.extend(shimContainer.style, { |
||
| 2456 | position: 'absolute', |
||
| 2457 | top: '0px', |
||
| 2458 | left: '0px', |
||
| 2459 | width: '1px', |
||
| 2460 | height: '1px', |
||
| 2461 | overflow: 'hidden' |
||
| 2462 | }); |
||
| 2463 | |||
| 2464 | container.appendChild(shimContainer); |
||
| 2465 | container = null; |
||
| 2466 | } |
||
| 2467 | |||
| 2468 | return shimContainer; |
||
| 2469 | }, |
||
| 2470 | |||
| 2471 | /** |
||
| 2472 | Returns runtime as DOM element (if appropriate) |
||
| 2473 | |||
| 2474 | @method getShim |
||
| 2475 | @return {DOMElement} |
||
| 2476 | */ |
||
| 2477 | getShim: function() { |
||
| 2478 | return _shim; |
||
| 2479 | }, |
||
| 2480 | |||
| 2481 | /** |
||
| 2482 | Invokes a method within the runtime itself (might differ across the runtimes) |
||
| 2483 | |||
| 2484 | @method shimExec |
||
| 2485 | @param {Mixed} [] |
||
| 2486 | @protected |
||
| 2487 | @return {Mixed} Depends on the action and component |
||
| 2488 | */ |
||
| 2489 | shimExec: function(component, action) { |
||
| 2490 | var args = [].slice.call(arguments, 2); |
||
| 2491 | return self.getShim().exec.call(this, this.uid, component, action, args); |
||
| 2492 | }, |
||
| 2493 | |||
| 2494 | /** |
||
| 2495 | Operaional interface that is used by components to invoke specific actions on the runtime |
||
| 2496 | (is invoked in the scope of component) |
||
| 2497 | |||
| 2498 | @method exec |
||
| 2499 | @param {Mixed} []* |
||
| 2500 | @protected |
||
| 2501 | @return {Mixed} Depends on the action and component |
||
| 2502 | */ |
||
| 2503 | exec: function(component, action) { // this is called in the context of component, not runtime |
||
| 2504 | var args = [].slice.call(arguments, 2); |
||
| 2505 | |||
| 2506 | if (self[component] && self[component][action]) { |
||
| 2507 | return self[component][action].apply(this, args); |
||
| 2508 | } |
||
| 2509 | return self.shimExec.apply(this, arguments); |
||
| 2510 | }, |
||
| 2511 | |||
| 2512 | /** |
||
| 2513 | Destroys the runtime (removes all events and deletes DOM structures) |
||
| 2514 | |||
| 2515 | @method destroy |
||
| 2516 | */ |
||
| 2517 | destroy: function() { |
||
| 2518 | if (!self) { |
||
| 2519 | return; // obviously already destroyed |
||
| 2520 | } |
||
| 2521 | |||
| 2522 | var shimContainer = Dom.get(this.shimid); |
||
| 2523 | if (shimContainer) { |
||
| 2524 | shimContainer.parentNode.removeChild(shimContainer); |
||
| 2525 | } |
||
| 2526 | |||
| 2527 | if (_shim) { |
||
| 2528 | _shim.removeAllInstances(); |
||
| 2529 | } |
||
| 2530 | |||
| 2531 | this.unbindAll(); |
||
| 2532 | delete runtimes[this.uid]; |
||
| 2533 | this.uid = null; // mark this runtime as destroyed |
||
| 2534 | _uid = self = _shim = shimContainer = null; |
||
| 2535 | } |
||
| 2536 | }); |
||
| 2537 | |||
| 2538 | // once we got the mode, test against all caps |
||
| 2539 | if (this.mode && options.required_caps && !this.can(options.required_caps)) { |
||
| 2540 | this.mode = false; |
||
| 2541 | } |
||
| 2542 | } |
||
| 2543 | |||
| 2544 | |||
| 2545 | /** |
||
| 2546 | Default order to try different runtime types |
||
| 2547 | |||
| 2548 | @property order |
||
| 2549 | @type String |
||
| 2550 | @static |
||
| 2551 | */ |
||
| 2552 | Runtime.order = 'html5,flash,silverlight,html4'; |
||
| 2553 | |||
| 2554 | |||
| 2555 | /** |
||
| 2556 | Retrieves runtime from private hash by it's uid |
||
| 2557 | |||
| 2558 | @method getRuntime |
||
| 2559 | @private |
||
| 2560 | @static |
||
| 2561 | @param {String} uid Unique identifier of the runtime |
||
| 2562 | @return {Runtime|Boolean} Returns runtime, if it exists and false, if - not |
||
| 2563 | */ |
||
| 2564 | Runtime.getRuntime = function(uid) { |
||
| 2565 | return runtimes[uid] ? runtimes[uid] : false; |
||
| 2566 | }; |
||
| 2567 | |||
| 2568 | |||
| 2569 | /** |
||
| 2570 | Register constructor for the Runtime of new (or perhaps modified) type |
||
| 2571 | |||
| 2572 | @method addConstructor |
||
| 2573 | @static |
||
| 2574 | @param {String} type Runtime type (e.g. flash, html5, etc) |
||
| 2575 | @param {Function} construct Constructor for the Runtime type |
||
| 2576 | */ |
||
| 2577 | Runtime.addConstructor = function(type, constructor) { |
||
| 2578 | constructor.prototype = EventTarget.instance; |
||
| 2579 | runtimeConstructors[type] = constructor; |
||
| 2580 | }; |
||
| 2581 | |||
| 2582 | |||
| 2583 | /** |
||
| 2584 | Get the constructor for the specified type. |
||
| 2585 | |||
| 2586 | method getConstructor |
||
| 2587 | @static |
||
| 2588 | @param {String} type Runtime type (e.g. flash, html5, etc) |
||
| 2589 | @return {Function} Constructor for the Runtime type |
||
| 2590 | */ |
||
| 2591 | Runtime.getConstructor = function(type) { |
||
| 2592 | return runtimeConstructors[type] || null; |
||
| 2593 | }; |
||
| 2594 | |||
| 2595 | |||
| 2596 | /** |
||
| 2597 | Get info about the runtime (uid, type, capabilities) |
||
| 2598 | |||
| 2599 | @method getInfo |
||
| 2600 | @static |
||
| 2601 | @param {String} uid Unique identifier of the runtime |
||
| 2602 | @return {Mixed} Info object or null if runtime doesn't exist |
||
| 2603 | */ |
||
| 2604 | Runtime.getInfo = function(uid) { |
||
| 2605 | var runtime = Runtime.getRuntime(uid); |
||
| 2606 | |||
| 2607 | if (runtime) { |
||
| 2608 | return { |
||
| 2609 | uid: runtime.uid, |
||
| 2610 | type: runtime.type, |
||
| 2611 | mode: runtime.mode, |
||
| 2612 | can: function() { |
||
| 2613 | return runtime.can.apply(runtime, arguments); |
||
| 2614 | } |
||
| 2615 | }; |
||
| 2616 | } |
||
| 2617 | return null; |
||
| 2618 | }; |
||
| 2619 | |||
| 2620 | |||
| 2621 | /** |
||
| 2622 | Convert caps represented by a comma-separated string to the object representation. |
||
| 2623 | |||
| 2624 | @method parseCaps |
||
| 2625 | @static |
||
| 2626 | @param {String} capStr Comma-separated list of capabilities |
||
| 2627 | @return {Object} |
||
| 2628 | */ |
||
| 2629 | Runtime.parseCaps = function(capStr) { |
||
| 2630 | var capObj = {}; |
||
| 2631 | |||
| 2632 | if (Basic.typeOf(capStr) !== 'string') { |
||
| 2633 | return capStr || {}; |
||
| 2634 | } |
||
| 2635 | |||
| 2636 | Basic.each(capStr.split(','), function(key) { |
||
| 2637 | capObj[key] = true; // we assume it to be - true |
||
| 2638 | }); |
||
| 2639 | |||
| 2640 | return capObj; |
||
| 2641 | }; |
||
| 2642 | |||
| 2643 | /** |
||
| 2644 | Test the specified runtime for specific capabilities. |
||
| 2645 | |||
| 2646 | @method can |
||
| 2647 | @static |
||
| 2648 | @param {String} type Runtime type (e.g. flash, html5, etc) |
||
| 2649 | @param {String|Object} caps Set of capabilities to check |
||
| 2650 | @return {Boolean} Result of the test |
||
| 2651 | */ |
||
| 2652 | Runtime.can = function(type, caps) { |
||
| 2653 | var runtime |
||
| 2654 | , constructor = Runtime.getConstructor(type) |
||
| 2655 | , mode |
||
| 2656 | ; |
||
| 2657 | if (constructor) { |
||
| 2658 | runtime = new constructor({ |
||
| 2659 | required_caps: caps |
||
| 2660 | }); |
||
| 2661 | mode = runtime.mode; |
||
| 2662 | runtime.destroy(); |
||
| 2663 | return !!mode; |
||
| 2664 | } |
||
| 2665 | return false; |
||
| 2666 | }; |
||
| 2667 | |||
| 2668 | |||
| 2669 | /** |
||
| 2670 | Figure out a runtime that supports specified capabilities. |
||
| 2671 | |||
| 2672 | @method thatCan |
||
| 2673 | @static |
||
| 2674 | @param {String|Object} caps Set of capabilities to check |
||
| 2675 | @param {String} [runtimeOrder] Comma-separated list of runtimes to check against |
||
| 2676 | @return {String} Usable runtime identifier or null |
||
| 2677 | */ |
||
| 2678 | Runtime.thatCan = function(caps, runtimeOrder) { |
||
| 2679 | var types = (runtimeOrder || Runtime.order).split(/\s*,\s*/); |
||
| 2680 | for (var i in types) { |
||
| 2681 | if (Runtime.can(types[i], caps)) { |
||
| 2682 | return types[i]; |
||
| 2683 | } |
||
| 2684 | } |
||
| 2685 | return null; |
||
| 2686 | }; |
||
| 2687 | |||
| 2688 | |||
| 2689 | /** |
||
| 2690 | Figure out an operational mode for the specified set of capabilities. |
||
| 2691 | |||
| 2692 | @method getMode |
||
| 2693 | @static |
||
| 2694 | @param {Object} modeCaps Set of capabilities that depend on particular runtime mode |
||
| 2695 | @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for |
||
| 2696 | @param {String|Boolean} [defaultMode='browser'] Default mode to use |
||
| 2697 | @return {String|Boolean} Compatible operational mode |
||
| 2698 | */ |
||
| 2699 | Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) { |
||
| 2700 | var mode = null; |
||
| 2701 | |||
| 2702 | if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified |
||
| 2703 | defaultMode = 'browser'; |
||
| 2704 | } |
||
| 2705 | |||
| 2706 | if (requiredCaps && !Basic.isEmptyObj(modeCaps)) { |
||
| 2707 | // loop over required caps and check if they do require the same mode |
||
| 2708 | Basic.each(requiredCaps, function(value, cap) { |
||
| 2709 | if (modeCaps.hasOwnProperty(cap)) { |
||
| 2710 | var capMode = modeCaps[cap](value); |
||
| 2711 | |||
| 2712 | // make sure we always have an array |
||
| 2713 | if (typeof(capMode) === 'string') { |
||
| 2714 | capMode = [capMode]; |
||
| 2715 | } |
||
| 2716 | |||
| 2717 | if (!mode) { |
||
| 2718 | mode = capMode; |
||
| 2719 | } else if (!(mode = Basic.arrayIntersect(mode, capMode))) { |
||
| 2720 | // if cap requires conflicting mode - runtime cannot fulfill required caps |
||
| 2721 | return (mode = false); |
||
| 2722 | } |
||
| 2723 | } |
||
| 2724 | }); |
||
| 2725 | |||
| 2726 | if (mode) { |
||
| 2727 | return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0]; |
||
| 2728 | } else if (mode === false) { |
||
| 2729 | return false; |
||
| 2730 | } |
||
| 2731 | } |
||
| 2732 | return defaultMode; |
||
| 2733 | }; |
||
| 2734 | |||
| 2735 | |||
| 2736 | /** |
||
| 2737 | Capability check that always returns true |
||
| 2738 | |||
| 2739 | @private |
||
| 2740 | @static |
||
| 2741 | @return {True} |
||
| 2742 | */ |
||
| 2743 | Runtime.capTrue = function() { |
||
| 2744 | return true; |
||
| 2745 | }; |
||
| 2746 | |||
| 2747 | /** |
||
| 2748 | Capability check that always returns false |
||
| 2749 | |||
| 2750 | @private |
||
| 2751 | @static |
||
| 2752 | @return {False} |
||
| 2753 | */ |
||
| 2754 | Runtime.capFalse = function() { |
||
| 2755 | return false; |
||
| 2756 | }; |
||
| 2757 | |||
| 2758 | /** |
||
| 2759 | Evaluate the expression to boolean value and create a function that always returns it. |
||
| 2760 | |||
| 2761 | @private |
||
| 2762 | @static |
||
| 2763 | @param {Mixed} expr Expression to evaluate |
||
| 2764 | @return {Function} Function returning the result of evaluation |
||
| 2765 | */ |
||
| 2766 | Runtime.capTest = function(expr) { |
||
| 2767 | return function() { |
||
| 2768 | return !!expr; |
||
| 2769 | }; |
||
| 2770 | }; |
||
| 2771 | |||
| 2772 | return Runtime; |
||
| 2773 | }); |
||
| 2774 | |||
| 2775 | // Included from: src/javascript/runtime/RuntimeClient.js |
||
| 2776 | |||
| 2777 | /** |
||
| 2778 | * RuntimeClient.js |
||
| 2779 | * |
||
| 2780 | * Copyright 2013, Moxiecode Systems AB |
||
| 2781 | * Released under GPL License. |
||
| 2782 | * |
||
| 2783 | * License: http://www.plupload.com/license |
||
| 2784 | * Contributing: http://www.plupload.com/contributing |
||
| 2785 | */ |
||
| 2786 | |||
| 2787 | define('moxie/runtime/RuntimeClient', [ |
||
| 2788 | 'moxie/core/Exceptions', |
||
| 2789 | 'moxie/core/utils/Basic', |
||
| 2790 | 'moxie/runtime/Runtime' |
||
| 2791 | ], function(x, Basic, Runtime) { |
||
| 2792 | /** |
||
| 2793 | Set of methods and properties, required by a component to acquire ability to connect to a runtime |
||
| 2794 | |||
| 2795 | @class RuntimeClient |
||
| 2796 | */ |
||
| 2797 | return function RuntimeClient() { |
||
| 2798 | var runtime; |
||
| 2799 | |||
| 2800 | Basic.extend(this, { |
||
| 2801 | /** |
||
| 2802 | Connects to the runtime specified by the options. Will either connect to existing runtime or create a new one. |
||
| 2803 | Increments number of clients connected to the specified runtime. |
||
| 2804 | |||
| 2805 | @method connectRuntime |
||
| 2806 | @param {Mixed} options Can be a runtme uid or a set of key-value pairs defining requirements and pre-requisites |
||
| 2807 | */ |
||
| 2808 | connectRuntime: function(options) { |
||
| 2809 | var comp = this, ruid; |
||
| 2810 | |||
| 2811 | function initialize(items) { |
||
| 2812 | var type, constructor; |
||
| 2813 | |||
| 2814 | // if we ran out of runtimes |
||
| 2815 | if (!items.length) { |
||
| 2816 | comp.trigger('RuntimeError', new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); |
||
| 2817 | runtime = null; |
||
| 2818 | return; |
||
| 2819 | } |
||
| 2820 | |||
| 2821 | type = items.shift(); |
||
| 2822 | constructor = Runtime.getConstructor(type); |
||
| 2823 | if (!constructor) { |
||
| 2824 | initialize(items); |
||
| 2825 | return; |
||
| 2826 | } |
||
| 2827 | |||
| 2828 | // try initializing the runtime |
||
| 2829 | runtime = new constructor(options); |
||
| 2830 | |||
| 2831 | runtime.bind('Init', function() { |
||
| 2832 | // mark runtime as initialized |
||
| 2833 | runtime.initialized = true; |
||
| 2834 | |||
| 2835 | // jailbreak ... |
||
| 2836 | setTimeout(function() { |
||
| 2837 | runtime.clients++; |
||
| 2838 | // this will be triggered on component |
||
| 2839 | comp.trigger('RuntimeInit', runtime); |
||
| 2840 | }, 1); |
||
| 2841 | }); |
||
| 2842 | |||
| 2843 | runtime.bind('Error', function() { |
||
| 2844 | runtime.destroy(); // runtime cannot destroy itself from inside at a right moment, thus we do it here |
||
| 2845 | initialize(items); |
||
| 2846 | }); |
||
| 2847 | |||
| 2848 | /*runtime.bind('Exception', function() { });*/ |
||
| 2849 | |||
| 2850 | // check if runtime managed to pick-up operational mode |
||
| 2851 | if (!runtime.mode) { |
||
| 2852 | runtime.trigger('Error'); |
||
| 2853 | return; |
||
| 2854 | } |
||
| 2855 | |||
| 2856 | runtime.init(); |
||
| 2857 | } |
||
| 2858 | |||
| 2859 | // check if a particular runtime was requested |
||
| 2860 | if (Basic.typeOf(options) === 'string') { |
||
| 2861 | ruid = options; |
||
| 2862 | } else if (Basic.typeOf(options.ruid) === 'string') { |
||
| 2863 | ruid = options.ruid; |
||
| 2864 | } |
||
| 2865 | |||
| 2866 | if (ruid) { |
||
| 2867 | runtime = Runtime.getRuntime(ruid); |
||
| 2868 | if (runtime) { |
||
| 2869 | runtime.clients++; |
||
| 2870 | return runtime; |
||
| 2871 | } else { |
||
| 2872 | // there should be a runtime and there's none - weird case |
||
| 2873 | throw new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR); |
||
| 2874 | } |
||
| 2875 | } |
||
| 2876 | |||
| 2877 | // initialize a fresh one, that fits runtime list and required features best |
||
| 2878 | initialize((options.runtime_order || Runtime.order).split(/\s*,\s*/)); |
||
| 2879 | }, |
||
| 2880 | |||
| 2881 | /** |
||
| 2882 | Returns the runtime to which the client is currently connected. |
||
| 2883 | |||
| 2884 | @method getRuntime |
||
| 2885 | @return {Runtime} Runtime or null if client is not connected |
||
| 2886 | */ |
||
| 2887 | getRuntime: function() { |
||
| 2888 | if (runtime && runtime.uid) { |
||
| 2889 | return runtime; |
||
| 2890 | } |
||
| 2891 | runtime = null; // make sure we do not leave zombies rambling around |
||
| 2892 | return null; |
||
| 2893 | }, |
||
| 2894 | |||
| 2895 | /** |
||
| 2896 | Disconnects from the runtime. Decrements number of clients connected to the specified runtime. |
||
| 2897 | |||
| 2898 | @method disconnectRuntime |
||
| 2899 | */ |
||
| 2900 | disconnectRuntime: function() { |
||
| 2901 | if (runtime && --runtime.clients <= 0) { |
||
| 2902 | runtime.destroy(); |
||
| 2903 | runtime = null; |
||
| 2904 | } |
||
| 2905 | } |
||
| 2906 | |||
| 2907 | }); |
||
| 2908 | }; |
||
| 2909 | |||
| 2910 | |||
| 2911 | }); |
||
| 2912 | |||
| 2913 | // Included from: src/javascript/file/Blob.js |
||
| 2914 | |||
| 2915 | /** |
||
| 2916 | * Blob.js |
||
| 2917 | * |
||
| 2918 | * Copyright 2013, Moxiecode Systems AB |
||
| 2919 | * Released under GPL License. |
||
| 2920 | * |
||
| 2921 | * License: http://www.plupload.com/license |
||
| 2922 | * Contributing: http://www.plupload.com/contributing |
||
| 2923 | */ |
||
| 2924 | |||
| 2925 | define('moxie/file/Blob', [ |
||
| 2926 | 'moxie/core/utils/Basic', |
||
| 2927 | 'moxie/core/utils/Encode', |
||
| 2928 | 'moxie/runtime/RuntimeClient' |
||
| 2929 | ], function(Basic, Encode, RuntimeClient) { |
||
| 2930 | |||
| 2931 | var blobpool = {}; |
||
| 2932 | |||
| 2933 | /** |
||
| 2934 | @class Blob |
||
| 2935 | @constructor |
||
| 2936 | @param {String} ruid Unique id of the runtime, to which this blob belongs to |
||
| 2937 | @param {Object} blob Object "Native" blob object, as it is represented in the runtime |
||
| 2938 | */ |
||
| 2939 | function Blob(ruid, blob) { |
||
| 2940 | |||
| 2941 | function _sliceDetached(start, end, type) { |
||
| 2942 | var blob, data = blobpool[this.uid]; |
||
| 2943 | |||
| 2944 | if (Basic.typeOf(data) !== 'string' || !data.length) { |
||
| 2945 | return null; // or throw exception |
||
| 2946 | } |
||
| 2947 | |||
| 2948 | blob = new Blob(null, { |
||
| 2949 | type: type, |
||
| 2950 | size: end - start |
||
| 2951 | }); |
||
| 2952 | blob.detach(data.substr(start, blob.size)); |
||
| 2953 | |||
| 2954 | return blob; |
||
| 2955 | } |
||
| 2956 | |||
| 2957 | RuntimeClient.call(this); |
||
| 2958 | |||
| 2959 | if (ruid) { |
||
| 2960 | this.connectRuntime(ruid); |
||
| 2961 | } |
||
| 2962 | |||
| 2963 | if (!blob) { |
||
| 2964 | blob = {}; |
||
| 2965 | } else if (Basic.typeOf(blob) === 'string') { // dataUrl or binary string |
||
| 2966 | blob = { data: blob }; |
||
| 2967 | } |
||
| 2968 | |||
| 2969 | Basic.extend(this, { |
||
| 2970 | |||
| 2971 | /** |
||
| 2972 | Unique id of the component |
||
| 2973 | |||
| 2974 | @property uid |
||
| 2975 | @type {String} |
||
| 2976 | */ |
||
| 2977 | uid: blob.uid || Basic.guid('uid_'), |
||
| 2978 | |||
| 2979 | /** |
||
| 2980 | Unique id of the connected runtime, if falsy, then runtime will have to be initialized |
||
| 2981 | before this Blob can be used, modified or sent |
||
| 2982 | |||
| 2983 | @property ruid |
||
| 2984 | @type {String} |
||
| 2985 | */ |
||
| 2986 | ruid: ruid, |
||
| 2987 | |||
| 2988 | /** |
||
| 2989 | Size of blob |
||
| 2990 | |||
| 2991 | @property size |
||
| 2992 | @type {Number} |
||
| 2993 | @default 0 |
||
| 2994 | */ |
||
| 2995 | size: blob.size || 0, |
||
| 2996 | |||
| 2997 | /** |
||
| 2998 | Mime type of blob |
||
| 2999 | |||
| 3000 | @property type |
||
| 3001 | @type {String} |
||
| 3002 | @default '' |
||
| 3003 | */ |
||
| 3004 | type: blob.type || '', |
||
| 3005 | |||
| 3006 | /** |
||
| 3007 | @method slice |
||
| 3008 | @param {Number} [start=0] |
||
| 3009 | */ |
||
| 3010 | slice: function(start, end, type) { |
||
| 3011 | if (this.isDetached()) { |
||
| 3012 | return _sliceDetached.apply(this, arguments); |
||
| 3013 | } |
||
| 3014 | return this.getRuntime().exec.call(this, 'Blob', 'slice', this.getSource(), start, end, type); |
||
| 3015 | }, |
||
| 3016 | |||
| 3017 | /** |
||
| 3018 | Returns "native" blob object (as it is represented in connected runtime) or null if not found |
||
| 3019 | |||
| 3020 | @method getSource |
||
| 3021 | @return {Blob} Returns "native" blob object or null if not found |
||
| 3022 | */ |
||
| 3023 | getSource: function() { |
||
| 3024 | if (!blobpool[this.uid]) { |
||
| 3025 | return null; |
||
| 3026 | } |
||
| 3027 | return blobpool[this.uid]; |
||
| 3028 | }, |
||
| 3029 | |||
| 3030 | /** |
||
| 3031 | Detaches blob from any runtime that it depends on and initialize with standalone value |
||
| 3032 | |||
| 3033 | @method detach |
||
| 3034 | @protected |
||
| 3035 | @param {DOMString} [data=''] Standalone value |
||
| 3036 | */ |
||
| 3037 | detach: function(data) { |
||
| 3038 | if (this.ruid) { |
||
| 3039 | this.getRuntime().exec.call(this, 'Blob', 'destroy'); |
||
| 3040 | this.disconnectRuntime(); |
||
| 3041 | this.ruid = null; |
||
| 3042 | } |
||
| 3043 | |||
| 3044 | data = data || ''; |
||
| 3045 | |||
| 3046 | // if dataUrl, convert to binary string |
||
| 3047 | var matches = data.match(/^data:([^;]*);base64,/); |
||
| 3048 | if (matches) { |
||
| 3049 | this.type = matches[1]; |
||
| 3050 | data = Encode.atob(data.substring(data.indexOf('base64,') + 7)); |
||
| 3051 | } |
||
| 3052 | |||
| 3053 | this.size = data.length; |
||
| 3054 | |||
| 3055 | blobpool[this.uid] = data; |
||
| 3056 | }, |
||
| 3057 | |||
| 3058 | /** |
||
| 3059 | Checks if blob is standalone (detached of any runtime) |
||
| 3060 | |||
| 3061 | @method isDetached |
||
| 3062 | @protected |
||
| 3063 | @return {Boolean} |
||
| 3064 | */ |
||
| 3065 | isDetached: function() { |
||
| 3066 | return !this.ruid && Basic.typeOf(blobpool[this.uid]) === 'string'; |
||
| 3067 | }, |
||
| 3068 | |||
| 3069 | /** |
||
| 3070 | Destroy Blob and free any resources it was using |
||
| 3071 | |||
| 3072 | @method destroy |
||
| 3073 | */ |
||
| 3074 | destroy: function() { |
||
| 3075 | this.detach(); |
||
| 3076 | delete blobpool[this.uid]; |
||
| 3077 | } |
||
| 3078 | }); |
||
| 3079 | |||
| 3080 | |||
| 3081 | if (blob.data) { |
||
| 3082 | this.detach(blob.data); // auto-detach if payload has been passed |
||
| 3083 | } else { |
||
| 3084 | blobpool[this.uid] = blob; |
||
| 3085 | } |
||
| 3086 | } |
||
| 3087 | |||
| 3088 | return Blob; |
||
| 3089 | }); |
||
| 3090 | |||
| 3091 | // Included from: src/javascript/file/File.js |
||
| 3092 | |||
| 3093 | /** |
||
| 3094 | * File.js |
||
| 3095 | * |
||
| 3096 | * Copyright 2013, Moxiecode Systems AB |
||
| 3097 | * Released under GPL License. |
||
| 3098 | * |
||
| 3099 | * License: http://www.plupload.com/license |
||
| 3100 | * Contributing: http://www.plupload.com/contributing |
||
| 3101 | */ |
||
| 3102 | |||
| 3103 | define('moxie/file/File', [ |
||
| 3104 | 'moxie/core/utils/Basic', |
||
| 3105 | 'moxie/core/utils/Mime', |
||
| 3106 | 'moxie/file/Blob' |
||
| 3107 | ], function(Basic, Mime, Blob) { |
||
| 3108 | /** |
||
| 3109 | @class File |
||
| 3110 | @extends Blob |
||
| 3111 | @constructor |
||
| 3112 | @param {String} ruid Unique id of the runtime, to which this blob belongs to |
||
| 3113 | @param {Object} file Object "Native" file object, as it is represented in the runtime |
||
| 3114 | */ |
||
| 3115 | function File(ruid, file) { |
||
| 3116 | var name, type; |
||
| 3117 | |||
| 3118 | if (!file) { // avoid extra errors in case we overlooked something |
||
| 3119 | file = {}; |
||
| 3120 | } |
||
| 3121 | |||
| 3122 | // figure out the type |
||
| 3123 | if (file.type && file.type !== '') { |
||
| 3124 | type = file.type; |
||
| 3125 | } else { |
||
| 3126 | type = Mime.getFileMime(file.name); |
||
| 3127 | } |
||
| 3128 | |||
| 3129 | // sanitize file name or generate new one |
||
| 3130 | if (file.name) { |
||
| 3131 | name = file.name.replace(/\\/g, '/'); |
||
| 3132 | name = name.substr(name.lastIndexOf('/') + 1); |
||
| 3133 | } else { |
||
| 3134 | var prefix = type.split('/')[0]; |
||
| 3135 | name = Basic.guid((prefix !== '' ? prefix : 'file') + '_'); |
||
| 3136 | |||
| 3137 | if (Mime.extensions[type]) { |
||
| 3138 | name += '.' + Mime.extensions[type][0]; // append proper extension if possible |
||
| 3139 | } |
||
| 3140 | } |
||
| 3141 | |||
| 3142 | Blob.apply(this, arguments); |
||
| 3143 | |||
| 3144 | Basic.extend(this, { |
||
| 3145 | /** |
||
| 3146 | File mime type |
||
| 3147 | |||
| 3148 | @property type |
||
| 3149 | @type {String} |
||
| 3150 | @default '' |
||
| 3151 | */ |
||
| 3152 | type: type || '', |
||
| 3153 | |||
| 3154 | /** |
||
| 3155 | File name |
||
| 3156 | |||
| 3157 | @property name |
||
| 3158 | @type {String} |
||
| 3159 | @default UID |
||
| 3160 | */ |
||
| 3161 | name: name || Basic.guid('file_'), |
||
| 3162 | |||
| 3163 | /** |
||
| 3164 | Date of last modification |
||
| 3165 | |||
| 3166 | @property lastModifiedDate |
||
| 3167 | @type {String} |
||
| 3168 | @default now |
||
| 3169 | */ |
||
| 3170 | lastModifiedDate: file.lastModifiedDate || (new Date()).toLocaleString() // Thu Aug 23 2012 19:40:00 GMT+0400 (GET) |
||
| 3171 | }); |
||
| 3172 | } |
||
| 3173 | |||
| 3174 | File.prototype = Blob.prototype; |
||
| 3175 | |||
| 3176 | return File; |
||
| 3177 | }); |
||
| 3178 | |||
| 3179 | // Included from: src/javascript/file/FileInput.js |
||
| 3180 | |||
| 3181 | /** |
||
| 3182 | * FileInput.js |
||
| 3183 | * |
||
| 3184 | * Copyright 2013, Moxiecode Systems AB |
||
| 3185 | * Released under GPL License. |
||
| 3186 | * |
||
| 3187 | * License: http://www.plupload.com/license |
||
| 3188 | * Contributing: http://www.plupload.com/contributing |
||
| 3189 | */ |
||
| 3190 | |||
| 3191 | define('moxie/file/FileInput', [ |
||
| 3192 | 'moxie/core/utils/Basic', |
||
| 3193 | 'moxie/core/utils/Mime', |
||
| 3194 | 'moxie/core/utils/Dom', |
||
| 3195 | 'moxie/core/Exceptions', |
||
| 3196 | 'moxie/core/EventTarget', |
||
| 3197 | 'moxie/core/I18n', |
||
| 3198 | 'moxie/file/File', |
||
| 3199 | 'moxie/runtime/Runtime', |
||
| 3200 | 'moxie/runtime/RuntimeClient' |
||
| 3201 | ], function(Basic, Mime, Dom, x, EventTarget, I18n, File, Runtime, RuntimeClient) { |
||
| 3202 | /** |
||
| 3203 | Provides a convenient way to create cross-browser file-picker. Generates file selection dialog on click, |
||
| 3204 | converts selected files to _File_ objects, to be used in conjunction with _Image_, preloaded in memory |
||
| 3205 | with _FileReader_ or uploaded to a server through _XMLHttpRequest_. |
||
| 3206 | |||
| 3207 | @class FileInput |
||
| 3208 | @constructor |
||
| 3209 | @extends EventTarget |
||
| 3210 | @uses RuntimeClient |
||
| 3211 | @param {Object|String|DOMElement} options If options is string or node, argument is considered as _browse\_button_. |
||
| 3212 | @param {String|DOMElement} options.browse_button DOM Element to turn into file picker. |
||
| 3213 | @param {Array} [options.accept] Array of mime types to accept. By default accepts all. |
||
| 3214 | @param {String} [options.file='file'] Name of the file field (not the filename). |
||
| 3215 | @param {Boolean} [options.multiple=false] Enable selection of multiple files. |
||
| 3216 | @param {Boolean} [options.directory=false] Turn file input into the folder input (cannot be both at the same time). |
||
| 3217 | @param {String|DOMElement} [options.container] DOM Element to use as a container for file-picker. Defaults to parentNode |
||
| 3218 | for _browse\_button_. |
||
| 3219 | @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support. |
||
| 3220 | |||
| 3221 | @example |
||
| 3222 | <div id="container"> |
||
| 3223 | <a id="file-picker" href="javascript:;">Browse...</a> |
||
| 3224 | </div> |
||
| 3225 | |||
| 3226 | <script> |
||
| 3227 | var fileInput = new mOxie.FileInput({ |
||
| 3228 | browse_button: 'file-picker', // or document.getElementById('file-picker') |
||
| 3229 | container: 'container', |
||
| 3230 | accept: [ |
||
| 3231 | {title: "Image files", extensions: "jpg,gif,png"} // accept only images |
||
| 3232 | ], |
||
| 3233 | multiple: true // allow multiple file selection |
||
| 3234 | }); |
||
| 3235 | |||
| 3236 | fileInput.onchange = function(e) { |
||
| 3237 | // do something to files array |
||
| 3238 | console.info(e.target.files); // or this.files or fileInput.files |
||
| 3239 | }; |
||
| 3240 | |||
| 3241 | fileInput.init(); // initialize |
||
| 3242 | </script> |
||
| 3243 | */ |
||
| 3244 | var dispatches = [ |
||
| 3245 | /** |
||
| 3246 | Dispatched when runtime is connected and file-picker is ready to be used. |
||
| 3247 | |||
| 3248 | @event ready |
||
| 3249 | @param {Object} event |
||
| 3250 | */ |
||
| 3251 | 'ready', |
||
| 3252 | |||
| 3253 | /** |
||
| 3254 | Dispatched right after [ready](#event_ready) event, and whenever [refresh()](#method_refresh) is invoked. |
||
| 3255 | Check [corresponding documentation entry](#method_refresh) for more info. |
||
| 3256 | |||
| 3257 | @event refresh |
||
| 3258 | @param {Object} event |
||
| 3259 | */ |
||
| 3260 | |||
| 3261 | /** |
||
| 3262 | Dispatched when selection of files in the dialog is complete. |
||
| 3263 | |||
| 3264 | @event change |
||
| 3265 | @param {Object} event |
||
| 3266 | */ |
||
| 3267 | 'change', |
||
| 3268 | |||
| 3269 | 'cancel', // TODO: might be useful |
||
| 3270 | |||
| 3271 | /** |
||
| 3272 | Dispatched when mouse cursor enters file-picker area. Can be used to style element |
||
| 3273 | accordingly. |
||
| 3274 | |||
| 3275 | @event mouseenter |
||
| 3276 | @param {Object} event |
||
| 3277 | */ |
||
| 3278 | 'mouseenter', |
||
| 3279 | |||
| 3280 | /** |
||
| 3281 | Dispatched when mouse cursor leaves file-picker area. Can be used to style element |
||
| 3282 | accordingly. |
||
| 3283 | |||
| 3284 | @event mouseleave |
||
| 3285 | @param {Object} event |
||
| 3286 | */ |
||
| 3287 | 'mouseleave', |
||
| 3288 | |||
| 3289 | /** |
||
| 3290 | Dispatched when functional mouse button is pressed on top of file-picker area. |
||
| 3291 | |||
| 3292 | @event mousedown |
||
| 3293 | @param {Object} event |
||
| 3294 | */ |
||
| 3295 | 'mousedown', |
||
| 3296 | |||
| 3297 | /** |
||
| 3298 | Dispatched when functional mouse button is released on top of file-picker area. |
||
| 3299 | |||
| 3300 | @event mouseup |
||
| 3301 | @param {Object} event |
||
| 3302 | */ |
||
| 3303 | 'mouseup' |
||
| 3304 | ]; |
||
| 3305 | |||
| 3306 | function FileInput(options) { |
||
| 3307 | var self = this, |
||
| 3308 | container, browseButton, defaults; |
||
| 3309 | |||
| 3310 | // if flat argument passed it should be browse_button id |
||
| 3311 | if (Basic.inArray(Basic.typeOf(options), ['string', 'node']) !== -1) { |
||
| 3312 | options = { browse_button : options }; |
||
| 3313 | } |
||
| 3314 | |||
| 3315 | // this will help us to find proper default container |
||
| 3316 | browseButton = Dom.get(options.browse_button); |
||
| 3317 | if (!browseButton) { |
||
| 3318 | // browse button is required |
||
| 3319 | throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); |
||
| 3320 | } |
||
| 3321 | |||
| 3322 | // figure out the options |
||
| 3323 | defaults = { |
||
| 3324 | accept: [{ |
||
| 3325 | title: I18n.translate('All Files'), |
||
| 3326 | extensions: '*' |
||
| 3327 | }], |
||
| 3328 | name: 'file', |
||
| 3329 | multiple: false, |
||
| 3330 | required_caps: false, |
||
| 3331 | container: browseButton.parentNode || document.body |
||
| 3332 | }; |
||
| 3333 | |||
| 3334 | options = Basic.extend({}, defaults, options); |
||
| 3335 | |||
| 3336 | // convert to object representation |
||
| 3337 | if (typeof(options.required_caps) === 'string') { |
||
| 3338 | options.required_caps = Runtime.parseCaps(options.required_caps); |
||
| 3339 | } |
||
| 3340 | |||
| 3341 | // normalize accept option (could be list of mime types or array of title/extensions pairs) |
||
| 3342 | if (typeof(options.accept) === 'string') { |
||
| 3343 | options.accept = Mime.mimes2extList(options.accept); |
||
| 3344 | } |
||
| 3345 | |||
| 3346 | container = Dom.get(options.container); |
||
| 3347 | // make sure we have container |
||
| 3348 | if (!container) { |
||
| 3349 | container = document.body; |
||
| 3350 | } |
||
| 3351 | |||
| 3352 | // make container relative, if it's not |
||
| 3353 | if (Dom.getStyle(container, 'position') === 'static') { |
||
| 3354 | container.style.position = 'relative'; |
||
| 3355 | } |
||
| 3356 | |||
| 3357 | container = browseButton = null; // IE |
||
| 3358 | |||
| 3359 | RuntimeClient.call(self); |
||
| 3360 | |||
| 3361 | Basic.extend(self, { |
||
| 3362 | /** |
||
| 3363 | Unique id of the component |
||
| 3364 | |||
| 3365 | @property uid |
||
| 3366 | @protected |
||
| 3367 | @readOnly |
||
| 3368 | @type {String} |
||
| 3369 | @default UID |
||
| 3370 | */ |
||
| 3371 | uid: Basic.guid('uid_'), |
||
| 3372 | |||
| 3373 | /** |
||
| 3374 | Unique id of the connected runtime, if any. |
||
| 3375 | |||
| 3376 | @property ruid |
||
| 3377 | @protected |
||
| 3378 | @type {String} |
||
| 3379 | */ |
||
| 3380 | ruid: null, |
||
| 3381 | |||
| 3382 | /** |
||
| 3383 | Unique id of the runtime container. Useful to get hold of it for various manipulations. |
||
| 3384 | |||
| 3385 | @property shimid |
||
| 3386 | @protected |
||
| 3387 | @type {String} |
||
| 3388 | */ |
||
| 3389 | shimid: null, |
||
| 3390 | |||
| 3391 | /** |
||
| 3392 | Array of selected mOxie.File objects |
||
| 3393 | |||
| 3394 | @property files |
||
| 3395 | @type {Array} |
||
| 3396 | @default null |
||
| 3397 | */ |
||
| 3398 | files: null, |
||
| 3399 | |||
| 3400 | /** |
||
| 3401 | Initializes the file-picker, connects it to runtime and dispatches event ready when done. |
||
| 3402 | |||
| 3403 | @method init |
||
| 3404 | */ |
||
| 3405 | init: function() { |
||
| 3406 | self.convertEventPropsToHandlers(dispatches); |
||
| 3407 | |||
| 3408 | self.bind('RuntimeInit', function(e, runtime) { |
||
| 3409 | self.ruid = runtime.uid; |
||
| 3410 | self.shimid = runtime.shimid; |
||
| 3411 | |||
| 3412 | self.bind("Ready", function() { |
||
| 3413 | self.trigger("Refresh"); |
||
| 3414 | }, 999); |
||
| 3415 | |||
| 3416 | self.bind("Change", function() { |
||
| 3417 | var files = runtime.exec.call(self, 'FileInput', 'getFiles'); |
||
| 3418 | |||
| 3419 | self.files = []; |
||
| 3420 | |||
| 3421 | Basic.each(files, function(file) { |
||
| 3422 | // ignore empty files (IE10 for example hangs if you try to send them via XHR) |
||
| 3423 | if (file.size === 0) { |
||
| 3424 | return true; |
||
| 3425 | } |
||
| 3426 | self.files.push(new File(self.ruid, file)); |
||
| 3427 | }); |
||
| 3428 | }, 999); |
||
| 3429 | |||
| 3430 | // re-position and resize shim container |
||
| 3431 | self.bind('Refresh', function() { |
||
| 3432 | var pos, size, browseButton, shimContainer; |
||
| 3433 | |||
| 3434 | browseButton = Dom.get(options.browse_button); |
||
| 3435 | shimContainer = Dom.get(runtime.shimid); // do not use runtime.getShimContainer(), since it will create container if it doesn't exist |
||
| 3436 | |||
| 3437 | if (browseButton) { |
||
| 3438 | pos = Dom.getPos(browseButton, Dom.get(options.container)); |
||
| 3439 | size = Dom.getSize(browseButton); |
||
| 3440 | |||
| 3441 | if (shimContainer) { |
||
| 3442 | Basic.extend(shimContainer.style, { |
||
| 3443 | top : pos.y + 'px', |
||
| 3444 | left : pos.x + 'px', |
||
| 3445 | width : size.w + 'px', |
||
| 3446 | height : size.h + 'px' |
||
| 3447 | }); |
||
| 3448 | } |
||
| 3449 | } |
||
| 3450 | shimContainer = browseButton = null; |
||
| 3451 | }); |
||
| 3452 | |||
| 3453 | runtime.exec.call(self, 'FileInput', 'init', options); |
||
| 3454 | }); |
||
| 3455 | |||
| 3456 | // runtime needs: options.required_features, options.runtime_order and options.container |
||
| 3457 | self.connectRuntime(Basic.extend({}, options, { |
||
| 3458 | required_caps: { |
||
| 3459 | select_file: true |
||
| 3460 | } |
||
| 3461 | })); |
||
| 3462 | }, |
||
| 3463 | |||
| 3464 | /** |
||
| 3465 | Disables file-picker element, so that it doesn't react to mouse clicks. |
||
| 3466 | |||
| 3467 | @method disable |
||
| 3468 | @param {Boolean} [state=true] Disable component if - true, enable if - false |
||
| 3469 | */ |
||
| 3470 | disable: function(state) { |
||
| 3471 | var runtime = this.getRuntime(); |
||
| 3472 | if (runtime) { |
||
| 3473 | runtime.exec.call(this, 'FileInput', 'disable', Basic.typeOf(state) === 'undefined' ? true : state); |
||
| 3474 | } |
||
| 3475 | }, |
||
| 3476 | |||
| 3477 | |||
| 3478 | /** |
||
| 3479 | Reposition and resize dialog trigger to match the position and size of browse_button element. |
||
| 3480 | |||
| 3481 | @method refresh |
||
| 3482 | */ |
||
| 3483 | refresh: function() { |
||
| 3484 | self.trigger("Refresh"); |
||
| 3485 | }, |
||
| 3486 | |||
| 3487 | |||
| 3488 | /** |
||
| 3489 | Destroy component. |
||
| 3490 | |||
| 3491 | @method destroy |
||
| 3492 | */ |
||
| 3493 | destroy: function() { |
||
| 3494 | var runtime = this.getRuntime(); |
||
| 3495 | if (runtime) { |
||
| 3496 | runtime.exec.call(this, 'FileInput', 'destroy'); |
||
| 3497 | this.disconnectRuntime(); |
||
| 3498 | } |
||
| 3499 | |||
| 3500 | if (Basic.typeOf(this.files) === 'array') { |
||
| 3501 | // no sense in leaving associated files behind |
||
| 3502 | Basic.each(this.files, function(file) { |
||
| 3503 | file.destroy(); |
||
| 3504 | }); |
||
| 3505 | } |
||
| 3506 | this.files = null; |
||
| 3507 | } |
||
| 3508 | }); |
||
| 3509 | } |
||
| 3510 | |||
| 3511 | FileInput.prototype = EventTarget.instance; |
||
| 3512 | |||
| 3513 | return FileInput; |
||
| 3514 | }); |
||
| 3515 | |||
| 3516 | // Included from: src/javascript/file/FileDrop.js |
||
| 3517 | |||
| 3518 | /** |
||
| 3519 | * FileDrop.js |
||
| 3520 | * |
||
| 3521 | * Copyright 2013, Moxiecode Systems AB |
||
| 3522 | * Released under GPL License. |
||
| 3523 | * |
||
| 3524 | * License: http://www.plupload.com/license |
||
| 3525 | * Contributing: http://www.plupload.com/contributing |
||
| 3526 | */ |
||
| 3527 | |||
| 3528 | define('moxie/file/FileDrop', [ |
||
| 3529 | 'moxie/core/I18n', |
||
| 3530 | 'moxie/core/utils/Dom', |
||
| 3531 | 'moxie/core/Exceptions', |
||
| 3532 | 'moxie/core/utils/Basic', |
||
| 3533 | 'moxie/file/File', |
||
| 3534 | 'moxie/runtime/RuntimeClient', |
||
| 3535 | 'moxie/core/EventTarget', |
||
| 3536 | 'moxie/core/utils/Mime' |
||
| 3537 | ], function(I18n, Dom, x, Basic, File, RuntimeClient, EventTarget, Mime) { |
||
| 3538 | /** |
||
| 3539 | Turn arbitrary DOM element to a drop zone accepting files. Converts selected files to _File_ objects, to be used |
||
| 3540 | in conjunction with _Image_, preloaded in memory with _FileReader_ or uploaded to a server through |
||
| 3541 | _XMLHttpRequest_. |
||
| 3542 | |||
| 3543 | @example |
||
| 3544 | <div id="drop_zone"> |
||
| 3545 | Drop files here |
||
| 3546 | </div> |
||
| 3547 | <br /> |
||
| 3548 | <div id="filelist"></div> |
||
| 3549 | |||
| 3550 | <script type="text/javascript"> |
||
| 3551 | var fileDrop = new mOxie.FileDrop('drop_zone'), fileList = mOxie.get('filelist'); |
||
| 3552 | |||
| 3553 | fileDrop.ondrop = function() { |
||
| 3554 | mOxie.each(this.files, function(file) { |
||
| 3555 | fileList.innerHTML += '<div>' + file.name + '</div>'; |
||
| 3556 | }); |
||
| 3557 | }; |
||
| 3558 | |||
| 3559 | fileDrop.init(); |
||
| 3560 | </script> |
||
| 3561 | |||
| 3562 | @class FileDrop |
||
| 3563 | @constructor |
||
| 3564 | @extends EventTarget |
||
| 3565 | @uses RuntimeClient |
||
| 3566 | @param {Object|String} options If options has typeof string, argument is considered as options.drop_zone |
||
| 3567 | @param {String|DOMElement} options.drop_zone DOM Element to turn into a drop zone |
||
| 3568 | @param {Array} [options.accept] Array of mime types to accept. By default accepts all |
||
| 3569 | @param {Object|String} [options.required_caps] Set of required capabilities, that chosen runtime must support |
||
| 3570 | */ |
||
| 3571 | var dispatches = [ |
||
| 3572 | /** |
||
| 3573 | Dispatched when runtime is connected and drop zone is ready to accept files. |
||
| 3574 | |||
| 3575 | @event ready |
||
| 3576 | @param {Object} event |
||
| 3577 | */ |
||
| 3578 | 'ready', |
||
| 3579 | |||
| 3580 | /** |
||
| 3581 | Dispatched when dragging cursor enters the drop zone. |
||
| 3582 | |||
| 3583 | @event dragenter |
||
| 3584 | @param {Object} event |
||
| 3585 | */ |
||
| 3586 | 'dragenter', |
||
| 3587 | |||
| 3588 | /** |
||
| 3589 | Dispatched when dragging cursor leaves the drop zone. |
||
| 3590 | |||
| 3591 | @event dragleave |
||
| 3592 | @param {Object} event |
||
| 3593 | */ |
||
| 3594 | 'dragleave', |
||
| 3595 | |||
| 3596 | /** |
||
| 3597 | Dispatched when file is dropped onto the drop zone. |
||
| 3598 | |||
| 3599 | @event drop |
||
| 3600 | @param {Object} event |
||
| 3601 | */ |
||
| 3602 | 'drop', |
||
| 3603 | |||
| 3604 | /** |
||
| 3605 | Dispatched if error occurs. |
||
| 3606 | |||
| 3607 | @event error |
||
| 3608 | @param {Object} event |
||
| 3609 | */ |
||
| 3610 | 'error' |
||
| 3611 | ]; |
||
| 3612 | |||
| 3613 | function FileDrop(options) { |
||
| 3614 | var self = this, defaults; |
||
| 3615 | |||
| 3616 | // if flat argument passed it should be drop_zone id |
||
| 3617 | if (typeof(options) === 'string') { |
||
| 3618 | options = { drop_zone : options }; |
||
| 3619 | } |
||
| 3620 | |||
| 3621 | // figure out the options |
||
| 3622 | defaults = { |
||
| 3623 | accept: [{ |
||
| 3624 | title: I18n.translate('All Files'), |
||
| 3625 | extensions: '*' |
||
| 3626 | }], |
||
| 3627 | required_caps: { |
||
| 3628 | drag_and_drop: true |
||
| 3629 | } |
||
| 3630 | }; |
||
| 3631 | |||
| 3632 | options = typeof(options) === 'object' ? Basic.extend({}, defaults, options) : defaults; |
||
| 3633 | |||
| 3634 | // this will help us to find proper default container |
||
| 3635 | options.container = Dom.get(options.drop_zone) || document.body; |
||
| 3636 | |||
| 3637 | // make container relative, if it is not |
||
| 3638 | if (Dom.getStyle(options.container, 'position') === 'static') { |
||
| 3639 | options.container.style.position = 'relative'; |
||
| 3640 | } |
||
| 3641 | |||
| 3642 | // normalize accept option (could be list of mime types or array of title/extensions pairs) |
||
| 3643 | if (typeof(options.accept) === 'string') { |
||
| 3644 | options.accept = Mime.mimes2extList(options.accept); |
||
| 3645 | } |
||
| 3646 | |||
| 3647 | RuntimeClient.call(self); |
||
| 3648 | |||
| 3649 | Basic.extend(self, { |
||
| 3650 | uid: Basic.guid('uid_'), |
||
| 3651 | |||
| 3652 | ruid: null, |
||
| 3653 | |||
| 3654 | files: null, |
||
| 3655 | |||
| 3656 | init: function() { |
||
| 3657 | |||
| 3658 | self.convertEventPropsToHandlers(dispatches); |
||
| 3659 | |||
| 3660 | self.bind('RuntimeInit', function(e, runtime) { |
||
| 3661 | self.ruid = runtime.uid; |
||
| 3662 | |||
| 3663 | self.bind("Drop", function() { |
||
| 3664 | var files = runtime.exec.call(self, 'FileDrop', 'getFiles'); |
||
| 3665 | |||
| 3666 | self.files = []; |
||
| 3667 | |||
| 3668 | Basic.each(files, function(file) { |
||
| 3669 | self.files.push(new File(self.ruid, file)); |
||
| 3670 | }); |
||
| 3671 | }, 999); |
||
| 3672 | |||
| 3673 | runtime.exec.call(self, 'FileDrop', 'init', options); |
||
| 3674 | |||
| 3675 | self.dispatchEvent('ready'); |
||
| 3676 | }); |
||
| 3677 | |||
| 3678 | // runtime needs: options.required_features, options.runtime_order and options.container |
||
| 3679 | self.connectRuntime(options); // throws RuntimeError |
||
| 3680 | }, |
||
| 3681 | |||
| 3682 | destroy: function() { |
||
| 3683 | var runtime = this.getRuntime(); |
||
| 3684 | if (runtime) { |
||
| 3685 | runtime.exec.call(this, 'FileDrop', 'destroy'); |
||
| 3686 | this.disconnectRuntime(); |
||
| 3687 | } |
||
| 3688 | this.files = null; |
||
| 3689 | } |
||
| 3690 | }); |
||
| 3691 | } |
||
| 3692 | |||
| 3693 | FileDrop.prototype = EventTarget.instance; |
||
| 3694 | |||
| 3695 | return FileDrop; |
||
| 3696 | }); |
||
| 3697 | |||
| 3698 | // Included from: src/javascript/runtime/RuntimeTarget.js |
||
| 3699 | |||
| 3700 | /** |
||
| 3701 | * RuntimeTarget.js |
||
| 3702 | * |
||
| 3703 | * Copyright 2013, Moxiecode Systems AB |
||
| 3704 | * Released under GPL License. |
||
| 3705 | * |
||
| 3706 | * License: http://www.plupload.com/license |
||
| 3707 | * Contributing: http://www.plupload.com/contributing |
||
| 3708 | */ |
||
| 3709 | |||
| 3710 | define('moxie/runtime/RuntimeTarget', [ |
||
| 3711 | 'moxie/core/utils/Basic', |
||
| 3712 | 'moxie/runtime/RuntimeClient', |
||
| 3713 | "moxie/core/EventTarget" |
||
| 3714 | ], function(Basic, RuntimeClient, EventTarget) { |
||
| 3715 | /** |
||
| 3716 | Instance of this class can be used as a target for the events dispatched by shims, |
||
| 3717 | when allowing them onto components is for either reason inappropriate |
||
| 3718 | |||
| 3719 | @class RuntimeTarget |
||
| 3720 | @constructor |
||
| 3721 | @protected |
||
| 3722 | @extends EventTarget |
||
| 3723 | */ |
||
| 3724 | function RuntimeTarget() { |
||
| 3725 | this.uid = Basic.guid('uid_'); |
||
| 3726 | |||
| 3727 | RuntimeClient.call(this); |
||
| 3728 | |||
| 3729 | this.destroy = function() { |
||
| 3730 | this.disconnectRuntime(); |
||
| 3731 | this.unbindAll(); |
||
| 3732 | }; |
||
| 3733 | } |
||
| 3734 | |||
| 3735 | RuntimeTarget.prototype = EventTarget.instance; |
||
| 3736 | |||
| 3737 | return RuntimeTarget; |
||
| 3738 | }); |
||
| 3739 | |||
| 3740 | // Included from: src/javascript/file/FileReader.js |
||
| 3741 | |||
| 3742 | /** |
||
| 3743 | * FileReader.js |
||
| 3744 | * |
||
| 3745 | * Copyright 2013, Moxiecode Systems AB |
||
| 3746 | * Released under GPL License. |
||
| 3747 | * |
||
| 3748 | * License: http://www.plupload.com/license |
||
| 3749 | * Contributing: http://www.plupload.com/contributing |
||
| 3750 | */ |
||
| 3751 | |||
| 3752 | define('moxie/file/FileReader', [ |
||
| 3753 | 'moxie/core/utils/Basic', |
||
| 3754 | 'moxie/core/utils/Encode', |
||
| 3755 | 'moxie/core/Exceptions', |
||
| 3756 | 'moxie/core/EventTarget', |
||
| 3757 | 'moxie/file/Blob', |
||
| 3758 | 'moxie/file/File', |
||
| 3759 | 'moxie/runtime/RuntimeTarget' |
||
| 3760 | ], function(Basic, Encode, x, EventTarget, Blob, File, RuntimeTarget) { |
||
| 3761 | /** |
||
| 3762 | Utility for preloading o.Blob/o.File objects in memory. By design closely follows [W3C FileReader](http://www.w3.org/TR/FileAPI/#dfn-filereader) |
||
| 3763 | interface. Where possible uses native FileReader, where - not falls back to shims. |
||
| 3764 | |||
| 3765 | @class FileReader |
||
| 3766 | @constructor FileReader |
||
| 3767 | @extends EventTarget |
||
| 3768 | @uses RuntimeClient |
||
| 3769 | */ |
||
| 3770 | var dispatches = [ |
||
| 3771 | |||
| 3772 | /** |
||
| 3773 | Dispatched when the read starts. |
||
| 3774 | |||
| 3775 | @event loadstart |
||
| 3776 | @param {Object} event |
||
| 3777 | */ |
||
| 3778 | 'loadstart', |
||
| 3779 | |||
| 3780 | /** |
||
| 3781 | Dispatched while reading (and decoding) blob, and reporting partial Blob data (progess.loaded/progress.total). |
||
| 3782 | |||
| 3783 | @event progress |
||
| 3784 | @param {Object} event |
||
| 3785 | */ |
||
| 3786 | 'progress', |
||
| 3787 | |||
| 3788 | /** |
||
| 3789 | Dispatched when the read has successfully completed. |
||
| 3790 | |||
| 3791 | @event load |
||
| 3792 | @param {Object} event |
||
| 3793 | */ |
||
| 3794 | 'load', |
||
| 3795 | |||
| 3796 | /** |
||
| 3797 | Dispatched when the read has been aborted. For instance, by invoking the abort() method. |
||
| 3798 | |||
| 3799 | @event abort |
||
| 3800 | @param {Object} event |
||
| 3801 | */ |
||
| 3802 | 'abort', |
||
| 3803 | |||
| 3804 | /** |
||
| 3805 | Dispatched when the read has failed. |
||
| 3806 | |||
| 3807 | @event error |
||
| 3808 | @param {Object} event |
||
| 3809 | */ |
||
| 3810 | 'error', |
||
| 3811 | |||
| 3812 | /** |
||
| 3813 | Dispatched when the request has completed (either in success or failure). |
||
| 3814 | |||
| 3815 | @event loadend |
||
| 3816 | @param {Object} event |
||
| 3817 | */ |
||
| 3818 | 'loadend' |
||
| 3819 | ]; |
||
| 3820 | |||
| 3821 | function FileReader() { |
||
| 3822 | var self = this, _fr; |
||
| 3823 | |||
| 3824 | Basic.extend(this, { |
||
| 3825 | /** |
||
| 3826 | UID of the component instance. |
||
| 3827 | |||
| 3828 | @property uid |
||
| 3829 | @type {String} |
||
| 3830 | */ |
||
| 3831 | uid: Basic.guid('uid_'), |
||
| 3832 | |||
| 3833 | /** |
||
| 3834 | Contains current state of FileReader object. Can take values of FileReader.EMPTY, FileReader.LOADING |
||
| 3835 | and FileReader.DONE. |
||
| 3836 | |||
| 3837 | @property readyState |
||
| 3838 | @type {Number} |
||
| 3839 | @default FileReader.EMPTY |
||
| 3840 | */ |
||
| 3841 | readyState: FileReader.EMPTY, |
||
| 3842 | |||
| 3843 | /** |
||
| 3844 | Result of the successful read operation. |
||
| 3845 | |||
| 3846 | @property result |
||
| 3847 | @type {String} |
||
| 3848 | */ |
||
| 3849 | result: null, |
||
| 3850 | |||
| 3851 | /** |
||
| 3852 | Stores the error of failed asynchronous read operation. |
||
| 3853 | |||
| 3854 | @property error |
||
| 3855 | @type {DOMError} |
||
| 3856 | */ |
||
| 3857 | error: null, |
||
| 3858 | |||
| 3859 | /** |
||
| 3860 | Initiates reading of File/Blob object contents to binary string. |
||
| 3861 | |||
| 3862 | @method readAsBinaryString |
||
| 3863 | @param {Blob|File} blob Object to preload |
||
| 3864 | */ |
||
| 3865 | readAsBinaryString: function(blob) { |
||
| 3866 | _read.call(this, 'readAsBinaryString', blob); |
||
| 3867 | }, |
||
| 3868 | |||
| 3869 | /** |
||
| 3870 | Initiates reading of File/Blob object contents to dataURL string. |
||
| 3871 | |||
| 3872 | @method readAsDataURL |
||
| 3873 | @param {Blob|File} blob Object to preload |
||
| 3874 | */ |
||
| 3875 | readAsDataURL: function(blob) { |
||
| 3876 | _read.call(this, 'readAsDataURL', blob); |
||
| 3877 | }, |
||
| 3878 | |||
| 3879 | /** |
||
| 3880 | Initiates reading of File/Blob object contents to string. |
||
| 3881 | |||
| 3882 | @method readAsText |
||
| 3883 | @param {Blob|File} blob Object to preload |
||
| 3884 | */ |
||
| 3885 | readAsText: function(blob) { |
||
| 3886 | _read.call(this, 'readAsText', blob); |
||
| 3887 | }, |
||
| 3888 | |||
| 3889 | /** |
||
| 3890 | Aborts preloading process. |
||
| 3891 | |||
| 3892 | @method abort |
||
| 3893 | */ |
||
| 3894 | abort: function() { |
||
| 3895 | this.result = null; |
||
| 3896 | |||
| 3897 | if (Basic.inArray(this.readyState, [FileReader.EMPTY, FileReader.DONE]) !== -1) { |
||
| 3898 | return; |
||
| 3899 | } else if (this.readyState === FileReader.LOADING) { |
||
| 3900 | this.readyState = FileReader.DONE; |
||
| 3901 | } |
||
| 3902 | |||
| 3903 | if (_fr) { |
||
| 3904 | _fr.getRuntime().exec.call(this, 'FileReader', 'abort'); |
||
| 3905 | } |
||
| 3906 | |||
| 3907 | this.trigger('abort'); |
||
| 3908 | this.trigger('loadend'); |
||
| 3909 | }, |
||
| 3910 | |||
| 3911 | /** |
||
| 3912 | Destroy component and release resources. |
||
| 3913 | |||
| 3914 | @method destroy |
||
| 3915 | */ |
||
| 3916 | destroy: function() { |
||
| 3917 | this.abort(); |
||
| 3918 | |||
| 3919 | if (_fr) { |
||
| 3920 | _fr.getRuntime().exec.call(this, 'FileReader', 'destroy'); |
||
| 3921 | _fr.disconnectRuntime(); |
||
| 3922 | } |
||
| 3923 | |||
| 3924 | self = _fr = null; |
||
| 3925 | } |
||
| 3926 | }); |
||
| 3927 | |||
| 3928 | |||
| 3929 | function _read(op, blob) { |
||
| 3930 | _fr = new RuntimeTarget(); |
||
| 3931 | |||
| 3932 | function error(err) { |
||
| 3933 | self.readyState = FileReader.DONE; |
||
| 3934 | self.error = err; |
||
| 3935 | self.trigger('error'); |
||
| 3936 | loadEnd(); |
||
| 3937 | } |
||
| 3938 | |||
| 3939 | function loadEnd() { |
||
| 3940 | _fr.destroy(); |
||
| 3941 | _fr = null; |
||
| 3942 | self.trigger('loadend'); |
||
| 3943 | } |
||
| 3944 | |||
| 3945 | function exec(runtime) { |
||
| 3946 | _fr.bind('Error', function(e, err) { |
||
| 3947 | error(err); |
||
| 3948 | }); |
||
| 3949 | |||
| 3950 | _fr.bind('Progress', function(e) { |
||
| 3951 | self.result = runtime.exec.call(_fr, 'FileReader', 'getResult'); |
||
| 3952 | self.trigger(e); |
||
| 3953 | }); |
||
| 3954 | |||
| 3955 | _fr.bind('Load', function(e) { |
||
| 3956 | self.readyState = FileReader.DONE; |
||
| 3957 | self.result = runtime.exec.call(_fr, 'FileReader', 'getResult'); |
||
| 3958 | self.trigger(e); |
||
| 3959 | loadEnd(); |
||
| 3960 | }); |
||
| 3961 | |||
| 3962 | runtime.exec.call(_fr, 'FileReader', 'read', op, blob); |
||
| 3963 | } |
||
| 3964 | |||
| 3965 | this.convertEventPropsToHandlers(dispatches); |
||
| 3966 | |||
| 3967 | if (this.readyState === FileReader.LOADING) { |
||
| 3968 | return error(new x.DOMException(x.DOMException.INVALID_STATE_ERR)); |
||
| 3969 | } |
||
| 3970 | |||
| 3971 | this.readyState = FileReader.LOADING; |
||
| 3972 | this.trigger('loadstart'); |
||
| 3973 | |||
| 3974 | // if source is o.Blob/o.File |
||
| 3975 | if (blob instanceof Blob) { |
||
| 3976 | if (blob.isDetached()) { |
||
| 3977 | var src = blob.getSource(); |
||
| 3978 | switch (op) { |
||
| 3979 | case 'readAsText': |
||
| 3980 | case 'readAsBinaryString': |
||
| 3981 | this.result = src; |
||
| 3982 | break; |
||
| 3983 | case 'readAsDataURL': |
||
| 3984 | this.result = 'data:' + blob.type + ';base64,' + Encode.btoa(src); |
||
| 3985 | break; |
||
| 3986 | } |
||
| 3987 | this.readyState = FileReader.DONE; |
||
| 3988 | this.trigger('load'); |
||
| 3989 | loadEnd(); |
||
| 3990 | } else { |
||
| 3991 | exec(_fr.connectRuntime(blob.ruid)); |
||
| 3992 | } |
||
| 3993 | } else { |
||
| 3994 | error(new x.DOMException(x.DOMException.NOT_FOUND_ERR)); |
||
| 3995 | } |
||
| 3996 | } |
||
| 3997 | } |
||
| 3998 | |||
| 3999 | /** |
||
| 4000 | Initial FileReader state |
||
| 4001 | |||
| 4002 | @property EMPTY |
||
| 4003 | @type {Number} |
||
| 4004 | @final |
||
| 4005 | @static |
||
| 4006 | @default 0 |
||
| 4007 | */ |
||
| 4008 | FileReader.EMPTY = 0; |
||
| 4009 | |||
| 4010 | /** |
||
| 4011 | FileReader switches to this state when it is preloading the source |
||
| 4012 | |||
| 4013 | @property LOADING |
||
| 4014 | @type {Number} |
||
| 4015 | @final |
||
| 4016 | @static |
||
| 4017 | @default 1 |
||
| 4018 | */ |
||
| 4019 | FileReader.LOADING = 1; |
||
| 4020 | |||
| 4021 | /** |
||
| 4022 | Preloading is complete, this is a final state |
||
| 4023 | |||
| 4024 | @property DONE |
||
| 4025 | @type {Number} |
||
| 4026 | @final |
||
| 4027 | @static |
||
| 4028 | @default 2 |
||
| 4029 | */ |
||
| 4030 | FileReader.DONE = 2; |
||
| 4031 | |||
| 4032 | FileReader.prototype = EventTarget.instance; |
||
| 4033 | |||
| 4034 | return FileReader; |
||
| 4035 | }); |
||
| 4036 | |||
| 4037 | // Included from: src/javascript/core/utils/Url.js |
||
| 4038 | |||
| 4039 | /** |
||
| 4040 | * Url.js |
||
| 4041 | * |
||
| 4042 | * Copyright 2013, Moxiecode Systems AB |
||
| 4043 | * Released under GPL License. |
||
| 4044 | * |
||
| 4045 | * License: http://www.plupload.com/license |
||
| 4046 | * Contributing: http://www.plupload.com/contributing |
||
| 4047 | */ |
||
| 4048 | |||
| 4049 | define('moxie/core/utils/Url', [], function() { |
||
| 4050 | /** |
||
| 4051 | Parse url into separate components and fill in absent parts with parts from current url, |
||
| 4052 | based on https://raw.github.com/kvz/phpjs/master/functions/url/parse_url.js |
||
| 4053 | |||
| 4054 | @method parseUrl |
||
| 4055 | @for Utils |
||
| 4056 | @static |
||
| 4057 | @param {String} url Url to parse (defaults to empty string if undefined) |
||
| 4058 | @return {Object} Hash containing extracted uri components |
||
| 4059 | */ |
||
| 4060 | var parseUrl = function(url, currentUrl) { |
||
| 4061 | var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'] |
||
| 4062 | , i = key.length |
||
| 4063 | , ports = { |
||
| 4064 | http: 80, |
||
| 4065 | https: 443 |
||
| 4066 | } |
||
| 4067 | , uri = {} |
||
| 4068 | , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/ |
||
| 4069 | , m = regex.exec(url || '') |
||
| 4070 | ; |
||
| 4071 | |||
| 4072 | while (i--) { |
||
| 4073 | if (m[i]) { |
||
| 4074 | uri[key[i]] = m[i]; |
||
| 4075 | } |
||
| 4076 | } |
||
| 4077 | |||
| 4078 | // when url is relative, we set the origin and the path ourselves |
||
| 4079 | if (!uri.scheme) { |
||
| 4080 | // come up with defaults |
||
| 4081 | if (!currentUrl || typeof(currentUrl) === 'string') { |
||
| 4082 | currentUrl = parseUrl(currentUrl || document.location.href); |
||
| 4083 | } |
||
| 4084 | |||
| 4085 | uri.scheme = currentUrl.scheme; |
||
| 4086 | uri.host = currentUrl.host; |
||
| 4087 | uri.port = currentUrl.port; |
||
| 4088 | |||
| 4089 | var path = ''; |
||
| 4090 | // for urls without trailing slash we need to figure out the path |
||
| 4091 | if (/^[^\/]/.test(uri.path)) { |
||
| 4092 | path = currentUrl.path; |
||
| 4093 | // if path ends with a filename, strip it |
||
| 4094 | if (!/(\/|\/[^\.]+)$/.test(path)) { |
||
| 4095 | path = path.replace(/\/[^\/]+$/, '/'); |
||
| 4096 | } else { |
||
| 4097 | path += '/'; |
||
| 4098 | } |
||
| 4099 | } |
||
| 4100 | uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir |
||
| 4101 | } |
||
| 4102 | |||
| 4103 | if (!uri.port) { |
||
| 4104 | uri.port = ports[uri.scheme] || 80; |
||
| 4105 | } |
||
| 4106 | |||
| 4107 | uri.port = parseInt(uri.port, 10); |
||
| 4108 | |||
| 4109 | if (!uri.path) { |
||
| 4110 | uri.path = "/"; |
||
| 4111 | } |
||
| 4112 | |||
| 4113 | delete uri.source; |
||
| 4114 | |||
| 4115 | return uri; |
||
| 4116 | }; |
||
| 4117 | |||
| 4118 | /** |
||
| 4119 | Resolve url - among other things will turn relative url to absolute |
||
| 4120 | |||
| 4121 | @method resolveUrl |
||
| 4122 | @static |
||
| 4123 | @param {String} url Either absolute or relative |
||
| 4124 | @return {String} Resolved, absolute url |
||
| 4125 | */ |
||
| 4126 | var resolveUrl = function(url) { |
||
| 4127 | var ports = { // we ignore default ports |
||
| 4128 | http: 80, |
||
| 4129 | https: 443 |
||
| 4130 | } |
||
| 4131 | , urlp = parseUrl(url) |
||
| 4132 | ; |
||
| 4133 | |||
| 4134 | return urlp.scheme + '://' + urlp.host + (urlp.port !== ports[urlp.scheme] ? ':' + urlp.port : '') + urlp.path + (urlp.query ? urlp.query : ''); |
||
| 4135 | }; |
||
| 4136 | |||
| 4137 | /** |
||
| 4138 | Check if specified url has the same origin as the current document |
||
| 4139 | |||
| 4140 | @method hasSameOrigin |
||
| 4141 | @param {String|Object} url |
||
| 4142 | @return {Boolean} |
||
| 4143 | */ |
||
| 4144 | var hasSameOrigin = function(url) { |
||
| 4145 | function origin(url) { |
||
| 4146 | return [url.scheme, url.host, url.port].join('/'); |
||
| 4147 | } |
||
| 4148 | |||
| 4149 | if (typeof url === 'string') { |
||
| 4150 | url = parseUrl(url); |
||
| 4151 | } |
||
| 4152 | |||
| 4153 | return origin(parseUrl()) === origin(url); |
||
| 4154 | }; |
||
| 4155 | |||
| 4156 | return { |
||
| 4157 | parseUrl: parseUrl, |
||
| 4158 | resolveUrl: resolveUrl, |
||
| 4159 | hasSameOrigin: hasSameOrigin |
||
| 4160 | }; |
||
| 4161 | }); |
||
| 4162 | |||
| 4163 | // Included from: src/javascript/file/FileReaderSync.js |
||
| 4164 | |||
| 4165 | /** |
||
| 4166 | * FileReaderSync.js |
||
| 4167 | * |
||
| 4168 | * Copyright 2013, Moxiecode Systems AB |
||
| 4169 | * Released under GPL License. |
||
| 4170 | * |
||
| 4171 | * License: http://www.plupload.com/license |
||
| 4172 | * Contributing: http://www.plupload.com/contributing |
||
| 4173 | */ |
||
| 4174 | |||
| 4175 | define('moxie/file/FileReaderSync', [ |
||
| 4176 | 'moxie/core/utils/Basic', |
||
| 4177 | 'moxie/runtime/RuntimeClient', |
||
| 4178 | 'moxie/core/utils/Encode' |
||
| 4179 | ], function(Basic, RuntimeClient, Encode) { |
||
| 4180 | /** |
||
| 4181 | Synchronous FileReader implementation. Something like this is available in WebWorkers environment, here |
||
| 4182 | it can be used to read only preloaded blobs/files and only below certain size (not yet sure what that'd be, |
||
| 4183 | but probably < 1mb). Not meant to be used directly by user. |
||
| 4184 | |||
| 4185 | @class FileReaderSync |
||
| 4186 | @private |
||
| 4187 | @constructor |
||
| 4188 | */ |
||
| 4189 | return function() { |
||
| 4190 | RuntimeClient.call(this); |
||
| 4191 | |||
| 4192 | Basic.extend(this, { |
||
| 4193 | uid: Basic.guid('uid_'), |
||
| 4194 | |||
| 4195 | readAsBinaryString: function(blob) { |
||
| 4196 | return _read.call(this, 'readAsBinaryString', blob); |
||
| 4197 | }, |
||
| 4198 | |||
| 4199 | readAsDataURL: function(blob) { |
||
| 4200 | return _read.call(this, 'readAsDataURL', blob); |
||
| 4201 | }, |
||
| 4202 | |||
| 4203 | /*readAsArrayBuffer: function(blob) { |
||
| 4204 | return _read.call(this, 'readAsArrayBuffer', blob); |
||
| 4205 | },*/ |
||
| 4206 | |||
| 4207 | readAsText: function(blob) { |
||
| 4208 | return _read.call(this, 'readAsText', blob); |
||
| 4209 | } |
||
| 4210 | }); |
||
| 4211 | |||
| 4212 | function _read(op, blob) { |
||
| 4213 | if (blob.isDetached()) { |
||
| 4214 | var src = blob.getSource(); |
||
| 4215 | switch (op) { |
||
| 4216 | case 'readAsBinaryString': |
||
| 4217 | return src; |
||
| 4218 | case 'readAsDataURL': |
||
| 4219 | return 'data:' + blob.type + ';base64,' + Encode.btoa(src); |
||
| 4220 | case 'readAsText': |
||
| 4221 | var txt = ''; |
||
| 4222 | for (var i = 0, length = src.length; i < length; i++) { |
||
| 4223 | txt += String.fromCharCode(src[i]); |
||
| 4224 | } |
||
| 4225 | return txt; |
||
| 4226 | } |
||
| 4227 | } else { |
||
| 4228 | var result = this.connectRuntime(blob.ruid).exec.call(this, 'FileReaderSync', 'read', op, blob); |
||
| 4229 | this.disconnectRuntime(); |
||
| 4230 | return result; |
||
| 4231 | } |
||
| 4232 | } |
||
| 4233 | }; |
||
| 4234 | }); |
||
| 4235 | |||
| 4236 | // Included from: src/javascript/xhr/FormData.js |
||
| 4237 | |||
| 4238 | /** |
||
| 4239 | * FormData.js |
||
| 4240 | * |
||
| 4241 | * Copyright 2013, Moxiecode Systems AB |
||
| 4242 | * Released under GPL License. |
||
| 4243 | * |
||
| 4244 | * License: http://www.plupload.com/license |
||
| 4245 | * Contributing: http://www.plupload.com/contributing |
||
| 4246 | */ |
||
| 4247 | |||
| 4248 | define("moxie/xhr/FormData", [ |
||
| 4249 | "moxie/core/Exceptions", |
||
| 4250 | "moxie/core/utils/Basic", |
||
| 4251 | "moxie/file/Blob" |
||
| 4252 | ], function(x, Basic, Blob) { |
||
| 4253 | /** |
||
| 4254 | FormData |
||
| 4255 | |||
| 4256 | @class FormData |
||
| 4257 | @constructor |
||
| 4258 | */ |
||
| 4259 | function FormData() { |
||
| 4260 | var _blob, _fields = []; |
||
| 4261 | |||
| 4262 | Basic.extend(this, { |
||
| 4263 | /** |
||
| 4264 | Append another key-value pair to the FormData object |
||
| 4265 | |||
| 4266 | @method append |
||
| 4267 | @param {String} name Name for the new field |
||
| 4268 | @param {String|Blob|Array|Object} value Value for the field |
||
| 4269 | */ |
||
| 4270 | append: function(name, value) { |
||
| 4271 | var self = this, valueType = Basic.typeOf(value); |
||
| 4272 | |||
| 4273 | // according to specs value might be either Blob or String |
||
| 4274 | if (value instanceof Blob) { |
||
| 4275 | _blob = { |
||
| 4276 | name: name, |
||
| 4277 | value: value // unfortunately we can only send single Blob in one FormData |
||
| 4278 | }; |
||
| 4279 | } else if ('array' === valueType) { |
||
| 4280 | name += '[]'; |
||
| 4281 | |||
| 4282 | Basic.each(value, function(value) { |
||
| 4283 | self.append(name, value); |
||
| 4284 | }); |
||
| 4285 | } else if ('object' === valueType) { |
||
| 4286 | Basic.each(value, function(value, key) { |
||
| 4287 | self.append(name + '[' + key + ']', value); |
||
| 4288 | }); |
||
| 4289 | } else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) { |
||
| 4290 | self.append(name, "false"); |
||
| 4291 | } else { |
||
| 4292 | _fields.push({ |
||
| 4293 | name: name, |
||
| 4294 | value: value.toString() |
||
| 4295 | }); |
||
| 4296 | } |
||
| 4297 | }, |
||
| 4298 | |||
| 4299 | /** |
||
| 4300 | Checks if FormData contains Blob. |
||
| 4301 | |||
| 4302 | @method hasBlob |
||
| 4303 | @return {Boolean} |
||
| 4304 | */ |
||
| 4305 | hasBlob: function() { |
||
| 4306 | return !!this.getBlob(); |
||
| 4307 | }, |
||
| 4308 | |||
| 4309 | /** |
||
| 4310 | Retrieves blob. |
||
| 4311 | |||
| 4312 | @method getBlob |
||
| 4313 | @return {Object} Either Blob if found or null |
||
| 4314 | */ |
||
| 4315 | getBlob: function() { |
||
| 4316 | return _blob && _blob.value || null; |
||
| 4317 | }, |
||
| 4318 | |||
| 4319 | /** |
||
| 4320 | Retrieves blob field name. |
||
| 4321 | |||
| 4322 | @method getBlobName |
||
| 4323 | @return {String} Either Blob field name or null |
||
| 4324 | */ |
||
| 4325 | getBlobName: function() { |
||
| 4326 | return _blob && _blob.name || null; |
||
| 4327 | }, |
||
| 4328 | |||
| 4329 | /** |
||
| 4330 | Loop over the fields in FormData and invoke the callback for each of them. |
||
| 4331 | |||
| 4332 | @method each |
||
| 4333 | @param {Function} cb Callback to call for each field |
||
| 4334 | */ |
||
| 4335 | each: function(cb) { |
||
| 4336 | Basic.each(_fields, function(field) { |
||
| 4337 | cb(field.value, field.name); |
||
| 4338 | }); |
||
| 4339 | |||
| 4340 | if (_blob) { |
||
| 4341 | cb(_blob.value, _blob.name); |
||
| 4342 | } |
||
| 4343 | }, |
||
| 4344 | |||
| 4345 | destroy: function() { |
||
| 4346 | _blob = null; |
||
| 4347 | _fields = []; |
||
| 4348 | } |
||
| 4349 | }); |
||
| 4350 | } |
||
| 4351 | |||
| 4352 | return FormData; |
||
| 4353 | }); |
||
| 4354 | |||
| 4355 | // Included from: src/javascript/xhr/XMLHttpRequest.js |
||
| 4356 | |||
| 4357 | /** |
||
| 4358 | * XMLHttpRequest.js |
||
| 4359 | * |
||
| 4360 | * Copyright 2013, Moxiecode Systems AB |
||
| 4361 | * Released under GPL License. |
||
| 4362 | * |
||
| 4363 | * License: http://www.plupload.com/license |
||
| 4364 | * Contributing: http://www.plupload.com/contributing |
||
| 4365 | */ |
||
| 4366 | |||
| 4367 | define("moxie/xhr/XMLHttpRequest", [ |
||
| 4368 | "moxie/core/utils/Basic", |
||
| 4369 | "moxie/core/Exceptions", |
||
| 4370 | "moxie/core/EventTarget", |
||
| 4371 | "moxie/core/utils/Encode", |
||
| 4372 | "moxie/core/utils/Url", |
||
| 4373 | "moxie/runtime/Runtime", |
||
| 4374 | "moxie/runtime/RuntimeTarget", |
||
| 4375 | "moxie/file/Blob", |
||
| 4376 | "moxie/file/FileReaderSync", |
||
| 4377 | "moxie/xhr/FormData", |
||
| 4378 | "moxie/core/utils/Env", |
||
| 4379 | "moxie/core/utils/Mime" |
||
| 4380 | ], function(Basic, x, EventTarget, Encode, Url, Runtime, RuntimeTarget, Blob, FileReaderSync, FormData, Env, Mime) { |
||
| 4381 | |||
| 4382 | var httpCode = { |
||
| 4383 | 100: 'Continue', |
||
| 4384 | 101: 'Switching Protocols', |
||
| 4385 | 102: 'Processing', |
||
| 4386 | |||
| 4387 | 200: 'OK', |
||
| 4388 | 201: 'Created', |
||
| 4389 | 202: 'Accepted', |
||
| 4390 | 203: 'Non-Authoritative Information', |
||
| 4391 | 204: 'No Content', |
||
| 4392 | 205: 'Reset Content', |
||
| 4393 | 206: 'Partial Content', |
||
| 4394 | 207: 'Multi-Status', |
||
| 4395 | 226: 'IM Used', |
||
| 4396 | |||
| 4397 | 300: 'Multiple Choices', |
||
| 4398 | 301: 'Moved Permanently', |
||
| 4399 | 302: 'Found', |
||
| 4400 | 303: 'See Other', |
||
| 4401 | 304: 'Not Modified', |
||
| 4402 | 305: 'Use Proxy', |
||
| 4403 | 306: 'Reserved', |
||
| 4404 | 307: 'Temporary Redirect', |
||
| 4405 | |||
| 4406 | 400: 'Bad Request', |
||
| 4407 | 401: 'Unauthorized', |
||
| 4408 | 402: 'Payment Required', |
||
| 4409 | 403: 'Forbidden', |
||
| 4410 | 404: 'Not Found', |
||
| 4411 | 405: 'Method Not Allowed', |
||
| 4412 | 406: 'Not Acceptable', |
||
| 4413 | 407: 'Proxy Authentication Required', |
||
| 4414 | 408: 'Request Timeout', |
||
| 4415 | 409: 'Conflict', |
||
| 4416 | 410: 'Gone', |
||
| 4417 | 411: 'Length Required', |
||
| 4418 | 412: 'Precondition Failed', |
||
| 4419 | 413: 'Request Entity Too Large', |
||
| 4420 | 414: 'Request-URI Too Long', |
||
| 4421 | 415: 'Unsupported Media Type', |
||
| 4422 | 416: 'Requested Range Not Satisfiable', |
||
| 4423 | 417: 'Expectation Failed', |
||
| 4424 | 422: 'Unprocessable Entity', |
||
| 4425 | 423: 'Locked', |
||
| 4426 | 424: 'Failed Dependency', |
||
| 4427 | 426: 'Upgrade Required', |
||
| 4428 | |||
| 4429 | 500: 'Internal Server Error', |
||
| 4430 | 501: 'Not Implemented', |
||
| 4431 | 502: 'Bad Gateway', |
||
| 4432 | 503: 'Service Unavailable', |
||
| 4433 | 504: 'Gateway Timeout', |
||
| 4434 | 505: 'HTTP Version Not Supported', |
||
| 4435 | 506: 'Variant Also Negotiates', |
||
| 4436 | 507: 'Insufficient Storage', |
||
| 4437 | 510: 'Not Extended' |
||
| 4438 | }; |
||
| 4439 | |||
| 4440 | function XMLHttpRequestUpload() { |
||
| 4441 | this.uid = Basic.guid('uid_'); |
||
| 4442 | } |
||
| 4443 | |||
| 4444 | XMLHttpRequestUpload.prototype = EventTarget.instance; |
||
| 4445 | |||
| 4446 | /** |
||
| 4447 | Implementation of XMLHttpRequest |
||
| 4448 | |||
| 4449 | @class XMLHttpRequest |
||
| 4450 | @constructor |
||
| 4451 | @uses RuntimeClient |
||
| 4452 | @extends EventTarget |
||
| 4453 | */ |
||
| 4454 | var dispatches = ['loadstart', 'progress', 'abort', 'error', 'load', 'timeout', 'loadend']; // & readystatechange (for historical reasons) |
||
| 4455 | |||
| 4456 | var NATIVE = 1, RUNTIME = 2; |
||
| 4457 | |||
| 4458 | function XMLHttpRequest() { |
||
| 4459 | var self = this, |
||
| 4460 | // this (together with _p() @see below) is here to gracefully upgrade to setter/getter syntax where possible |
||
| 4461 | props = { |
||
| 4462 | /** |
||
| 4463 | The amount of milliseconds a request can take before being terminated. Initially zero. Zero means there is no timeout. |
||
| 4464 | |||
| 4465 | @property timeout |
||
| 4466 | @type Number |
||
| 4467 | @default 0 |
||
| 4468 | */ |
||
| 4469 | timeout: 0, |
||
| 4470 | |||
| 4471 | /** |
||
| 4472 | Current state, can take following values: |
||
| 4473 | UNSENT (numeric value 0) |
||
| 4474 | The object has been constructed. |
||
| 4475 | |||
| 4476 | OPENED (numeric value 1) |
||
| 4477 | The open() method has been successfully invoked. During this state request headers can be set using setRequestHeader() and the request can be made using the send() method. |
||
| 4478 | |||
| 4479 | HEADERS_RECEIVED (numeric value 2) |
||
| 4480 | All redirects (if any) have been followed and all HTTP headers of the final response have been received. Several response members of the object are now available. |
||
| 4481 | |||
| 4482 | LOADING (numeric value 3) |
||
| 4483 | The response entity body is being received. |
||
| 4484 | |||
| 4485 | DONE (numeric value 4) |
||
| 4486 | |||
| 4487 | @property readyState |
||
| 4488 | @type Number |
||
| 4489 | @default 0 (UNSENT) |
||
| 4490 | */ |
||
| 4491 | readyState: XMLHttpRequest.UNSENT, |
||
| 4492 | |||
| 4493 | /** |
||
| 4494 | True when user credentials are to be included in a cross-origin request. False when they are to be excluded |
||
| 4495 | in a cross-origin request and when cookies are to be ignored in its response. Initially false. |
||
| 4496 | |||
| 4497 | @property withCredentials |
||
| 4498 | @type Boolean |
||
| 4499 | @default false |
||
| 4500 | */ |
||
| 4501 | withCredentials: false, |
||
| 4502 | |||
| 4503 | /** |
||
| 4504 | Returns the HTTP status code. |
||
| 4505 | |||
| 4506 | @property status |
||
| 4507 | @type Number |
||
| 4508 | @default 0 |
||
| 4509 | */ |
||
| 4510 | status: 0, |
||
| 4511 | |||
| 4512 | /** |
||
| 4513 | Returns the HTTP status text. |
||
| 4514 | |||
| 4515 | @property statusText |
||
| 4516 | @type String |
||
| 4517 | */ |
||
| 4518 | statusText: "", |
||
| 4519 | |||
| 4520 | /** |
||
| 4521 | Returns the response type. Can be set to change the response type. Values are: |
||
| 4522 | the empty string (default), "arraybuffer", "blob", "document", "json", and "text". |
||
| 4523 | |||
| 4524 | @property responseType |
||
| 4525 | @type String |
||
| 4526 | */ |
||
| 4527 | responseType: "", |
||
| 4528 | |||
| 4529 | /** |
||
| 4530 | Returns the document response entity body. |
||
| 4531 | |||
| 4532 | Throws an "InvalidStateError" exception if responseType is not the empty string or "document". |
||
| 4533 | |||
| 4534 | @property responseXML |
||
| 4535 | @type Document |
||
| 4536 | */ |
||
| 4537 | responseXML: null, |
||
| 4538 | |||
| 4539 | /** |
||
| 4540 | Returns the text response entity body. |
||
| 4541 | |||
| 4542 | Throws an "InvalidStateError" exception if responseType is not the empty string or "text". |
||
| 4543 | |||
| 4544 | @property responseText |
||
| 4545 | @type String |
||
| 4546 | */ |
||
| 4547 | responseText: null, |
||
| 4548 | |||
| 4549 | /** |
||
| 4550 | Returns the response entity body (http://www.w3.org/TR/XMLHttpRequest/#response-entity-body). |
||
| 4551 | Can become: ArrayBuffer, Blob, Document, JSON, Text |
||
| 4552 | |||
| 4553 | @property response |
||
| 4554 | @type Mixed |
||
| 4555 | */ |
||
| 4556 | response: null |
||
| 4557 | }, |
||
| 4558 | |||
| 4559 | _async = true, |
||
| 4560 | _url, |
||
| 4561 | _method, |
||
| 4562 | _headers = {}, |
||
| 4563 | _user, |
||
| 4564 | _password, |
||
| 4565 | _encoding = null, |
||
| 4566 | _mimeType = null, |
||
| 4567 | |||
| 4568 | // flags |
||
| 4569 | _sync_flag = false, |
||
| 4570 | _send_flag = false, |
||
| 4571 | _upload_events_flag = false, |
||
| 4572 | _upload_complete_flag = false, |
||
| 4573 | _error_flag = false, |
||
| 4574 | _same_origin_flag = false, |
||
| 4575 | |||
| 4576 | // times |
||
| 4577 | _start_time, |
||
| 4578 | _timeoutset_time, |
||
| 4579 | |||
| 4580 | _finalMime = null, |
||
| 4581 | _finalCharset = null, |
||
| 4582 | |||
| 4583 | _options = {}, |
||
| 4584 | _xhr, |
||
| 4585 | _responseHeaders = '', |
||
| 4586 | _responseHeadersBag |
||
| 4587 | ; |
||
| 4588 | |||
| 4589 | |||
| 4590 | Basic.extend(this, props, { |
||
| 4591 | /** |
||
| 4592 | Unique id of the component |
||
| 4593 | |||
| 4594 | @property uid |
||
| 4595 | @type String |
||
| 4596 | */ |
||
| 4597 | uid: Basic.guid('uid_'), |
||
| 4598 | |||
| 4599 | /** |
||
| 4600 | Target for Upload events |
||
| 4601 | |||
| 4602 | @property upload |
||
| 4603 | @type XMLHttpRequestUpload |
||
| 4604 | */ |
||
| 4605 | upload: new XMLHttpRequestUpload(), |
||
| 4606 | |||
| 4607 | |||
| 4608 | /** |
||
| 4609 | Sets the request method, request URL, synchronous flag, request username, and request password. |
||
| 4610 | |||
| 4611 | Throws a "SyntaxError" exception if one of the following is true: |
||
| 4612 | |||
| 4613 | method is not a valid HTTP method. |
||
| 4614 | url cannot be resolved. |
||
| 4615 | url contains the "user:password" format in the userinfo production. |
||
| 4616 | Throws a "SecurityError" exception if method is a case-insensitive match for CONNECT, TRACE or TRACK. |
||
| 4617 | |||
| 4618 | Throws an "InvalidAccessError" exception if one of the following is true: |
||
| 4619 | |||
| 4620 | Either user or password is passed as argument and the origin of url does not match the XMLHttpRequest origin. |
||
| 4621 | There is an associated XMLHttpRequest document and either the timeout attribute is not zero, |
||
| 4622 | the withCredentials attribute is true, or the responseType attribute is not the empty string. |
||
| 4623 | |||
| 4624 | |||
| 4625 | @method open |
||
| 4626 | @param {String} method HTTP method to use on request |
||
| 4627 | @param {String} url URL to request |
||
| 4628 | @param {Boolean} [async=true] If false request will be done in synchronous manner. Asynchronous by default. |
||
| 4629 | @param {String} [user] Username to use in HTTP authentication process on server-side |
||
| 4630 | @param {String} [password] Password to use in HTTP authentication process on server-side |
||
| 4631 | */ |
||
| 4632 | open: function(method, url, async, user, password) { |
||
| 4633 | var urlp; |
||
| 4634 | |||
| 4635 | // first two arguments are required |
||
| 4636 | if (!method || !url) { |
||
| 4637 | throw new x.DOMException(x.DOMException.SYNTAX_ERR); |
||
| 4638 | } |
||
| 4639 | |||
| 4640 | // 2 - check if any code point in method is higher than U+00FF or after deflating method it does not match the method |
||
| 4641 | if (/[\u0100-\uffff]/.test(method) || Encode.utf8_encode(method) !== method) { |
||
| 4642 | throw new x.DOMException(x.DOMException.SYNTAX_ERR); |
||
| 4643 | } |
||
| 4644 | |||
| 4645 | // 3 |
||
| 4646 | if (!!~Basic.inArray(method.toUpperCase(), ['CONNECT', 'DELETE', 'GET', 'HEAD', 'OPTIONS', 'POST', 'PUT', 'TRACE', 'TRACK'])) { |
||
| 4647 | _method = method.toUpperCase(); |
||
| 4648 | } |
||
| 4649 | |||
| 4650 | |||
| 4651 | // 4 - allowing these methods poses a security risk |
||
| 4652 | if (!!~Basic.inArray(_method, ['CONNECT', 'TRACE', 'TRACK'])) { |
||
| 4653 | throw new x.DOMException(x.DOMException.SECURITY_ERR); |
||
| 4654 | } |
||
| 4655 | |||
| 4656 | // 5 |
||
| 4657 | url = Encode.utf8_encode(url); |
||
| 4658 | |||
| 4659 | // 6 - Resolve url relative to the XMLHttpRequest base URL. If the algorithm returns an error, throw a "SyntaxError". |
||
| 4660 | urlp = Url.parseUrl(url); |
||
| 4661 | |||
| 4662 | _same_origin_flag = Url.hasSameOrigin(urlp); |
||
| 4663 | |||
| 4664 | // 7 - manually build up absolute url |
||
| 4665 | _url = Url.resolveUrl(url); |
||
| 4666 | |||
| 4667 | // 9-10, 12-13 |
||
| 4668 | if ((user || password) && !_same_origin_flag) { |
||
| 4669 | throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); |
||
| 4670 | } |
||
| 4671 | |||
| 4672 | _user = user || urlp.user; |
||
| 4673 | _password = password || urlp.pass; |
||
| 4674 | |||
| 4675 | // 11 |
||
| 4676 | _async = async || true; |
||
| 4677 | |||
| 4678 | if (_async === false && (_p('timeout') || _p('withCredentials') || _p('responseType') !== "")) { |
||
| 4679 | throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); |
||
| 4680 | } |
||
| 4681 | |||
| 4682 | // 14 - terminate abort() |
||
| 4683 | |||
| 4684 | // 15 - terminate send() |
||
| 4685 | |||
| 4686 | // 18 |
||
| 4687 | _sync_flag = !_async; |
||
| 4688 | _send_flag = false; |
||
| 4689 | _headers = {}; |
||
| 4690 | _reset.call(this); |
||
| 4691 | |||
| 4692 | // 19 |
||
| 4693 | _p('readyState', XMLHttpRequest.OPENED); |
||
| 4694 | |||
| 4695 | // 20 |
||
| 4696 | this.convertEventPropsToHandlers(['readystatechange']); // unify event handlers |
||
| 4697 | this.dispatchEvent('readystatechange'); |
||
| 4698 | }, |
||
| 4699 | |||
| 4700 | /** |
||
| 4701 | Appends an header to the list of author request headers, or if header is already |
||
| 4702 | in the list of author request headers, combines its value with value. |
||
| 4703 | |||
| 4704 | Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. |
||
| 4705 | Throws a "SyntaxError" exception if header is not a valid HTTP header field name or if value |
||
| 4706 | is not a valid HTTP header field value. |
||
| 4707 | |||
| 4708 | @method setRequestHeader |
||
| 4709 | @param {String} header |
||
| 4710 | @param {String|Number} value |
||
| 4711 | */ |
||
| 4712 | setRequestHeader: function(header, value) { |
||
| 4713 | var uaHeaders = [ // these headers are controlled by the user agent |
||
| 4714 | "accept-charset", |
||
| 4715 | "accept-encoding", |
||
| 4716 | "access-control-request-headers", |
||
| 4717 | "access-control-request-method", |
||
| 4718 | "connection", |
||
| 4719 | "content-length", |
||
| 4720 | "cookie", |
||
| 4721 | "cookie2", |
||
| 4722 | "content-transfer-encoding", |
||
| 4723 | "date", |
||
| 4724 | "expect", |
||
| 4725 | "host", |
||
| 4726 | "keep-alive", |
||
| 4727 | "origin", |
||
| 4728 | "referer", |
||
| 4729 | "te", |
||
| 4730 | "trailer", |
||
| 4731 | "transfer-encoding", |
||
| 4732 | "upgrade", |
||
| 4733 | "user-agent", |
||
| 4734 | "via" |
||
| 4735 | ]; |
||
| 4736 | |||
| 4737 | // 1-2 |
||
| 4738 | if (_p('readyState') !== XMLHttpRequest.OPENED || _send_flag) { |
||
| 4739 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 4740 | } |
||
| 4741 | |||
| 4742 | // 3 |
||
| 4743 | if (/[\u0100-\uffff]/.test(header) || Encode.utf8_encode(header) !== header) { |
||
| 4744 | throw new x.DOMException(x.DOMException.SYNTAX_ERR); |
||
| 4745 | } |
||
| 4746 | |||
| 4747 | // 4 |
||
| 4748 | /* this step is seemingly bypassed in browsers, probably to allow various unicode characters in header values |
||
| 4749 | if (/[\u0100-\uffff]/.test(value) || Encode.utf8_encode(value) !== value) { |
||
| 4750 | throw new x.DOMException(x.DOMException.SYNTAX_ERR); |
||
| 4751 | }*/ |
||
| 4752 | |||
| 4753 | header = Basic.trim(header).toLowerCase(); |
||
| 4754 | |||
| 4755 | // setting of proxy-* and sec-* headers is prohibited by spec |
||
| 4756 | if (!!~Basic.inArray(header, uaHeaders) || /^(proxy\-|sec\-)/.test(header)) { |
||
| 4757 | return false; |
||
| 4758 | } |
||
| 4759 | |||
| 4760 | // camelize |
||
| 4761 | // browsers lowercase header names (at least for custom ones) |
||
| 4762 | // header = header.replace(/\b\w/g, function($1) { return $1.toUpperCase(); }); |
||
| 4763 | |||
| 4764 | if (!_headers[header]) { |
||
| 4765 | _headers[header] = value; |
||
| 4766 | } else { |
||
| 4767 | // http://tools.ietf.org/html/rfc2616#section-4.2 (last paragraph) |
||
| 4768 | _headers[header] += ', ' + value; |
||
| 4769 | } |
||
| 4770 | return true; |
||
| 4771 | }, |
||
| 4772 | |||
| 4773 | /** |
||
| 4774 | Returns all headers from the response, with the exception of those whose field name is Set-Cookie or Set-Cookie2. |
||
| 4775 | |||
| 4776 | @method getAllResponseHeaders |
||
| 4777 | @return {String} reponse headers or empty string |
||
| 4778 | */ |
||
| 4779 | getAllResponseHeaders: function() { |
||
| 4780 | return _responseHeaders || ''; |
||
| 4781 | }, |
||
| 4782 | |||
| 4783 | /** |
||
| 4784 | Returns the header field value from the response of which the field name matches header, |
||
| 4785 | unless the field name is Set-Cookie or Set-Cookie2. |
||
| 4786 | |||
| 4787 | @method getResponseHeader |
||
| 4788 | @param {String} header |
||
| 4789 | @return {String} value(s) for the specified header or null |
||
| 4790 | */ |
||
| 4791 | getResponseHeader: function(header) { |
||
| 4792 | header = header.toLowerCase(); |
||
| 4793 | |||
| 4794 | if (_error_flag || !!~Basic.inArray(header, ['set-cookie', 'set-cookie2'])) { |
||
| 4795 | return null; |
||
| 4796 | } |
||
| 4797 | |||
| 4798 | if (_responseHeaders && _responseHeaders !== '') { |
||
| 4799 | // if we didn't parse response headers until now, do it and keep for later |
||
| 4800 | if (!_responseHeadersBag) { |
||
| 4801 | _responseHeadersBag = {}; |
||
| 4802 | Basic.each(_responseHeaders.split(/\r\n/), function(line) { |
||
| 4803 | var pair = line.split(/:\s+/); |
||
| 4804 | if (pair.length === 2) { // last line might be empty, omit |
||
| 4805 | pair[0] = Basic.trim(pair[0]); // just in case |
||
| 4806 | _responseHeadersBag[pair[0].toLowerCase()] = { // simply to retain header name in original form |
||
| 4807 | header: pair[0], |
||
| 4808 | value: Basic.trim(pair[1]) |
||
| 4809 | }; |
||
| 4810 | } |
||
| 4811 | }); |
||
| 4812 | } |
||
| 4813 | if (_responseHeadersBag.hasOwnProperty(header)) { |
||
| 4814 | return _responseHeadersBag[header].header + ': ' + _responseHeadersBag[header].value; |
||
| 4815 | } |
||
| 4816 | } |
||
| 4817 | return null; |
||
| 4818 | }, |
||
| 4819 | |||
| 4820 | /** |
||
| 4821 | Sets the Content-Type header for the response to mime. |
||
| 4822 | Throws an "InvalidStateError" exception if the state is LOADING or DONE. |
||
| 4823 | Throws a "SyntaxError" exception if mime is not a valid media type. |
||
| 4824 | |||
| 4825 | @method overrideMimeType |
||
| 4826 | @param String mime Mime type to set |
||
| 4827 | */ |
||
| 4828 | overrideMimeType: function(mime) { |
||
| 4829 | var matches, charset; |
||
| 4830 | |||
| 4831 | // 1 |
||
| 4832 | if (!!~Basic.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { |
||
| 4833 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 4834 | } |
||
| 4835 | |||
| 4836 | // 2 |
||
| 4837 | mime = Basic.trim(mime.toLowerCase()); |
||
| 4838 | |||
| 4839 | if (/;/.test(mime) && (matches = mime.match(/^([^;]+)(?:;\scharset\=)?(.*)$/))) { |
||
| 4840 | mime = matches[1]; |
||
| 4841 | if (matches[2]) { |
||
| 4842 | charset = matches[2]; |
||
| 4843 | } |
||
| 4844 | } |
||
| 4845 | |||
| 4846 | if (!Mime.mimes[mime]) { |
||
| 4847 | throw new x.DOMException(x.DOMException.SYNTAX_ERR); |
||
| 4848 | } |
||
| 4849 | |||
| 4850 | // 3-4 |
||
| 4851 | _finalMime = mime; |
||
| 4852 | _finalCharset = charset; |
||
| 4853 | }, |
||
| 4854 | |||
| 4855 | /** |
||
| 4856 | Initiates the request. The optional argument provides the request entity body. |
||
| 4857 | The argument is ignored if request method is GET or HEAD. |
||
| 4858 | |||
| 4859 | Throws an "InvalidStateError" exception if the state is not OPENED or if the send() flag is set. |
||
| 4860 | |||
| 4861 | @method send |
||
| 4862 | @param {Blob|Document|String|FormData} [data] Request entity body |
||
| 4863 | @param {Object} [options] Set of requirements and pre-requisities for runtime initialization |
||
| 4864 | */ |
||
| 4865 | send: function(data, options) { |
||
| 4866 | if (Basic.typeOf(options) === 'string') { |
||
| 4867 | _options = { ruid: options }; |
||
| 4868 | } else if (!options) { |
||
| 4869 | _options = {}; |
||
| 4870 | } else { |
||
| 4871 | _options = options; |
||
| 4872 | } |
||
| 4873 | |||
| 4874 | this.convertEventPropsToHandlers(dispatches); |
||
| 4875 | this.upload.convertEventPropsToHandlers(dispatches); |
||
| 4876 | |||
| 4877 | // 1-2 |
||
| 4878 | if (this.readyState !== XMLHttpRequest.OPENED || _send_flag) { |
||
| 4879 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 4880 | } |
||
| 4881 | |||
| 4882 | // 3 |
||
| 4883 | // sending Blob |
||
| 4884 | if (data instanceof Blob) { |
||
| 4885 | _options.ruid = data.ruid; |
||
| 4886 | _mimeType = data.type || 'application/octet-stream'; |
||
| 4887 | } |
||
| 4888 | |||
| 4889 | // FormData |
||
| 4890 | else if (data instanceof FormData) { |
||
| 4891 | if (data.hasBlob()) { |
||
| 4892 | var blob = data.getBlob(); |
||
| 4893 | _options.ruid = blob.ruid; |
||
| 4894 | _mimeType = blob.type || 'application/octet-stream'; |
||
| 4895 | } |
||
| 4896 | } |
||
| 4897 | |||
| 4898 | // DOMString |
||
| 4899 | else if (typeof data === 'string') { |
||
| 4900 | _encoding = 'UTF-8'; |
||
| 4901 | _mimeType = 'text/plain;charset=UTF-8'; |
||
| 4902 | |||
| 4903 | // data should be converted to Unicode and encoded as UTF-8 |
||
| 4904 | data = Encode.utf8_encode(data); |
||
| 4905 | } |
||
| 4906 | |||
| 4907 | // if withCredentials not set, but requested, set it automatically |
||
| 4908 | if (!this.withCredentials) { |
||
| 4909 | this.withCredentials = (_options.required_caps && _options.required_caps.send_browser_cookies) && !_same_origin_flag; |
||
| 4910 | } |
||
| 4911 | |||
| 4912 | // 4 - storage mutex |
||
| 4913 | // 5 |
||
| 4914 | _upload_events_flag = (!_sync_flag && this.upload.hasEventListener()); // DSAP |
||
| 4915 | // 6 |
||
| 4916 | _error_flag = false; |
||
| 4917 | // 7 |
||
| 4918 | _upload_complete_flag = !data; |
||
| 4919 | // 8 - Asynchronous steps |
||
| 4920 | if (!_sync_flag) { |
||
| 4921 | // 8.1 |
||
| 4922 | _send_flag = true; |
||
| 4923 | // 8.2 |
||
| 4924 | // this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr |
||
| 4925 | // 8.3 |
||
| 4926 | //if (!_upload_complete_flag) { |
||
| 4927 | // this.upload.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr |
||
| 4928 | //} |
||
| 4929 | } |
||
| 4930 | // 8.5 - Return the send() method call, but continue running the steps in this algorithm. |
||
| 4931 | _doXHR.call(this, data); |
||
| 4932 | }, |
||
| 4933 | |||
| 4934 | /** |
||
| 4935 | Cancels any network activity. |
||
| 4936 | |||
| 4937 | @method abort |
||
| 4938 | */ |
||
| 4939 | abort: function() { |
||
| 4940 | _error_flag = true; |
||
| 4941 | _sync_flag = false; |
||
| 4942 | |||
| 4943 | if (!~Basic.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED, XMLHttpRequest.DONE])) { |
||
| 4944 | _p('readyState', XMLHttpRequest.DONE); |
||
| 4945 | _send_flag = false; |
||
| 4946 | |||
| 4947 | if (_xhr) { |
||
| 4948 | _xhr.getRuntime().exec.call(_xhr, 'XMLHttpRequest', 'abort', _upload_complete_flag); |
||
| 4949 | } else { |
||
| 4950 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 4951 | } |
||
| 4952 | |||
| 4953 | _upload_complete_flag = true; |
||
| 4954 | } else { |
||
| 4955 | _p('readyState', XMLHttpRequest.UNSENT); |
||
| 4956 | } |
||
| 4957 | }, |
||
| 4958 | |||
| 4959 | destroy: function() { |
||
| 4960 | if (_xhr) { |
||
| 4961 | if (Basic.typeOf(_xhr.destroy) === 'function') { |
||
| 4962 | _xhr.destroy(); |
||
| 4963 | } |
||
| 4964 | _xhr = null; |
||
| 4965 | } |
||
| 4966 | |||
| 4967 | this.unbindAll(); |
||
| 4968 | |||
| 4969 | if (this.upload) { |
||
| 4970 | this.upload.unbindAll(); |
||
| 4971 | this.upload = null; |
||
| 4972 | } |
||
| 4973 | } |
||
| 4974 | }); |
||
| 4975 | |||
| 4976 | /* this is nice, but maybe too lengthy |
||
| 4977 | |||
| 4978 | // if supported by JS version, set getters/setters for specific properties |
||
| 4979 | o.defineProperty(this, 'readyState', { |
||
| 4980 | configurable: false, |
||
| 4981 | |||
| 4982 | get: function() { |
||
| 4983 | return _p('readyState'); |
||
| 4984 | } |
||
| 4985 | }); |
||
| 4986 | |||
| 4987 | o.defineProperty(this, 'timeout', { |
||
| 4988 | configurable: false, |
||
| 4989 | |||
| 4990 | get: function() { |
||
| 4991 | return _p('timeout'); |
||
| 4992 | }, |
||
| 4993 | |||
| 4994 | set: function(value) { |
||
| 4995 | |||
| 4996 | if (_sync_flag) { |
||
| 4997 | throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); |
||
| 4998 | } |
||
| 4999 | |||
| 5000 | // timeout still should be measured relative to the start time of request |
||
| 5001 | _timeoutset_time = (new Date).getTime(); |
||
| 5002 | |||
| 5003 | _p('timeout', value); |
||
| 5004 | } |
||
| 5005 | }); |
||
| 5006 | |||
| 5007 | // the withCredentials attribute has no effect when fetching same-origin resources |
||
| 5008 | o.defineProperty(this, 'withCredentials', { |
||
| 5009 | configurable: false, |
||
| 5010 | |||
| 5011 | get: function() { |
||
| 5012 | return _p('withCredentials'); |
||
| 5013 | }, |
||
| 5014 | |||
| 5015 | set: function(value) { |
||
| 5016 | // 1-2 |
||
| 5017 | if (!~o.inArray(_p('readyState'), [XMLHttpRequest.UNSENT, XMLHttpRequest.OPENED]) || _send_flag) { |
||
| 5018 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5019 | } |
||
| 5020 | |||
| 5021 | // 3-4 |
||
| 5022 | if (_anonymous_flag || _sync_flag) { |
||
| 5023 | throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); |
||
| 5024 | } |
||
| 5025 | |||
| 5026 | // 5 |
||
| 5027 | _p('withCredentials', value); |
||
| 5028 | } |
||
| 5029 | }); |
||
| 5030 | |||
| 5031 | o.defineProperty(this, 'status', { |
||
| 5032 | configurable: false, |
||
| 5033 | |||
| 5034 | get: function() { |
||
| 5035 | return _p('status'); |
||
| 5036 | } |
||
| 5037 | }); |
||
| 5038 | |||
| 5039 | o.defineProperty(this, 'statusText', { |
||
| 5040 | configurable: false, |
||
| 5041 | |||
| 5042 | get: function() { |
||
| 5043 | return _p('statusText'); |
||
| 5044 | } |
||
| 5045 | }); |
||
| 5046 | |||
| 5047 | o.defineProperty(this, 'responseType', { |
||
| 5048 | configurable: false, |
||
| 5049 | |||
| 5050 | get: function() { |
||
| 5051 | return _p('responseType'); |
||
| 5052 | }, |
||
| 5053 | |||
| 5054 | set: function(value) { |
||
| 5055 | // 1 |
||
| 5056 | if (!!~o.inArray(_p('readyState'), [XMLHttpRequest.LOADING, XMLHttpRequest.DONE])) { |
||
| 5057 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5058 | } |
||
| 5059 | |||
| 5060 | // 2 |
||
| 5061 | if (_sync_flag) { |
||
| 5062 | throw new x.DOMException(x.DOMException.INVALID_ACCESS_ERR); |
||
| 5063 | } |
||
| 5064 | |||
| 5065 | // 3 |
||
| 5066 | _p('responseType', value.toLowerCase()); |
||
| 5067 | } |
||
| 5068 | }); |
||
| 5069 | |||
| 5070 | o.defineProperty(this, 'responseText', { |
||
| 5071 | configurable: false, |
||
| 5072 | |||
| 5073 | get: function() { |
||
| 5074 | // 1 |
||
| 5075 | if (!~o.inArray(_p('responseType'), ['', 'text'])) { |
||
| 5076 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5077 | } |
||
| 5078 | |||
| 5079 | // 2-3 |
||
| 5080 | if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) { |
||
| 5081 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5082 | } |
||
| 5083 | |||
| 5084 | return _p('responseText'); |
||
| 5085 | } |
||
| 5086 | }); |
||
| 5087 | |||
| 5088 | o.defineProperty(this, 'responseXML', { |
||
| 5089 | configurable: false, |
||
| 5090 | |||
| 5091 | get: function() { |
||
| 5092 | // 1 |
||
| 5093 | if (!~o.inArray(_p('responseType'), ['', 'document'])) { |
||
| 5094 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5095 | } |
||
| 5096 | |||
| 5097 | // 2-3 |
||
| 5098 | if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { |
||
| 5099 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5100 | } |
||
| 5101 | |||
| 5102 | return _p('responseXML'); |
||
| 5103 | } |
||
| 5104 | }); |
||
| 5105 | |||
| 5106 | o.defineProperty(this, 'response', { |
||
| 5107 | configurable: false, |
||
| 5108 | |||
| 5109 | get: function() { |
||
| 5110 | if (!!~o.inArray(_p('responseType'), ['', 'text'])) { |
||
| 5111 | if (_p('readyState') !== XMLHttpRequest.DONE && _p('readyState') !== XMLHttpRequest.LOADING || _error_flag) { |
||
| 5112 | return ''; |
||
| 5113 | } |
||
| 5114 | } |
||
| 5115 | |||
| 5116 | if (_p('readyState') !== XMLHttpRequest.DONE || _error_flag) { |
||
| 5117 | return null; |
||
| 5118 | } |
||
| 5119 | |||
| 5120 | return _p('response'); |
||
| 5121 | } |
||
| 5122 | }); |
||
| 5123 | |||
| 5124 | */ |
||
| 5125 | |||
| 5126 | function _p(prop, value) { |
||
| 5127 | if (!props.hasOwnProperty(prop)) { |
||
| 5128 | return; |
||
| 5129 | } |
||
| 5130 | if (arguments.length === 1) { // get |
||
| 5131 | return Env.can('define_property') ? props[prop] : self[prop]; |
||
| 5132 | } else { // set |
||
| 5133 | if (Env.can('define_property')) { |
||
| 5134 | props[prop] = value; |
||
| 5135 | } else { |
||
| 5136 | self[prop] = value; |
||
| 5137 | } |
||
| 5138 | } |
||
| 5139 | } |
||
| 5140 | |||
| 5141 | /* |
||
| 5142 | function _toASCII(str, AllowUnassigned, UseSTD3ASCIIRules) { |
||
| 5143 | // TODO: http://tools.ietf.org/html/rfc3490#section-4.1 |
||
| 5144 | return str.toLowerCase(); |
||
| 5145 | } |
||
| 5146 | */ |
||
| 5147 | |||
| 5148 | |||
| 5149 | function _doXHR(data) { |
||
| 5150 | var self = this; |
||
| 5151 | |||
| 5152 | _start_time = new Date().getTime(); |
||
| 5153 | |||
| 5154 | _xhr = new RuntimeTarget(); |
||
| 5155 | |||
| 5156 | function loadEnd() { |
||
| 5157 | if (_xhr) { // it could have been destroyed by now |
||
| 5158 | _xhr.destroy(); |
||
| 5159 | _xhr = null; |
||
| 5160 | } |
||
| 5161 | self.dispatchEvent('loadend'); |
||
| 5162 | self = null; |
||
| 5163 | } |
||
| 5164 | |||
| 5165 | function exec(runtime) { |
||
| 5166 | _xhr.bind('LoadStart', function(e) { |
||
| 5167 | _p('readyState', XMLHttpRequest.LOADING); |
||
| 5168 | self.dispatchEvent('readystatechange'); |
||
| 5169 | |||
| 5170 | self.dispatchEvent(e); |
||
| 5171 | |||
| 5172 | if (_upload_events_flag) { |
||
| 5173 | self.upload.dispatchEvent(e); |
||
| 5174 | } |
||
| 5175 | }); |
||
| 5176 | |||
| 5177 | _xhr.bind('Progress', function(e) { |
||
| 5178 | if (_p('readyState') !== XMLHttpRequest.LOADING) { |
||
| 5179 | _p('readyState', XMLHttpRequest.LOADING); // LoadStart unreliable (in Flash for example) |
||
| 5180 | self.dispatchEvent('readystatechange'); |
||
| 5181 | } |
||
| 5182 | self.dispatchEvent(e); |
||
| 5183 | }); |
||
| 5184 | |||
| 5185 | _xhr.bind('UploadProgress', function(e) { |
||
| 5186 | if (_upload_events_flag) { |
||
| 5187 | self.upload.dispatchEvent({ |
||
| 5188 | type: 'progress', |
||
| 5189 | lengthComputable: false, |
||
| 5190 | total: e.total, |
||
| 5191 | loaded: e.loaded |
||
| 5192 | }); |
||
| 5193 | } |
||
| 5194 | }); |
||
| 5195 | |||
| 5196 | _xhr.bind('Load', function(e) { |
||
| 5197 | _p('readyState', XMLHttpRequest.DONE); |
||
| 5198 | _p('status', Number(runtime.exec.call(_xhr, 'XMLHttpRequest', 'getStatus') || 0)); |
||
| 5199 | _p('statusText', httpCode[_p('status')] || ""); |
||
| 5200 | |||
| 5201 | _p('response', runtime.exec.call(_xhr, 'XMLHttpRequest', 'getResponse', _p('responseType'))); |
||
| 5202 | |||
| 5203 | if (!!~Basic.inArray(_p('responseType'), ['text', ''])) { |
||
| 5204 | _p('responseText', _p('response')); |
||
| 5205 | } else if (_p('responseType') === 'document') { |
||
| 5206 | _p('responseXML', _p('response')); |
||
| 5207 | } |
||
| 5208 | |||
| 5209 | _responseHeaders = runtime.exec.call(_xhr, 'XMLHttpRequest', 'getAllResponseHeaders'); |
||
| 5210 | |||
| 5211 | self.dispatchEvent('readystatechange'); |
||
| 5212 | |||
| 5213 | if (_p('status') > 0) { // status 0 usually means that server is unreachable |
||
| 5214 | if (_upload_events_flag) { |
||
| 5215 | self.upload.dispatchEvent(e); |
||
| 5216 | } |
||
| 5217 | self.dispatchEvent(e); |
||
| 5218 | } else { |
||
| 5219 | _error_flag = true; |
||
| 5220 | self.dispatchEvent('error'); |
||
| 5221 | } |
||
| 5222 | loadEnd(); |
||
| 5223 | }); |
||
| 5224 | |||
| 5225 | _xhr.bind('Abort', function(e) { |
||
| 5226 | self.dispatchEvent(e); |
||
| 5227 | loadEnd(); |
||
| 5228 | }); |
||
| 5229 | |||
| 5230 | _xhr.bind('Error', function(e) { |
||
| 5231 | _error_flag = true; |
||
| 5232 | _p('readyState', XMLHttpRequest.DONE); |
||
| 5233 | self.dispatchEvent('readystatechange'); |
||
| 5234 | _upload_complete_flag = true; |
||
| 5235 | self.dispatchEvent(e); |
||
| 5236 | loadEnd(); |
||
| 5237 | }); |
||
| 5238 | |||
| 5239 | runtime.exec.call(_xhr, 'XMLHttpRequest', 'send', { |
||
| 5240 | url: _url, |
||
| 5241 | method: _method, |
||
| 5242 | async: _async, |
||
| 5243 | user: _user, |
||
| 5244 | password: _password, |
||
| 5245 | headers: _headers, |
||
| 5246 | mimeType: _mimeType, |
||
| 5247 | encoding: _encoding, |
||
| 5248 | responseType: self.responseType, |
||
| 5249 | withCredentials: self.withCredentials, |
||
| 5250 | options: _options |
||
| 5251 | }, data); |
||
| 5252 | } |
||
| 5253 | |||
| 5254 | // clarify our requirements |
||
| 5255 | if (typeof(_options.required_caps) === 'string') { |
||
| 5256 | _options.required_caps = Runtime.parseCaps(_options.required_caps); |
||
| 5257 | } |
||
| 5258 | |||
| 5259 | _options.required_caps = Basic.extend({}, _options.required_caps, { |
||
| 5260 | return_response_type: self.responseType |
||
| 5261 | }); |
||
| 5262 | |||
| 5263 | if (data instanceof FormData) { |
||
| 5264 | _options.required_caps.send_multipart = true; |
||
| 5265 | } |
||
| 5266 | |||
| 5267 | if (!_same_origin_flag) { |
||
| 5268 | _options.required_caps.do_cors = true; |
||
| 5269 | } |
||
| 5270 | |||
| 5271 | |||
| 5272 | if (_options.ruid) { // we do not need to wait if we can connect directly |
||
| 5273 | exec(_xhr.connectRuntime(_options)); |
||
| 5274 | } else { |
||
| 5275 | _xhr.bind('RuntimeInit', function(e, runtime) { |
||
| 5276 | exec(runtime); |
||
| 5277 | }); |
||
| 5278 | _xhr.bind('RuntimeError', function(e, err) { |
||
| 5279 | self.dispatchEvent('RuntimeError', err); |
||
| 5280 | }); |
||
| 5281 | _xhr.connectRuntime(_options); |
||
| 5282 | } |
||
| 5283 | } |
||
| 5284 | |||
| 5285 | |||
| 5286 | function _reset() { |
||
| 5287 | _p('responseText', ""); |
||
| 5288 | _p('responseXML', null); |
||
| 5289 | _p('response', null); |
||
| 5290 | _p('status', 0); |
||
| 5291 | _p('statusText', ""); |
||
| 5292 | _start_time = _timeoutset_time = null; |
||
| 5293 | } |
||
| 5294 | } |
||
| 5295 | |||
| 5296 | XMLHttpRequest.UNSENT = 0; |
||
| 5297 | XMLHttpRequest.OPENED = 1; |
||
| 5298 | XMLHttpRequest.HEADERS_RECEIVED = 2; |
||
| 5299 | XMLHttpRequest.LOADING = 3; |
||
| 5300 | XMLHttpRequest.DONE = 4; |
||
| 5301 | |||
| 5302 | XMLHttpRequest.prototype = EventTarget.instance; |
||
| 5303 | |||
| 5304 | return XMLHttpRequest; |
||
| 5305 | }); |
||
| 5306 | |||
| 5307 | // Included from: src/javascript/runtime/Transporter.js |
||
| 5308 | |||
| 5309 | /** |
||
| 5310 | * Transporter.js |
||
| 5311 | * |
||
| 5312 | * Copyright 2013, Moxiecode Systems AB |
||
| 5313 | * Released under GPL License. |
||
| 5314 | * |
||
| 5315 | * License: http://www.plupload.com/license |
||
| 5316 | * Contributing: http://www.plupload.com/contributing |
||
| 5317 | */ |
||
| 5318 | |||
| 5319 | define("moxie/runtime/Transporter", [ |
||
| 5320 | "moxie/core/utils/Basic", |
||
| 5321 | "moxie/core/utils/Encode", |
||
| 5322 | "moxie/runtime/RuntimeClient", |
||
| 5323 | "moxie/core/EventTarget" |
||
| 5324 | ], function(Basic, Encode, RuntimeClient, EventTarget) { |
||
| 5325 | function Transporter() { |
||
| 5326 | var mod, _runtime, _data, _size, _pos, _chunk_size; |
||
| 5327 | |||
| 5328 | RuntimeClient.call(this); |
||
| 5329 | |||
| 5330 | Basic.extend(this, { |
||
| 5331 | uid: Basic.guid('uid_'), |
||
| 5332 | |||
| 5333 | state: Transporter.IDLE, |
||
| 5334 | |||
| 5335 | result: null, |
||
| 5336 | |||
| 5337 | transport: function(data, type, options) { |
||
| 5338 | var self = this; |
||
| 5339 | |||
| 5340 | options = Basic.extend({ |
||
| 5341 | chunk_size: 204798 |
||
| 5342 | }, options); |
||
| 5343 | |||
| 5344 | // should divide by three, base64 requires this |
||
| 5345 | if ((mod = options.chunk_size % 3)) { |
||
| 5346 | options.chunk_size += 3 - mod; |
||
| 5347 | } |
||
| 5348 | |||
| 5349 | _chunk_size = options.chunk_size; |
||
| 5350 | |||
| 5351 | _reset.call(this); |
||
| 5352 | _data = data; |
||
| 5353 | _size = data.length; |
||
| 5354 | |||
| 5355 | if (Basic.typeOf(options) === 'string' || options.ruid) { |
||
| 5356 | _run.call(self, type, this.connectRuntime(options)); |
||
| 5357 | } else { |
||
| 5358 | // we require this to run only once |
||
| 5359 | var cb = function(e, runtime) { |
||
| 5360 | self.unbind("RuntimeInit", cb); |
||
| 5361 | _run.call(self, type, runtime); |
||
| 5362 | }; |
||
| 5363 | this.bind("RuntimeInit", cb); |
||
| 5364 | this.connectRuntime(options); |
||
| 5365 | } |
||
| 5366 | }, |
||
| 5367 | |||
| 5368 | abort: function() { |
||
| 5369 | var self = this; |
||
| 5370 | |||
| 5371 | self.state = Transporter.IDLE; |
||
| 5372 | if (_runtime) { |
||
| 5373 | _runtime.exec.call(self, 'Transporter', 'clear'); |
||
| 5374 | self.trigger("TransportingAborted"); |
||
| 5375 | } |
||
| 5376 | |||
| 5377 | _reset.call(self); |
||
| 5378 | }, |
||
| 5379 | |||
| 5380 | |||
| 5381 | destroy: function() { |
||
| 5382 | this.unbindAll(); |
||
| 5383 | _runtime = null; |
||
| 5384 | this.disconnectRuntime(); |
||
| 5385 | _reset.call(this); |
||
| 5386 | } |
||
| 5387 | }); |
||
| 5388 | |||
| 5389 | function _reset() { |
||
| 5390 | _size = _pos = 0; |
||
| 5391 | _data = this.result = null; |
||
| 5392 | } |
||
| 5393 | |||
| 5394 | function _run(type, runtime) { |
||
| 5395 | var self = this; |
||
| 5396 | |||
| 5397 | _runtime = runtime; |
||
| 5398 | |||
| 5399 | //self.unbind("RuntimeInit"); |
||
| 5400 | |||
| 5401 | self.bind("TransportingProgress", function(e) { |
||
| 5402 | _pos = e.loaded; |
||
| 5403 | |||
| 5404 | if (_pos < _size && Basic.inArray(self.state, [Transporter.IDLE, Transporter.DONE]) === -1) { |
||
| 5405 | _transport.call(self); |
||
| 5406 | } |
||
| 5407 | }, 999); |
||
| 5408 | |||
| 5409 | self.bind("TransportingComplete", function() { |
||
| 5410 | _pos = _size; |
||
| 5411 | self.state = Transporter.DONE; |
||
| 5412 | _data = null; // clean a bit |
||
| 5413 | self.result = _runtime.exec.call(self, 'Transporter', 'getAsBlob', type || ''); |
||
| 5414 | }, 999); |
||
| 5415 | |||
| 5416 | self.state = Transporter.BUSY; |
||
| 5417 | self.trigger("TransportingStarted"); |
||
| 5418 | _transport.call(self); |
||
| 5419 | } |
||
| 5420 | |||
| 5421 | function _transport() { |
||
| 5422 | var self = this, |
||
| 5423 | chunk, |
||
| 5424 | bytesLeft = _size - _pos; |
||
| 5425 | |||
| 5426 | if (_chunk_size > bytesLeft) { |
||
| 5427 | _chunk_size = bytesLeft; |
||
| 5428 | } |
||
| 5429 | |||
| 5430 | chunk = Encode.btoa(_data.substr(_pos, _chunk_size)); |
||
| 5431 | _runtime.exec.call(self, 'Transporter', 'receive', chunk, _size); |
||
| 5432 | } |
||
| 5433 | } |
||
| 5434 | |||
| 5435 | Transporter.IDLE = 0; |
||
| 5436 | Transporter.BUSY = 1; |
||
| 5437 | Transporter.DONE = 2; |
||
| 5438 | |||
| 5439 | Transporter.prototype = EventTarget.instance; |
||
| 5440 | |||
| 5441 | return Transporter; |
||
| 5442 | }); |
||
| 5443 | |||
| 5444 | // Included from: src/javascript/image/Image.js |
||
| 5445 | |||
| 5446 | /** |
||
| 5447 | * Image.js |
||
| 5448 | * |
||
| 5449 | * Copyright 2013, Moxiecode Systems AB |
||
| 5450 | * Released under GPL License. |
||
| 5451 | * |
||
| 5452 | * License: http://www.plupload.com/license |
||
| 5453 | * Contributing: http://www.plupload.com/contributing |
||
| 5454 | */ |
||
| 5455 | |||
| 5456 | define("moxie/image/Image", [ |
||
| 5457 | "moxie/core/utils/Basic", |
||
| 5458 | "moxie/core/utils/Dom", |
||
| 5459 | "moxie/core/Exceptions", |
||
| 5460 | "moxie/file/FileReaderSync", |
||
| 5461 | "moxie/xhr/XMLHttpRequest", |
||
| 5462 | "moxie/runtime/Runtime", |
||
| 5463 | "moxie/runtime/RuntimeClient", |
||
| 5464 | "moxie/runtime/Transporter", |
||
| 5465 | "moxie/core/utils/Env", |
||
| 5466 | "moxie/core/EventTarget", |
||
| 5467 | "moxie/file/Blob", |
||
| 5468 | "moxie/file/File", |
||
| 5469 | "moxie/core/utils/Encode" |
||
| 5470 | ], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) { |
||
| 5471 | /** |
||
| 5472 | Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data. |
||
| 5473 | |||
| 5474 | @class Image |
||
| 5475 | @constructor |
||
| 5476 | @extends EventTarget |
||
| 5477 | */ |
||
| 5478 | var dispatches = [ |
||
| 5479 | 'progress', |
||
| 5480 | |||
| 5481 | /** |
||
| 5482 | Dispatched when loading is complete. |
||
| 5483 | |||
| 5484 | @event load |
||
| 5485 | @param {Object} event |
||
| 5486 | */ |
||
| 5487 | 'load', |
||
| 5488 | |||
| 5489 | 'error', |
||
| 5490 | |||
| 5491 | /** |
||
| 5492 | Dispatched when resize operation is complete. |
||
| 5493 | |||
| 5494 | @event resize |
||
| 5495 | @param {Object} event |
||
| 5496 | */ |
||
| 5497 | 'resize', |
||
| 5498 | |||
| 5499 | /** |
||
| 5500 | Dispatched when visual representation of the image is successfully embedded |
||
| 5501 | into the corresponsing container. |
||
| 5502 | |||
| 5503 | @event embedded |
||
| 5504 | @param {Object} event |
||
| 5505 | */ |
||
| 5506 | 'embedded' |
||
| 5507 | ]; |
||
| 5508 | |||
| 5509 | function Image() { |
||
| 5510 | RuntimeClient.call(this); |
||
| 5511 | |||
| 5512 | Basic.extend(this, { |
||
| 5513 | /** |
||
| 5514 | Unique id of the component |
||
| 5515 | |||
| 5516 | @property uid |
||
| 5517 | @type {String} |
||
| 5518 | */ |
||
| 5519 | uid: Basic.guid('uid_'), |
||
| 5520 | |||
| 5521 | /** |
||
| 5522 | Unique id of the connected runtime, if any. |
||
| 5523 | |||
| 5524 | @property ruid |
||
| 5525 | @type {String} |
||
| 5526 | */ |
||
| 5527 | ruid: null, |
||
| 5528 | |||
| 5529 | /** |
||
| 5530 | Name of the file, that was used to create an image, if available. If not equals to empty string. |
||
| 5531 | |||
| 5532 | @property name |
||
| 5533 | @type {String} |
||
| 5534 | @default "" |
||
| 5535 | */ |
||
| 5536 | name: "", |
||
| 5537 | |||
| 5538 | /** |
||
| 5539 | Size of the image in bytes. Actual value is set only after image is preloaded. |
||
| 5540 | |||
| 5541 | @property size |
||
| 5542 | @type {Number} |
||
| 5543 | @default 0 |
||
| 5544 | */ |
||
| 5545 | size: 0, |
||
| 5546 | |||
| 5547 | /** |
||
| 5548 | Width of the image. Actual value is set only after image is preloaded. |
||
| 5549 | |||
| 5550 | @property width |
||
| 5551 | @type {Number} |
||
| 5552 | @default 0 |
||
| 5553 | */ |
||
| 5554 | width: 0, |
||
| 5555 | |||
| 5556 | /** |
||
| 5557 | Height of the image. Actual value is set only after image is preloaded. |
||
| 5558 | |||
| 5559 | @property height |
||
| 5560 | @type {Number} |
||
| 5561 | @default 0 |
||
| 5562 | */ |
||
| 5563 | height: 0, |
||
| 5564 | |||
| 5565 | /** |
||
| 5566 | Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded. |
||
| 5567 | |||
| 5568 | @property type |
||
| 5569 | @type {String} |
||
| 5570 | @default "" |
||
| 5571 | */ |
||
| 5572 | type: "", |
||
| 5573 | |||
| 5574 | /** |
||
| 5575 | Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded. |
||
| 5576 | |||
| 5577 | @property meta |
||
| 5578 | @type {Object} |
||
| 5579 | @default {} |
||
| 5580 | */ |
||
| 5581 | meta: {}, |
||
| 5582 | |||
| 5583 | /** |
||
| 5584 | Alias for load method, that takes another mOxie.Image object as a source (see load). |
||
| 5585 | |||
| 5586 | @method clone |
||
| 5587 | @param {Image} src Source for the image |
||
| 5588 | @param {Boolean} [exact=false] Whether to activate in-depth clone mode |
||
| 5589 | */ |
||
| 5590 | clone: function() { |
||
| 5591 | this.load.apply(this, arguments); |
||
| 5592 | }, |
||
| 5593 | |||
| 5594 | /** |
||
| 5595 | Loads image from various sources. Currently the source for new image can be: mOxie.Image, mOxie.Blob/mOxie.File, |
||
| 5596 | native Blob/File, dataUrl or URL. Depending on the type of the source, arguments - differ. When source is URL, |
||
| 5597 | Image will be downloaded from remote destination and loaded in memory. |
||
| 5598 | |||
| 5599 | @example |
||
| 5600 | var img = new mOxie.Image(); |
||
| 5601 | img.onload = function() { |
||
| 5602 | var blob = img.getAsBlob(); |
||
| 5603 | |||
| 5604 | var formData = new mOxie.FormData(); |
||
| 5605 | formData.append('file', blob); |
||
| 5606 | |||
| 5607 | var xhr = new mOxie.XMLHttpRequest(); |
||
| 5608 | xhr.onload = function() { |
||
| 5609 | // upload complete |
||
| 5610 | }; |
||
| 5611 | xhr.open('post', 'upload.php'); |
||
| 5612 | xhr.send(formData); |
||
| 5613 | }; |
||
| 5614 | img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg) |
||
| 5615 | |||
| 5616 | |||
| 5617 | @method load |
||
| 5618 | @param {Image|Blob|File|String} src Source for the image |
||
| 5619 | @param {Boolean|Object} [mixed] |
||
| 5620 | */ |
||
| 5621 | load: function() { |
||
| 5622 | // this is here because to bind properly we need an uid first, which is created above |
||
| 5623 | this.bind('Load Resize', function() { |
||
| 5624 | _updateInfo.call(this); |
||
| 5625 | }, 999); |
||
| 5626 | |||
| 5627 | this.convertEventPropsToHandlers(dispatches); |
||
| 5628 | |||
| 5629 | _load.apply(this, arguments); |
||
| 5630 | }, |
||
| 5631 | |||
| 5632 | /** |
||
| 5633 | Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions. |
||
| 5634 | |||
| 5635 | @method downsize |
||
| 5636 | @param {Number} width Resulting width |
||
| 5637 | @param {Number} [height=width] Resulting height (optional, if not supplied will default to width) |
||
| 5638 | @param {Boolean} [crop=false] Whether to crop the image to exact dimensions |
||
| 5639 | @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) |
||
| 5640 | */ |
||
| 5641 | downsize: function(opts) { |
||
| 5642 | var defaults = { |
||
| 5643 | width: this.width, |
||
| 5644 | height: this.height, |
||
| 5645 | crop: false, |
||
| 5646 | preserveHeaders: true |
||
| 5647 | }; |
||
| 5648 | |||
| 5649 | if (typeof(opts) === 'object') { |
||
| 5650 | opts = Basic.extend(defaults, opts); |
||
| 5651 | } else { |
||
| 5652 | opts = Basic.extend(defaults, { |
||
| 5653 | width: arguments[0], |
||
| 5654 | height: arguments[1], |
||
| 5655 | crop: arguments[2], |
||
| 5656 | preserveHeaders: arguments[3] |
||
| 5657 | }); |
||
| 5658 | } |
||
| 5659 | |||
| 5660 | try { |
||
| 5661 | if (!this.size) { // only preloaded image objects can be used as source |
||
| 5662 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5663 | } |
||
| 5664 | |||
| 5665 | // no way to reliably intercept the crash due to high resolution, so we simply avoid it |
||
| 5666 | if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) { |
||
| 5667 | throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); |
||
| 5668 | } |
||
| 5669 | |||
| 5670 | this.getRuntime().exec.call(this, 'Image', 'downsize', opts.width, opts.height, opts.crop, opts.preserveHeaders); |
||
| 5671 | } catch(ex) { |
||
| 5672 | // for now simply trigger error event |
||
| 5673 | this.trigger('error', ex.code); |
||
| 5674 | } |
||
| 5675 | }, |
||
| 5676 | |||
| 5677 | /** |
||
| 5678 | Alias for downsize(width, height, true). (see downsize) |
||
| 5679 | |||
| 5680 | @method crop |
||
| 5681 | @param {Number} width Resulting width |
||
| 5682 | @param {Number} [height=width] Resulting height (optional, if not supplied will default to width) |
||
| 5683 | @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize) |
||
| 5684 | */ |
||
| 5685 | crop: function(width, height, preserveHeaders) { |
||
| 5686 | this.downsize(width, height, true, preserveHeaders); |
||
| 5687 | }, |
||
| 5688 | |||
| 5689 | getAsCanvas: function() { |
||
| 5690 | if (!Env.can('create_canvas')) { |
||
| 5691 | throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); |
||
| 5692 | } |
||
| 5693 | |||
| 5694 | var runtime = this.connectRuntime(this.ruid); |
||
| 5695 | return runtime.exec.call(this, 'Image', 'getAsCanvas'); |
||
| 5696 | }, |
||
| 5697 | |||
| 5698 | /** |
||
| 5699 | Retrieves image in it's current state as mOxie.Blob object. Cannot be run on empty or image in progress (throws |
||
| 5700 | DOMException.INVALID_STATE_ERR). |
||
| 5701 | |||
| 5702 | @method getAsBlob |
||
| 5703 | @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png |
||
| 5704 | @param {Number} [quality=90] Applicable only together with mime type image/jpeg |
||
| 5705 | @return {Blob} Image as Blob |
||
| 5706 | */ |
||
| 5707 | getAsBlob: function(type, quality) { |
||
| 5708 | if (!this.size) { |
||
| 5709 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5710 | } |
||
| 5711 | |||
| 5712 | if (!type) { |
||
| 5713 | type = 'image/jpeg'; |
||
| 5714 | } |
||
| 5715 | |||
| 5716 | if (type === 'image/jpeg' && !quality) { |
||
| 5717 | quality = 90; |
||
| 5718 | } |
||
| 5719 | |||
| 5720 | return this.getRuntime().exec.call(this, 'Image', 'getAsBlob', type, quality); |
||
| 5721 | }, |
||
| 5722 | |||
| 5723 | /** |
||
| 5724 | Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws |
||
| 5725 | DOMException.INVALID_STATE_ERR). |
||
| 5726 | |||
| 5727 | @method getAsDataURL |
||
| 5728 | @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png |
||
| 5729 | @param {Number} [quality=90] Applicable only together with mime type image/jpeg |
||
| 5730 | @return {String} Image as dataURL string |
||
| 5731 | */ |
||
| 5732 | getAsDataURL: function(type, quality) { |
||
| 5733 | if (!this.size) { |
||
| 5734 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5735 | } |
||
| 5736 | return this.getRuntime().exec.call(this, 'Image', 'getAsDataURL', type, quality); |
||
| 5737 | }, |
||
| 5738 | |||
| 5739 | /** |
||
| 5740 | Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws |
||
| 5741 | DOMException.INVALID_STATE_ERR). |
||
| 5742 | |||
| 5743 | @method getAsBinaryString |
||
| 5744 | @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png |
||
| 5745 | @param {Number} [quality=90] Applicable only together with mime type image/jpeg |
||
| 5746 | @return {String} Image as binary string |
||
| 5747 | */ |
||
| 5748 | getAsBinaryString: function(type, quality) { |
||
| 5749 | var dataUrl = this.getAsDataURL(type, quality); |
||
| 5750 | return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)); |
||
| 5751 | }, |
||
| 5752 | |||
| 5753 | /** |
||
| 5754 | Embeds a visual representation of the image into the specified node. Depending on the runtime, |
||
| 5755 | it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare, |
||
| 5756 | can be used in legacy browsers that do not have canvas or proper dataURI support). |
||
| 5757 | |||
| 5758 | @method embed |
||
| 5759 | @param {DOMElement} el DOM element to insert the image object into |
||
| 5760 | @param {Object} [options] |
||
| 5761 | @param {Number} [options.width] The width of an embed (defaults to the image width) |
||
| 5762 | @param {Number} [options.height] The height of an embed (defaults to the image height) |
||
| 5763 | @param {String} [type="image/jpeg"] Mime type |
||
| 5764 | @param {Number} [quality=90] Quality of an embed, if mime type is image/jpeg |
||
| 5765 | @param {Boolean} [crop=false] Whether to crop an embed to the specified dimensions |
||
| 5766 | */ |
||
| 5767 | embed: function(el) { |
||
| 5768 | var self = this |
||
| 5769 | , imgCopy |
||
| 5770 | , type, quality, crop |
||
| 5771 | , options = arguments[1] || {} |
||
| 5772 | , width = this.width |
||
| 5773 | , height = this.height |
||
| 5774 | , runtime // this has to be outside of all the closures to contain proper runtime |
||
| 5775 | ; |
||
| 5776 | |||
| 5777 | function onResize() { |
||
| 5778 | // if possible, embed a canvas element directly |
||
| 5779 | if (Env.can('create_canvas')) { |
||
| 5780 | var canvas = imgCopy.getAsCanvas(); |
||
| 5781 | if (canvas) { |
||
| 5782 | el.appendChild(canvas); |
||
| 5783 | canvas = null; |
||
| 5784 | imgCopy.destroy(); |
||
| 5785 | self.trigger('embedded'); |
||
| 5786 | return; |
||
| 5787 | } |
||
| 5788 | } |
||
| 5789 | |||
| 5790 | var dataUrl = imgCopy.getAsDataURL(type, quality); |
||
| 5791 | if (!dataUrl) { |
||
| 5792 | throw new x.ImageError(x.ImageError.WRONG_FORMAT); |
||
| 5793 | } |
||
| 5794 | |||
| 5795 | if (Env.can('use_data_uri_of', dataUrl.length)) { |
||
| 5796 | el.innerHTML = '<img src="' + dataUrl + '" width="' + imgCopy.width + '" height="' + imgCopy.height + '" />'; |
||
| 5797 | imgCopy.destroy(); |
||
| 5798 | self.trigger('embedded'); |
||
| 5799 | } else { |
||
| 5800 | var tr = new Transporter(); |
||
| 5801 | |||
| 5802 | tr.bind("TransportingComplete", function() { |
||
| 5803 | runtime = self.connectRuntime(this.result.ruid); |
||
| 5804 | |||
| 5805 | self.bind("Embedded", function() { |
||
| 5806 | // position and size properly |
||
| 5807 | Basic.extend(runtime.getShimContainer().style, { |
||
| 5808 | //position: 'relative', |
||
| 5809 | top: '0px', |
||
| 5810 | left: '0px', |
||
| 5811 | width: imgCopy.width + 'px', |
||
| 5812 | height: imgCopy.height + 'px' |
||
| 5813 | }); |
||
| 5814 | |||
| 5815 | // some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's |
||
| 5816 | // position type changes (in Gecko), but since we basically need this only in IEs 6/7 and |
||
| 5817 | // sometimes 8 and they do not have this problem, we can comment this for now |
||
| 5818 | /*tr.bind("RuntimeInit", function(e, runtime) { |
||
| 5819 | tr.destroy(); |
||
| 5820 | runtime.destroy(); |
||
| 5821 | onResize.call(self); // re-feed our image data |
||
| 5822 | });*/ |
||
| 5823 | |||
| 5824 | runtime = null; |
||
| 5825 | }, 999); |
||
| 5826 | |||
| 5827 | runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height); |
||
| 5828 | imgCopy.destroy(); |
||
| 5829 | }); |
||
| 5830 | |||
| 5831 | tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, Basic.extend({}, options, { |
||
| 5832 | required_caps: { |
||
| 5833 | display_media: true |
||
| 5834 | }, |
||
| 5835 | runtime_order: 'flash,silverlight', |
||
| 5836 | container: el |
||
| 5837 | })); |
||
| 5838 | } |
||
| 5839 | } |
||
| 5840 | |||
| 5841 | try { |
||
| 5842 | if (!(el = Dom.get(el))) { |
||
| 5843 | throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR); |
||
| 5844 | } |
||
| 5845 | |||
| 5846 | if (!this.size) { // only preloaded image objects can be used as source |
||
| 5847 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5848 | } |
||
| 5849 | |||
| 5850 | if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) { |
||
| 5851 | throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR); |
||
| 5852 | } |
||
| 5853 | |||
| 5854 | type = options.type || this.type || 'image/jpeg'; |
||
| 5855 | quality = options.quality || 90; |
||
| 5856 | crop = Basic.typeOf(options.crop) !== 'undefined' ? options.crop : false; |
||
| 5857 | |||
| 5858 | // figure out dimensions for the thumb |
||
| 5859 | if (options.width) { |
||
| 5860 | width = options.width; |
||
| 5861 | height = options.height || width; |
||
| 5862 | } else { |
||
| 5863 | // if container element has measurable dimensions, use them |
||
| 5864 | var dimensions = Dom.getSize(el); |
||
| 5865 | if (dimensions.w && dimensions.h) { // both should be > 0 |
||
| 5866 | width = dimensions.w; |
||
| 5867 | height = dimensions.h; |
||
| 5868 | } |
||
| 5869 | } |
||
| 5870 | |||
| 5871 | imgCopy = new Image(); |
||
| 5872 | |||
| 5873 | imgCopy.bind("Resize", function() { |
||
| 5874 | onResize.call(self); |
||
| 5875 | }); |
||
| 5876 | |||
| 5877 | imgCopy.bind("Load", function() { |
||
| 5878 | imgCopy.downsize(width, height, crop, false); |
||
| 5879 | }); |
||
| 5880 | |||
| 5881 | imgCopy.clone(this, false); |
||
| 5882 | |||
| 5883 | return imgCopy; |
||
| 5884 | } catch(ex) { |
||
| 5885 | // for now simply trigger error event |
||
| 5886 | this.trigger('error', ex.code); |
||
| 5887 | } |
||
| 5888 | }, |
||
| 5889 | |||
| 5890 | /** |
||
| 5891 | Properly destroys the image and frees resources in use. If any. Recommended way to dispose mOxie.Image object. |
||
| 5892 | |||
| 5893 | @method destroy |
||
| 5894 | */ |
||
| 5895 | destroy: function() { |
||
| 5896 | if (this.ruid) { |
||
| 5897 | this.getRuntime().exec.call(this, 'Image', 'destroy'); |
||
| 5898 | this.disconnectRuntime(); |
||
| 5899 | } |
||
| 5900 | this.unbindAll(); |
||
| 5901 | } |
||
| 5902 | }); |
||
| 5903 | |||
| 5904 | |||
| 5905 | function _updateInfo(info) { |
||
| 5906 | if (!info) { |
||
| 5907 | info = this.getRuntime().exec.call(this, 'Image', 'getInfo'); |
||
| 5908 | } |
||
| 5909 | |||
| 5910 | this.size = info.size; |
||
| 5911 | this.width = info.width; |
||
| 5912 | this.height = info.height; |
||
| 5913 | this.type = info.type; |
||
| 5914 | this.meta = info.meta; |
||
| 5915 | |||
| 5916 | // update file name, only if empty |
||
| 5917 | if (this.name === '') { |
||
| 5918 | this.name = info.name; |
||
| 5919 | } |
||
| 5920 | } |
||
| 5921 | |||
| 5922 | |||
| 5923 | function _load(src) { |
||
| 5924 | var srcType = Basic.typeOf(src); |
||
| 5925 | |||
| 5926 | try { |
||
| 5927 | // if source is Image |
||
| 5928 | if (src instanceof Image) { |
||
| 5929 | if (!src.size) { // only preloaded image objects can be used as source |
||
| 5930 | throw new x.DOMException(x.DOMException.INVALID_STATE_ERR); |
||
| 5931 | } |
||
| 5932 | _loadFromImage.apply(this, arguments); |
||
| 5933 | } |
||
| 5934 | // if source is o.Blob/o.File |
||
| 5935 | else if (src instanceof Blob) { |
||
| 5936 | if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) { |
||
| 5937 | throw new x.ImageError(x.ImageError.WRONG_FORMAT); |
||
| 5938 | } |
||
| 5939 | _loadFromBlob.apply(this, arguments); |
||
| 5940 | } |
||
| 5941 | // if native blob/file |
||
| 5942 | else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) { |
||
| 5943 | _load.call(this, new File(null, src), arguments[1]); |
||
| 5944 | } |
||
| 5945 | // if String |
||
| 5946 | else if (srcType === 'string') { |
||
| 5947 | // if dataUrl String |
||
| 5948 | if (/^data:[^;]*;base64,/.test(src)) { |
||
| 5949 | _load.call(this, new Blob(null, { data: src }), arguments[1]); |
||
| 5950 | } |
||
| 5951 | // else assume Url, either relative or absolute |
||
| 5952 | else { |
||
| 5953 | _loadFromUrl.apply(this, arguments); |
||
| 5954 | } |
||
| 5955 | } |
||
| 5956 | // if source seems to be an img node |
||
| 5957 | else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') { |
||
| 5958 | _load.call(this, src.src, arguments[1]); |
||
| 5959 | } |
||
| 5960 | else { |
||
| 5961 | throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR); |
||
| 5962 | } |
||
| 5963 | } catch(ex) { |
||
| 5964 | // for now simply trigger error event |
||
| 5965 | this.trigger('error', ex.code); |
||
| 5966 | } |
||
| 5967 | } |
||
| 5968 | |||
| 5969 | |||
| 5970 | function _loadFromImage(img, exact) { |
||
| 5971 | var runtime = this.connectRuntime(img.ruid); |
||
| 5972 | this.ruid = runtime.uid; |
||
| 5973 | runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact)); |
||
| 5974 | } |
||
| 5975 | |||
| 5976 | |||
| 5977 | function _loadFromBlob(blob, options) { |
||
| 5978 | var self = this; |
||
| 5979 | |||
| 5980 | self.name = blob.name || ''; |
||
| 5981 | |||
| 5982 | function exec(runtime) { |
||
| 5983 | self.ruid = runtime.uid; |
||
| 5984 | runtime.exec.call(self, 'Image', 'loadFromBlob', blob); |
||
| 5985 | } |
||
| 5986 | |||
| 5987 | if (blob.isDetached()) { |
||
| 5988 | this.bind('RuntimeInit', function(e, runtime) { |
||
| 5989 | exec(runtime); |
||
| 5990 | }); |
||
| 5991 | |||
| 5992 | // convert to object representation |
||
| 5993 | if (options && typeof(options.required_caps) === 'string') { |
||
| 5994 | options.required_caps = Runtime.parseCaps(options.required_caps); |
||
| 5995 | } |
||
| 5996 | |||
| 5997 | this.connectRuntime(Basic.extend({ |
||
| 5998 | required_caps: { |
||
| 5999 | access_image_binary: true, |
||
| 6000 | resize_image: true |
||
| 6001 | } |
||
| 6002 | }, options)); |
||
| 6003 | } else { |
||
| 6004 | exec(this.connectRuntime(blob.ruid)); |
||
| 6005 | } |
||
| 6006 | } |
||
| 6007 | |||
| 6008 | |||
| 6009 | function _loadFromUrl(url, options) { |
||
| 6010 | var self = this, xhr; |
||
| 6011 | |||
| 6012 | xhr = new XMLHttpRequest(); |
||
| 6013 | |||
| 6014 | xhr.open('get', url); |
||
| 6015 | xhr.responseType = 'blob'; |
||
| 6016 | |||
| 6017 | xhr.onprogress = function(e) { |
||
| 6018 | self.trigger(e); |
||
| 6019 | }; |
||
| 6020 | |||
| 6021 | xhr.onload = function() { |
||
| 6022 | _loadFromBlob.call(self, xhr.response, true); |
||
| 6023 | }; |
||
| 6024 | |||
| 6025 | xhr.onerror = function(e) { |
||
| 6026 | self.trigger(e); |
||
| 6027 | }; |
||
| 6028 | |||
| 6029 | xhr.onloadend = function() { |
||
| 6030 | xhr.destroy(); |
||
| 6031 | }; |
||
| 6032 | |||
| 6033 | xhr.bind('RuntimeError', function(e, err) { |
||
| 6034 | self.trigger('RuntimeError', err); |
||
| 6035 | }); |
||
| 6036 | |||
| 6037 | xhr.send(null, options); |
||
| 6038 | } |
||
| 6039 | } |
||
| 6040 | |||
| 6041 | // virtual world will crash on you if image has a resolution higher than this: |
||
| 6042 | Image.MAX_RESIZE_WIDTH = 6500; |
||
| 6043 | Image.MAX_RESIZE_HEIGHT = 6500; |
||
| 6044 | |||
| 6045 | Image.prototype = EventTarget.instance; |
||
| 6046 | |||
| 6047 | return Image; |
||
| 6048 | }); |
||
| 6049 | |||
| 6050 | // Included from: src/javascript/runtime/html5/Runtime.js |
||
| 6051 | |||
| 6052 | /** |
||
| 6053 | * Runtime.js |
||
| 6054 | * |
||
| 6055 | * Copyright 2013, Moxiecode Systems AB |
||
| 6056 | * Released under GPL License. |
||
| 6057 | * |
||
| 6058 | * License: http://www.plupload.com/license |
||
| 6059 | * Contributing: http://www.plupload.com/contributing |
||
| 6060 | */ |
||
| 6061 | |||
| 6062 | /*global File:true */ |
||
| 6063 | |||
| 6064 | /** |
||
| 6065 | Defines constructor for HTML5 runtime. |
||
| 6066 | |||
| 6067 | @class moxie/runtime/html5/Runtime |
||
| 6068 | @private |
||
| 6069 | */ |
||
| 6070 | define("moxie/runtime/html5/Runtime", [ |
||
| 6071 | "moxie/core/utils/Basic", |
||
| 6072 | "moxie/core/Exceptions", |
||
| 6073 | "moxie/runtime/Runtime", |
||
| 6074 | "moxie/core/utils/Env" |
||
| 6075 | ], function(Basic, x, Runtime, Env) { |
||
| 6076 | |||
| 6077 | var type = "html5", extensions = {}; |
||
| 6078 | |||
| 6079 | function Html5Runtime(options) { |
||
| 6080 | var I = this |
||
| 6081 | , Test = Runtime.capTest |
||
| 6082 | , True = Runtime.capTrue |
||
| 6083 | ; |
||
| 6084 | |||
| 6085 | var caps = Basic.extend({ |
||
| 6086 | access_binary: Test(window.FileReader || window.File && window.File.getAsDataURL), |
||
| 6087 | access_image_binary: function() { |
||
| 6088 | return I.can('access_binary') && !!extensions.Image; |
||
| 6089 | }, |
||
| 6090 | display_media: Test(Env.can('create_canvas') || Env.can('use_data_uri_over32kb')), |
||
| 6091 | do_cors: Test(window.XMLHttpRequest && 'withCredentials' in new XMLHttpRequest()), |
||
| 6092 | drag_and_drop: Test(function() { |
||
| 6093 | // this comes directly from Modernizr: http://www.modernizr.com/ |
||
| 6094 | var div = document.createElement('div'); |
||
| 6095 | // IE has support for drag and drop since version 5, but doesn't support dropping files from desktop |
||
| 6096 | return (('draggable' in div) || ('ondragstart' in div && 'ondrop' in div)) && (Env.browser !== 'IE' || Env.version > 9); |
||
| 6097 | }()), |
||
| 6098 | filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest |
||
| 6099 | return (Env.browser === 'Chrome' && Env.version >= 28) || (Env.browser === 'IE' && Env.version >= 10); |
||
| 6100 | }()), |
||
| 6101 | return_response_headers: True, |
||
| 6102 | return_response_type: function(responseType) { |
||
| 6103 | if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported |
||
| 6104 | return true; |
||
| 6105 | } |
||
| 6106 | return Env.can('return_response_type', responseType); |
||
| 6107 | }, |
||
| 6108 | return_status_code: True, |
||
| 6109 | report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload), |
||
| 6110 | resize_image: function() { |
||
| 6111 | return I.can('access_binary') && Env.can('create_canvas'); |
||
| 6112 | }, |
||
| 6113 | select_file: function() { |
||
| 6114 | return Env.can('use_fileinput') && window.File; |
||
| 6115 | }, |
||
| 6116 | select_folder: function() { |
||
| 6117 | return I.can('select_file') && Env.browser === 'Chrome' && Env.version >= 21; |
||
| 6118 | }, |
||
| 6119 | select_multiple: function() { |
||
| 6120 | // it is buggy on Safari Windows and iOS |
||
| 6121 | return I.can('select_file') && |
||
| 6122 | !(Env.browser === 'Safari' && Env.os === 'Windows') && |
||
| 6123 | !(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.4", '<')); |
||
| 6124 | }, |
||
| 6125 | send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))), |
||
| 6126 | send_custom_headers: Test(window.XMLHttpRequest), |
||
| 6127 | send_multipart: function() { |
||
| 6128 | return !!(window.XMLHttpRequest && new XMLHttpRequest().upload && window.FormData) || I.can('send_binary_string'); |
||
| 6129 | }, |
||
| 6130 | slice_blob: Test(window.File && (File.prototype.mozSlice || File.prototype.webkitSlice || File.prototype.slice)), |
||
| 6131 | stream_upload: function(){ |
||
| 6132 | return I.can('slice_blob') && I.can('send_multipart'); |
||
| 6133 | }, |
||
| 6134 | summon_file_dialog: Test(function() { // yeah... some dirty sniffing here... |
||
| 6135 | return (Env.browser === 'Firefox' && Env.version >= 4) || |
||
| 6136 | (Env.browser === 'Opera' && Env.version >= 12) || |
||
| 6137 | (Env.browser === 'IE' && Env.version >= 10) || |
||
| 6138 | !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']); |
||
| 6139 | }()), |
||
| 6140 | upload_filesize: True |
||
| 6141 | }, |
||
| 6142 | arguments[2] |
||
| 6143 | ); |
||
| 6144 | |||
| 6145 | Runtime.call(this, options, (arguments[1] || type), caps); |
||
| 6146 | |||
| 6147 | |||
| 6148 | Basic.extend(this, { |
||
| 6149 | |||
| 6150 | init : function() { |
||
| 6151 | this.trigger("Init"); |
||
| 6152 | }, |
||
| 6153 | |||
| 6154 | destroy: (function(destroy) { // extend default destroy method |
||
| 6155 | return function() { |
||
| 6156 | destroy.call(I); |
||
| 6157 | destroy = I = null; |
||
| 6158 | }; |
||
| 6159 | }(this.destroy)) |
||
| 6160 | }); |
||
| 6161 | |||
| 6162 | Basic.extend(this.getShim(), extensions); |
||
| 6163 | } |
||
| 6164 | |||
| 6165 | Runtime.addConstructor(type, Html5Runtime); |
||
| 6166 | |||
| 6167 | return extensions; |
||
| 6168 | }); |
||
| 6169 | |||
| 6170 | // Included from: src/javascript/runtime/html5/file/Blob.js |
||
| 6171 | |||
| 6172 | /** |
||
| 6173 | * Blob.js |
||
| 6174 | * |
||
| 6175 | * Copyright 2013, Moxiecode Systems AB |
||
| 6176 | * Released under GPL License. |
||
| 6177 | * |
||
| 6178 | * License: http://www.plupload.com/license |
||
| 6179 | * Contributing: http://www.plupload.com/contributing |
||
| 6180 | */ |
||
| 6181 | |||
| 6182 | /** |
||
| 6183 | @class moxie/runtime/html5/file/Blob |
||
| 6184 | @private |
||
| 6185 | */ |
||
| 6186 | define("moxie/runtime/html5/file/Blob", [ |
||
| 6187 | "moxie/runtime/html5/Runtime", |
||
| 6188 | "moxie/file/Blob" |
||
| 6189 | ], function(extensions, Blob) { |
||
| 6190 | |||
| 6191 | function HTML5Blob() { |
||
| 6192 | function w3cBlobSlice(blob, start, end) { |
||
| 6193 | var blobSlice; |
||
| 6194 | |||
| 6195 | if (window.File.prototype.slice) { |
||
| 6196 | try { |
||
| 6197 | blob.slice(); // depricated version will throw WRONG_ARGUMENTS_ERR exception |
||
| 6198 | return blob.slice(start, end); |
||
| 6199 | } catch (e) { |
||
| 6200 | // depricated slice method |
||
| 6201 | return blob.slice(start, end - start); |
||
| 6202 | } |
||
| 6203 | // slice method got prefixed: https://bugzilla.mozilla.org/show_bug.cgi?id=649672 |
||
| 6204 | } else if ((blobSlice = window.File.prototype.webkitSlice || window.File.prototype.mozSlice)) { |
||
| 6205 | return blobSlice.call(blob, start, end); |
||
| 6206 | } else { |
||
| 6207 | return null; // or throw some exception |
||
| 6208 | } |
||
| 6209 | } |
||
| 6210 | |||
| 6211 | this.slice = function() { |
||
| 6212 | return new Blob(this.getRuntime().uid, w3cBlobSlice.apply(this, arguments)); |
||
| 6213 | }; |
||
| 6214 | } |
||
| 6215 | |||
| 6216 | return (extensions.Blob = HTML5Blob); |
||
| 6217 | }); |
||
| 6218 | |||
| 6219 | // Included from: src/javascript/core/utils/Events.js |
||
| 6220 | |||
| 6221 | /** |
||
| 6222 | * Events.js |
||
| 6223 | * |
||
| 6224 | * Copyright 2013, Moxiecode Systems AB |
||
| 6225 | * Released under GPL License. |
||
| 6226 | * |
||
| 6227 | * License: http://www.plupload.com/license |
||
| 6228 | * Contributing: http://www.plupload.com/contributing |
||
| 6229 | */ |
||
| 6230 | |||
| 6231 | define('moxie/core/utils/Events', [ |
||
| 6232 | 'moxie/core/utils/Basic' |
||
| 6233 | ], function(Basic) { |
||
| 6234 | var eventhash = {}, uid = 'moxie_' + Basic.guid(); |
||
| 6235 | |||
| 6236 | // IE W3C like event funcs |
||
| 6237 | function preventDefault() { |
||
| 6238 | this.returnValue = false; |
||
| 6239 | } |
||
| 6240 | |||
| 6241 | function stopPropagation() { |
||
| 6242 | this.cancelBubble = true; |
||
| 6243 | } |
||
| 6244 | |||
| 6245 | /** |
||
| 6246 | Adds an event handler to the specified object and store reference to the handler |
||
| 6247 | in objects internal Plupload registry (@see removeEvent). |
||
| 6248 | |||
| 6249 | @method addEvent |
||
| 6250 | @for Utils |
||
| 6251 | @static |
||
| 6252 | @param {Object} obj DOM element like object to add handler to. |
||
| 6253 | @param {String} name Name to add event listener to. |
||
| 6254 | @param {Function} callback Function to call when event occurs. |
||
| 6255 | @param {String} [key] that might be used to add specifity to the event record. |
||
| 6256 | */ |
||
| 6257 | var addEvent = function(obj, name, callback, key) { |
||
| 6258 | var func, events; |
||
| 6259 | |||
| 6260 | name = name.toLowerCase(); |
||
| 6261 | |||
| 6262 | // Add event listener |
||
| 6263 | if (obj.addEventListener) { |
||
| 6264 | func = callback; |
||
| 6265 | |||
| 6266 | obj.addEventListener(name, func, false); |
||
| 6267 | } else if (obj.attachEvent) { |
||
| 6268 | func = function() { |
||
| 6269 | var evt = window.event; |
||
| 6270 | |||
| 6271 | if (!evt.target) { |
||
| 6272 | evt.target = evt.srcElement; |
||
| 6273 | } |
||
| 6274 | |||
| 6275 | evt.preventDefault = preventDefault; |
||
| 6276 | evt.stopPropagation = stopPropagation; |
||
| 6277 | |||
| 6278 | callback(evt); |
||
| 6279 | }; |
||
| 6280 | |||
| 6281 | obj.attachEvent('on' + name, func); |
||
| 6282 | } |
||
| 6283 | |||
| 6284 | // Log event handler to objects internal mOxie registry |
||
| 6285 | if (!obj[uid]) { |
||
| 6286 | obj[uid] = Basic.guid(); |
||
| 6287 | } |
||
| 6288 | |||
| 6289 | if (!eventhash.hasOwnProperty(obj[uid])) { |
||
| 6290 | eventhash[obj[uid]] = {}; |
||
| 6291 | } |
||
| 6292 | |||
| 6293 | events = eventhash[obj[uid]]; |
||
| 6294 | |||
| 6295 | if (!events.hasOwnProperty(name)) { |
||
| 6296 | events[name] = []; |
||
| 6297 | } |
||
| 6298 | |||
| 6299 | events[name].push({ |
||
| 6300 | func: func, |
||
| 6301 | orig: callback, // store original callback for IE |
||
| 6302 | key: key |
||
| 6303 | }); |
||
| 6304 | }; |
||
| 6305 | |||
| 6306 | |||
| 6307 | /** |
||
| 6308 | Remove event handler from the specified object. If third argument (callback) |
||
| 6309 | is not specified remove all events with the specified name. |
||
| 6310 | |||
| 6311 | @method removeEvent |
||
| 6312 | @static |
||
| 6313 | @param {Object} obj DOM element to remove event listener(s) from. |
||
| 6314 | @param {String} name Name of event listener to remove. |
||
| 6315 | @param {Function|String} [callback] might be a callback or unique key to match. |
||
| 6316 | */ |
||
| 6317 | var removeEvent = function(obj, name, callback) { |
||
| 6318 | var type, undef; |
||
| 6319 | |||
| 6320 | name = name.toLowerCase(); |
||
| 6321 | |||
| 6322 | if (obj[uid] && eventhash[obj[uid]] && eventhash[obj[uid]][name]) { |
||
| 6323 | type = eventhash[obj[uid]][name]; |
||
| 6324 | } else { |
||
| 6325 | return; |
||
| 6326 | } |
||
| 6327 | |||
| 6328 | for (var i = type.length - 1; i >= 0; i--) { |
||
| 6329 | // undefined or not, key should match |
||
| 6330 | if (type[i].orig === callback || type[i].key === callback) { |
||
| 6331 | if (obj.removeEventListener) { |
||
| 6332 | obj.removeEventListener(name, type[i].func, false); |
||
| 6333 | } else if (obj.detachEvent) { |
||
| 6334 | obj.detachEvent('on'+name, type[i].func); |
||
| 6335 | } |
||
| 6336 | |||
| 6337 | type[i].orig = null; |
||
| 6338 | type[i].func = null; |
||
| 6339 | type.splice(i, 1); |
||
| 6340 | |||
| 6341 | // If callback was passed we are done here, otherwise proceed |
||
| 6342 | if (callback !== undef) { |
||
| 6343 | break; |
||
| 6344 | } |
||
| 6345 | } |
||
| 6346 | } |
||
| 6347 | |||
| 6348 | // If event array got empty, remove it |
||
| 6349 | if (!type.length) { |
||
| 6350 | delete eventhash[obj[uid]][name]; |
||
| 6351 | } |
||
| 6352 | |||
| 6353 | // If mOxie registry has become empty, remove it |
||
| 6354 | if (Basic.isEmptyObj(eventhash[obj[uid]])) { |
||
| 6355 | delete eventhash[obj[uid]]; |
||
| 6356 | |||
| 6357 | // IE doesn't let you remove DOM object property with - delete |
||
| 6358 | try { |
||
| 6359 | delete obj[uid]; |
||
| 6360 | } catch(e) { |
||
| 6361 | obj[uid] = undef; |
||
| 6362 | } |
||
| 6363 | } |
||
| 6364 | }; |
||
| 6365 | |||
| 6366 | |||
| 6367 | /** |
||
| 6368 | Remove all kind of events from the specified object |
||
| 6369 | |||
| 6370 | @method removeAllEvents |
||
| 6371 | @static |
||
| 6372 | @param {Object} obj DOM element to remove event listeners from. |
||
| 6373 | @param {String} [key] unique key to match, when removing events. |
||
| 6374 | */ |
||
| 6375 | var removeAllEvents = function(obj, key) { |
||
| 6376 | if (!obj || !obj[uid]) { |
||
| 6377 | return; |
||
| 6378 | } |
||
| 6379 | |||
| 6380 | Basic.each(eventhash[obj[uid]], function(events, name) { |
||
| 6381 | removeEvent(obj, name, key); |
||
| 6382 | }); |
||
| 6383 | }; |
||
| 6384 | |||
| 6385 | return { |
||
| 6386 | addEvent: addEvent, |
||
| 6387 | removeEvent: removeEvent, |
||
| 6388 | removeAllEvents: removeAllEvents |
||
| 6389 | }; |
||
| 6390 | }); |
||
| 6391 | |||
| 6392 | // Included from: src/javascript/runtime/html5/file/FileInput.js |
||
| 6393 | |||
| 6394 | /** |
||
| 6395 | * FileInput.js |
||
| 6396 | * |
||
| 6397 | * Copyright 2013, Moxiecode Systems AB |
||
| 6398 | * Released under GPL License. |
||
| 6399 | * |
||
| 6400 | * License: http://www.plupload.com/license |
||
| 6401 | * Contributing: http://www.plupload.com/contributing |
||
| 6402 | */ |
||
| 6403 | |||
| 6404 | /** |
||
| 6405 | @class moxie/runtime/html5/file/FileInput |
||
| 6406 | @private |
||
| 6407 | */ |
||
| 6408 | define("moxie/runtime/html5/file/FileInput", [ |
||
| 6409 | "moxie/runtime/html5/Runtime", |
||
| 6410 | "moxie/core/utils/Basic", |
||
| 6411 | "moxie/core/utils/Dom", |
||
| 6412 | "moxie/core/utils/Events", |
||
| 6413 | "moxie/core/utils/Mime", |
||
| 6414 | "moxie/core/utils/Env" |
||
| 6415 | ], function(extensions, Basic, Dom, Events, Mime, Env) { |
||
| 6416 | |||
| 6417 | function FileInput() { |
||
| 6418 | var _files = [], _options; |
||
| 6419 | |||
| 6420 | Basic.extend(this, { |
||
| 6421 | init: function(options) { |
||
| 6422 | var comp = this, I = comp.getRuntime(), input, shimContainer, mimes, browseButton, zIndex, top; |
||
| 6423 | |||
| 6424 | _options = options; |
||
| 6425 | _files = []; |
||
| 6426 | |||
| 6427 | // figure out accept string |
||
| 6428 | mimes = _options.accept.mimes || Mime.extList2mimes(_options.accept, I.can('filter_by_extension')); |
||
| 6429 | |||
| 6430 | shimContainer = I.getShimContainer(); |
||
| 6431 | |||
| 6432 | shimContainer.innerHTML = '<input id="' + I.uid +'" type="file" style="font-size:999px;opacity:0;"' + |
||
| 6433 | (_options.multiple && I.can('select_multiple') ? 'multiple' : '') + |
||
| 6434 | (_options.directory && I.can('select_folder') ? 'webkitdirectory directory' : '') + // Chrome 11+ |
||
| 6435 | (mimes ? ' accept="' + mimes.join(',') + '"' : '') + ' />'; |
||
| 6436 | |||
| 6437 | input = Dom.get(I.uid); |
||
| 6438 | |||
| 6439 | // prepare file input to be placed underneath the browse_button element |
||
| 6440 | Basic.extend(input.style, { |
||
| 6441 | position: 'absolute', |
||
| 6442 | top: 0, |
||
| 6443 | left: 0, |
||
| 6444 | width: '100%', |
||
| 6445 | height: '100%' |
||
| 6446 | }); |
||
| 6447 | |||
| 6448 | |||
| 6449 | browseButton = Dom.get(_options.browse_button); |
||
| 6450 | |||
| 6451 | // Route click event to the input[type=file] element for browsers that support such behavior |
||
| 6452 | if (I.can('summon_file_dialog')) { |
||
| 6453 | if (Dom.getStyle(browseButton, 'position') === 'static') { |
||
| 6454 | browseButton.style.position = 'relative'; |
||
| 6455 | } |
||
| 6456 | |||
| 6457 | zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1; |
||
| 6458 | |||
| 6459 | browseButton.style.zIndex = zIndex; |
||
| 6460 | shimContainer.style.zIndex = zIndex - 1; |
||
| 6461 | |||
| 6462 | Events.addEvent(browseButton, 'click', function(e) { |
||
| 6463 | var input = Dom.get(I.uid); |
||
| 6464 | if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] |
||
| 6465 | input.click(); |
||
| 6466 | } |
||
| 6467 | e.preventDefault(); |
||
| 6468 | }, comp.uid); |
||
| 6469 | } |
||
| 6470 | |||
| 6471 | /* Since we have to place input[type=file] on top of the browse_button for some browsers, |
||
| 6472 | browse_button loses interactivity, so we restore it here */ |
||
| 6473 | top = I.can('summon_file_dialog') ? browseButton : shimContainer; |
||
| 6474 | |||
| 6475 | Events.addEvent(top, 'mouseover', function() { |
||
| 6476 | comp.trigger('mouseenter'); |
||
| 6477 | }, comp.uid); |
||
| 6478 | |||
| 6479 | Events.addEvent(top, 'mouseout', function() { |
||
| 6480 | comp.trigger('mouseleave'); |
||
| 6481 | }, comp.uid); |
||
| 6482 | |||
| 6483 | Events.addEvent(top, 'mousedown', function() { |
||
| 6484 | comp.trigger('mousedown'); |
||
| 6485 | }, comp.uid); |
||
| 6486 | |||
| 6487 | Events.addEvent(Dom.get(_options.container), 'mouseup', function() { |
||
| 6488 | comp.trigger('mouseup'); |
||
| 6489 | }, comp.uid); |
||
| 6490 | |||
| 6491 | |||
| 6492 | input.onchange = function onChange() { // there should be only one handler for this |
||
| 6493 | _files = []; |
||
| 6494 | |||
| 6495 | if (_options.directory) { |
||
| 6496 | // folders are represented by dots, filter them out (Chrome 11+) |
||
| 6497 | Basic.each(this.files, function(file) { |
||
| 6498 | if (file.name !== ".") { // if it doesn't looks like a folder |
||
| 6499 | _files.push(file); |
||
| 6500 | } |
||
| 6501 | }); |
||
| 6502 | } else { |
||
| 6503 | _files = [].slice.call(this.files); |
||
| 6504 | } |
||
| 6505 | |||
| 6506 | // clearing the value enables the user to select the same file again if they want to |
||
| 6507 | if (Env.browser !== 'IE' && Env.browser !== 'IEMobile') { |
||
| 6508 | this.value = ''; |
||
| 6509 | } else { |
||
| 6510 | // in IE input[type="file"] is read-only so the only way to reset it is to re-insert it |
||
| 6511 | var clone = this.cloneNode(true); |
||
| 6512 | this.parentNode.replaceChild(clone, this); |
||
| 6513 | clone.onchange = onChange; |
||
| 6514 | } |
||
| 6515 | comp.trigger('change'); |
||
| 6516 | }; |
||
| 6517 | |||
| 6518 | // ready event is perfectly asynchronous |
||
| 6519 | comp.trigger({ |
||
| 6520 | type: 'ready', |
||
| 6521 | async: true |
||
| 6522 | }); |
||
| 6523 | |||
| 6524 | shimContainer = null; |
||
| 6525 | }, |
||
| 6526 | |||
| 6527 | getFiles: function() { |
||
| 6528 | return _files; |
||
| 6529 | }, |
||
| 6530 | |||
| 6531 | disable: function(state) { |
||
| 6532 | var I = this.getRuntime(), input; |
||
| 6533 | |||
| 6534 | if ((input = Dom.get(I.uid))) { |
||
| 6535 | input.disabled = !!state; |
||
| 6536 | } |
||
| 6537 | }, |
||
| 6538 | |||
| 6539 | destroy: function() { |
||
| 6540 | var I = this.getRuntime() |
||
| 6541 | , shim = I.getShim() |
||
| 6542 | , shimContainer = I.getShimContainer() |
||
| 6543 | ; |
||
| 6544 | |||
| 6545 | Events.removeAllEvents(shimContainer, this.uid); |
||
| 6546 | Events.removeAllEvents(_options && Dom.get(_options.container), this.uid); |
||
| 6547 | Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid); |
||
| 6548 | |||
| 6549 | if (shimContainer) { |
||
| 6550 | shimContainer.innerHTML = ''; |
||
| 6551 | } |
||
| 6552 | |||
| 6553 | shim.removeInstance(this.uid); |
||
| 6554 | |||
| 6555 | _files = _options = shimContainer = shim = null; |
||
| 6556 | } |
||
| 6557 | }); |
||
| 6558 | } |
||
| 6559 | |||
| 6560 | return (extensions.FileInput = FileInput); |
||
| 6561 | }); |
||
| 6562 | |||
| 6563 | // Included from: src/javascript/runtime/html5/file/FileDrop.js |
||
| 6564 | |||
| 6565 | /** |
||
| 6566 | * FileDrop.js |
||
| 6567 | * |
||
| 6568 | * Copyright 2013, Moxiecode Systems AB |
||
| 6569 | * Released under GPL License. |
||
| 6570 | * |
||
| 6571 | * License: http://www.plupload.com/license |
||
| 6572 | * Contributing: http://www.plupload.com/contributing |
||
| 6573 | */ |
||
| 6574 | |||
| 6575 | /** |
||
| 6576 | @class moxie/runtime/html5/file/FileDrop |
||
| 6577 | @private |
||
| 6578 | */ |
||
| 6579 | define("moxie/runtime/html5/file/FileDrop", [ |
||
| 6580 | "moxie/runtime/html5/Runtime", |
||
| 6581 | "moxie/core/utils/Basic", |
||
| 6582 | "moxie/core/utils/Dom", |
||
| 6583 | "moxie/core/utils/Events", |
||
| 6584 | "moxie/core/utils/Mime" |
||
| 6585 | ], function(extensions, Basic, Dom, Events, Mime) { |
||
| 6586 | |||
| 6587 | function FileDrop() { |
||
| 6588 | var _files = [], _allowedExts = [], _options; |
||
| 6589 | |||
| 6590 | Basic.extend(this, { |
||
| 6591 | init: function(options) { |
||
| 6592 | var comp = this, dropZone; |
||
| 6593 | |||
| 6594 | _options = options; |
||
| 6595 | _allowedExts = _extractExts(_options.accept); |
||
| 6596 | dropZone = _options.container; |
||
| 6597 | |||
| 6598 | Events.addEvent(dropZone, 'dragover', function(e) { |
||
| 6599 | if (!_hasFiles(e)) { |
||
| 6600 | return; |
||
| 6601 | } |
||
| 6602 | e.preventDefault(); |
||
| 6603 | e.dataTransfer.dropEffect = 'copy'; |
||
| 6604 | }, comp.uid); |
||
| 6605 | |||
| 6606 | Events.addEvent(dropZone, 'drop', function(e) { |
||
| 6607 | if (!_hasFiles(e)) { |
||
| 6608 | return; |
||
| 6609 | } |
||
| 6610 | e.preventDefault(); |
||
| 6611 | |||
| 6612 | _files = []; |
||
| 6613 | |||
| 6614 | // Chrome 21+ accepts folders via Drag'n'Drop |
||
| 6615 | if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) { |
||
| 6616 | _readItems(e.dataTransfer.items, function() { |
||
| 6617 | comp.trigger("drop"); |
||
| 6618 | }); |
||
| 6619 | } else { |
||
| 6620 | Basic.each(e.dataTransfer.files, function(file) { |
||
| 6621 | if (_isAcceptable(file)) { |
||
| 6622 | _files.push(file); |
||
| 6623 | } |
||
| 6624 | }); |
||
| 6625 | comp.trigger("drop"); |
||
| 6626 | } |
||
| 6627 | }, comp.uid); |
||
| 6628 | |||
| 6629 | Events.addEvent(dropZone, 'dragenter', function(e) { |
||
| 6630 | comp.trigger("dragenter"); |
||
| 6631 | }, comp.uid); |
||
| 6632 | |||
| 6633 | Events.addEvent(dropZone, 'dragleave', function(e) { |
||
| 6634 | comp.trigger("dragleave"); |
||
| 6635 | }, comp.uid); |
||
| 6636 | }, |
||
| 6637 | |||
| 6638 | getFiles: function() { |
||
| 6639 | return _files; |
||
| 6640 | }, |
||
| 6641 | |||
| 6642 | destroy: function() { |
||
| 6643 | Events.removeAllEvents(_options && Dom.get(_options.container), this.uid); |
||
| 6644 | _files = _allowedExts = _options = null; |
||
| 6645 | } |
||
| 6646 | }); |
||
| 6647 | |||
| 6648 | |||
| 6649 | function _hasFiles(e) { |
||
| 6650 | if (!e.dataTransfer || !e.dataTransfer.types) { // e.dataTransfer.files is not available in Gecko during dragover |
||
| 6651 | return false; |
||
| 6652 | } |
||
| 6653 | |||
| 6654 | var types = Basic.toArray(e.dataTransfer.types || []); |
||
| 6655 | |||
| 6656 | return Basic.inArray("Files", types) !== -1 || |
||
| 6657 | Basic.inArray("public.file-url", types) !== -1 || // Safari < 5 |
||
| 6658 | Basic.inArray("application/x-moz-file", types) !== -1 // Gecko < 1.9.2 (< Firefox 3.6) |
||
| 6659 | ; |
||
| 6660 | } |
||
| 6661 | |||
| 6662 | |||
| 6663 | function _extractExts(accept) { |
||
| 6664 | var exts = []; |
||
| 6665 | for (var i = 0; i < accept.length; i++) { |
||
| 6666 | [].push.apply(exts, accept[i].extensions.split(/\s*,\s*/)); |
||
| 6667 | } |
||
| 6668 | return Basic.inArray('*', exts) === -1 ? exts : []; |
||
| 6669 | } |
||
| 6670 | |||
| 6671 | |||
| 6672 | function _isAcceptable(file) { |
||
| 6673 | if (!_allowedExts.length) { |
||
| 6674 | return true; |
||
| 6675 | } |
||
| 6676 | var ext = Mime.getFileExtension(file.name); |
||
| 6677 | return !ext || Basic.inArray(ext, _allowedExts) !== -1; |
||
| 6678 | } |
||
| 6679 | |||
| 6680 | |||
| 6681 | function _readItems(items, cb) { |
||
| 6682 | var entries = []; |
||
| 6683 | Basic.each(items, function(item) { |
||
| 6684 | var entry = item.webkitGetAsEntry(); |
||
| 6685 | // Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579) |
||
| 6686 | if (entry) { |
||
| 6687 | // file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61 |
||
| 6688 | if (entry.isFile) { |
||
| 6689 | var file = item.getAsFile(); |
||
| 6690 | if (_isAcceptable(file)) { |
||
| 6691 | _files.push(file); |
||
| 6692 | } |
||
| 6693 | } else { |
||
| 6694 | entries.push(entry); |
||
| 6695 | } |
||
| 6696 | } |
||
| 6697 | }); |
||
| 6698 | |||
| 6699 | if (entries.length) { |
||
| 6700 | _readEntries(entries, cb); |
||
| 6701 | } else { |
||
| 6702 | cb(); |
||
| 6703 | } |
||
| 6704 | } |
||
| 6705 | |||
| 6706 | |||
| 6707 | function _readEntries(entries, cb) { |
||
| 6708 | var queue = []; |
||
| 6709 | Basic.each(entries, function(entry) { |
||
| 6710 | queue.push(function(cbcb) { |
||
| 6711 | _readEntry(entry, cbcb); |
||
| 6712 | }); |
||
| 6713 | }); |
||
| 6714 | Basic.inSeries(queue, function() { |
||
| 6715 | cb(); |
||
| 6716 | }); |
||
| 6717 | } |
||
| 6718 | |||
| 6719 | |||
| 6720 | function _readEntry(entry, cb) { |
||
| 6721 | if (entry.isFile) { |
||
| 6722 | entry.file(function(file) { |
||
| 6723 | if (_isAcceptable(file)) { |
||
| 6724 | _files.push(file); |
||
| 6725 | } |
||
| 6726 | cb(); |
||
| 6727 | }, function() { |
||
| 6728 | // fire an error event maybe |
||
| 6729 | cb(); |
||
| 6730 | }); |
||
| 6731 | } else if (entry.isDirectory) { |
||
| 6732 | _readDirEntry(entry, cb); |
||
| 6733 | } else { |
||
| 6734 | cb(); // not file, not directory? what then?.. |
||
| 6735 | } |
||
| 6736 | } |
||
| 6737 | |||
| 6738 | |||
| 6739 | function _readDirEntry(dirEntry, cb) { |
||
| 6740 | var entries = [], dirReader = dirEntry.createReader(); |
||
| 6741 | |||
| 6742 | // keep quering recursively till no more entries |
||
| 6743 | function getEntries(cbcb) { |
||
| 6744 | dirReader.readEntries(function(moreEntries) { |
||
| 6745 | if (moreEntries.length) { |
||
| 6746 | [].push.apply(entries, moreEntries); |
||
| 6747 | getEntries(cbcb); |
||
| 6748 | } else { |
||
| 6749 | cbcb(); |
||
| 6750 | } |
||
| 6751 | }, cbcb); |
||
| 6752 | } |
||
| 6753 | |||
| 6754 | // ...and you thought FileReader was crazy... |
||
| 6755 | getEntries(function() { |
||
| 6756 | _readEntries(entries, cb); |
||
| 6757 | }); |
||
| 6758 | } |
||
| 6759 | } |
||
| 6760 | |||
| 6761 | return (extensions.FileDrop = FileDrop); |
||
| 6762 | }); |
||
| 6763 | |||
| 6764 | // Included from: src/javascript/runtime/html5/file/FileReader.js |
||
| 6765 | |||
| 6766 | /** |
||
| 6767 | * FileReader.js |
||
| 6768 | * |
||
| 6769 | * Copyright 2013, Moxiecode Systems AB |
||
| 6770 | * Released under GPL License. |
||
| 6771 | * |
||
| 6772 | * License: http://www.plupload.com/license |
||
| 6773 | * Contributing: http://www.plupload.com/contributing |
||
| 6774 | */ |
||
| 6775 | |||
| 6776 | /** |
||
| 6777 | @class moxie/runtime/html5/file/FileReader |
||
| 6778 | @private |
||
| 6779 | */ |
||
| 6780 | define("moxie/runtime/html5/file/FileReader", [ |
||
| 6781 | "moxie/runtime/html5/Runtime", |
||
| 6782 | "moxie/core/utils/Encode", |
||
| 6783 | "moxie/core/utils/Basic" |
||
| 6784 | ], function(extensions, Encode, Basic) { |
||
| 6785 | |||
| 6786 | function FileReader() { |
||
| 6787 | var _fr, _convertToBinary = false; |
||
| 6788 | |||
| 6789 | Basic.extend(this, { |
||
| 6790 | |||
| 6791 | read: function(op, blob) { |
||
| 6792 | var target = this; |
||
| 6793 | |||
| 6794 | _fr = new window.FileReader(); |
||
| 6795 | |||
| 6796 | _fr.addEventListener('progress', function(e) { |
||
| 6797 | target.trigger(e); |
||
| 6798 | }); |
||
| 6799 | |||
| 6800 | _fr.addEventListener('load', function(e) { |
||
| 6801 | target.trigger(e); |
||
| 6802 | }); |
||
| 6803 | |||
| 6804 | _fr.addEventListener('error', function(e) { |
||
| 6805 | target.trigger(e, _fr.error); |
||
| 6806 | }); |
||
| 6807 | |||
| 6808 | _fr.addEventListener('loadend', function() { |
||
| 6809 | _fr = null; |
||
| 6810 | }); |
||
| 6811 | |||
| 6812 | if (Basic.typeOf(_fr[op]) === 'function') { |
||
| 6813 | _convertToBinary = false; |
||
| 6814 | _fr[op](blob.getSource()); |
||
| 6815 | } else if (op === 'readAsBinaryString') { // readAsBinaryString is depricated in general and never existed in IE10+ |
||
| 6816 | _convertToBinary = true; |
||
| 6817 | _fr.readAsDataURL(blob.getSource()); |
||
| 6818 | } |
||
| 6819 | }, |
||
| 6820 | |||
| 6821 | getResult: function() { |
||
| 6822 | return _fr && _fr.result ? (_convertToBinary ? _toBinary(_fr.result) : _fr.result) : null; |
||
| 6823 | }, |
||
| 6824 | |||
| 6825 | abort: function() { |
||
| 6826 | if (_fr) { |
||
| 6827 | _fr.abort(); |
||
| 6828 | } |
||
| 6829 | }, |
||
| 6830 | |||
| 6831 | destroy: function() { |
||
| 6832 | _fr = null; |
||
| 6833 | } |
||
| 6834 | }); |
||
| 6835 | |||
| 6836 | function _toBinary(str) { |
||
| 6837 | return Encode.atob(str.substring(str.indexOf('base64,') + 7)); |
||
| 6838 | } |
||
| 6839 | } |
||
| 6840 | |||
| 6841 | return (extensions.FileReader = FileReader); |
||
| 6842 | }); |
||
| 6843 | |||
| 6844 | // Included from: src/javascript/runtime/html5/xhr/XMLHttpRequest.js |
||
| 6845 | |||
| 6846 | /** |
||
| 6847 | * XMLHttpRequest.js |
||
| 6848 | * |
||
| 6849 | * Copyright 2013, Moxiecode Systems AB |
||
| 6850 | * Released under GPL License. |
||
| 6851 | * |
||
| 6852 | * License: http://www.plupload.com/license |
||
| 6853 | * Contributing: http://www.plupload.com/contributing |
||
| 6854 | */ |
||
| 6855 | |||
| 6856 | /*global ActiveXObject:true */ |
||
| 6857 | |||
| 6858 | /** |
||
| 6859 | @class moxie/runtime/html5/xhr/XMLHttpRequest |
||
| 6860 | @private |
||
| 6861 | */ |
||
| 6862 | define("moxie/runtime/html5/xhr/XMLHttpRequest", [ |
||
| 6863 | "moxie/runtime/html5/Runtime", |
||
| 6864 | "moxie/core/utils/Basic", |
||
| 6865 | "moxie/core/utils/Mime", |
||
| 6866 | "moxie/core/utils/Url", |
||
| 6867 | "moxie/file/File", |
||
| 6868 | "moxie/file/Blob", |
||
| 6869 | "moxie/xhr/FormData", |
||
| 6870 | "moxie/core/Exceptions", |
||
| 6871 | "moxie/core/utils/Env" |
||
| 6872 | ], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) { |
||
| 6873 | |||
| 6874 | function XMLHttpRequest() { |
||
| 6875 | var self = this |
||
| 6876 | , _xhr |
||
| 6877 | , _filename |
||
| 6878 | ; |
||
| 6879 | |||
| 6880 | Basic.extend(this, { |
||
| 6881 | send: function(meta, data) { |
||
| 6882 | var target = this |
||
| 6883 | , isGecko2_5_6 = (Env.browser === 'Mozilla' && Env.version >= 4 && Env.version < 7) |
||
| 6884 | , isAndroidBrowser = Env.browser === 'Android Browser' |
||
| 6885 | , mustSendAsBinary = false |
||
| 6886 | ; |
||
| 6887 | |||
| 6888 | // extract file name |
||
| 6889 | _filename = meta.url.replace(/^.+?\/([\w\-\.]+)$/, '$1').toLowerCase(); |
||
| 6890 | |||
| 6891 | _xhr = _getNativeXHR(); |
||
| 6892 | _xhr.open(meta.method, meta.url, meta.async, meta.user, meta.password); |
||
| 6893 | |||
| 6894 | |||
| 6895 | // prepare data to be sent |
||
| 6896 | if (data instanceof Blob) { |
||
| 6897 | if (data.isDetached()) { |
||
| 6898 | mustSendAsBinary = true; |
||
| 6899 | } |
||
| 6900 | data = data.getSource(); |
||
| 6901 | } else if (data instanceof FormData) { |
||
| 6902 | |||
| 6903 | if (data.hasBlob()) { |
||
| 6904 | if (data.getBlob().isDetached()) { |
||
| 6905 | data = _prepareMultipart.call(target, data); // _xhr must be instantiated and be in OPENED state |
||
| 6906 | mustSendAsBinary = true; |
||
| 6907 | } else if ((isGecko2_5_6 || isAndroidBrowser) && Basic.typeOf(data.getBlob().getSource()) === 'blob' && window.FileReader) { |
||
| 6908 | // Gecko 2/5/6 can't send blob in FormData: https://bugzilla.mozilla.org/show_bug.cgi?id=649150 |
||
| 6909 | // Android browsers (default one and Dolphin) seem to have the same issue, see: #613 |
||
| 6910 | _preloadAndSend.call(target, meta, data); |
||
| 6911 | return; // _preloadAndSend will reinvoke send() with transmutated FormData =%D |
||
| 6912 | } |
||
| 6913 | } |
||
| 6914 | |||
| 6915 | // transfer fields to real FormData |
||
| 6916 | if (data instanceof FormData) { // if still a FormData, e.g. not mangled by _prepareMultipart() |
||
| 6917 | var fd = new window.FormData(); |
||
| 6918 | data.each(function(value, name) { |
||
| 6919 | if (value instanceof Blob) { |
||
| 6920 | fd.append(name, value.getSource()); |
||
| 6921 | } else { |
||
| 6922 | fd.append(name, value); |
||
| 6923 | } |
||
| 6924 | }); |
||
| 6925 | data = fd; |
||
| 6926 | } |
||
| 6927 | } |
||
| 6928 | |||
| 6929 | |||
| 6930 | // if XHR L2 |
||
| 6931 | if (_xhr.upload) { |
||
| 6932 | if (meta.withCredentials) { |
||
| 6933 | _xhr.withCredentials = true; |
||
| 6934 | } |
||
| 6935 | |||
| 6936 | _xhr.addEventListener('load', function(e) { |
||
| 6937 | target.trigger(e); |
||
| 6938 | }); |
||
| 6939 | |||
| 6940 | _xhr.addEventListener('error', function(e) { |
||
| 6941 | target.trigger(e); |
||
| 6942 | }); |
||
| 6943 | |||
| 6944 | // additionally listen to progress events |
||
| 6945 | _xhr.addEventListener('progress', function(e) { |
||
| 6946 | target.trigger(e); |
||
| 6947 | }); |
||
| 6948 | |||
| 6949 | _xhr.upload.addEventListener('progress', function(e) { |
||
| 6950 | target.trigger({ |
||
| 6951 | type: 'UploadProgress', |
||
| 6952 | loaded: e.loaded, |
||
| 6953 | total: e.total |
||
| 6954 | }); |
||
| 6955 | }); |
||
| 6956 | // ... otherwise simulate XHR L2 |
||
| 6957 | } else { |
||
| 6958 | _xhr.onreadystatechange = function onReadyStateChange() { |
||
| 6959 | |||
| 6960 | // fake Level 2 events |
||
| 6961 | switch (_xhr.readyState) { |
||
| 6962 | |||
| 6963 | case 1: // XMLHttpRequest.OPENED |
||
| 6964 | // readystatechanged is fired twice for OPENED state (in IE and Mozilla) - neu |
||
| 6965 | break; |
||
| 6966 | |||
| 6967 | // looks like HEADERS_RECEIVED (state 2) is not reported in Opera (or it's old versions) - neu |
||
| 6968 | case 2: // XMLHttpRequest.HEADERS_RECEIVED |
||
| 6969 | break; |
||
| 6970 | |||
| 6971 | case 3: // XMLHttpRequest.LOADING |
||
| 6972 | // try to fire progress event for not XHR L2 |
||
| 6973 | var total, loaded; |
||
| 6974 | |||
| 6975 | try { |
||
| 6976 | if (Url.hasSameOrigin(meta.url)) { // Content-Length not accessible for cross-domain on some browsers |
||
| 6977 | total = _xhr.getResponseHeader('Content-Length') || 0; // old Safari throws an exception here |
||
| 6978 | } |
||
| 6979 | |||
| 6980 | if (_xhr.responseText) { // responseText was introduced in IE7 |
||
| 6981 | loaded = _xhr.responseText.length; |
||
| 6982 | } |
||
| 6983 | } catch(ex) { |
||
| 6984 | total = loaded = 0; |
||
| 6985 | } |
||
| 6986 | |||
| 6987 | target.trigger({ |
||
| 6988 | type: 'progress', |
||
| 6989 | lengthComputable: !!total, |
||
| 6990 | total: parseInt(total, 10), |
||
| 6991 | loaded: loaded |
||
| 6992 | }); |
||
| 6993 | break; |
||
| 6994 | |||
| 6995 | case 4: // XMLHttpRequest.DONE |
||
| 6996 | // release readystatechange handler (mostly for IE) |
||
| 6997 | _xhr.onreadystatechange = function() {}; |
||
| 6998 | |||
| 6999 | // usually status 0 is returned when server is unreachable, but FF also fails to status 0 for 408 timeout |
||
| 7000 | if (_xhr.status === 0) { |
||
| 7001 | target.trigger('error'); |
||
| 7002 | } else { |
||
| 7003 | target.trigger('load'); |
||
| 7004 | } |
||
| 7005 | break; |
||
| 7006 | } |
||
| 7007 | }; |
||
| 7008 | } |
||
| 7009 | |||
| 7010 | |||
| 7011 | // set request headers |
||
| 7012 | if (!Basic.isEmptyObj(meta.headers)) { |
||
| 7013 | Basic.each(meta.headers, function(value, header) { |
||
| 7014 | _xhr.setRequestHeader(header, value); |
||
| 7015 | }); |
||
| 7016 | } |
||
| 7017 | |||
| 7018 | // request response type |
||
| 7019 | if ("" !== meta.responseType && 'responseType' in _xhr) { |
||
| 7020 | if ('json' === meta.responseType && !Env.can('return_response_type', 'json')) { // we can fake this one |
||
| 7021 | _xhr.responseType = 'text'; |
||
| 7022 | } else { |
||
| 7023 | _xhr.responseType = meta.responseType; |
||
| 7024 | } |
||
| 7025 | } |
||
| 7026 | |||
| 7027 | // send ... |
||
| 7028 | if (!mustSendAsBinary) { |
||
| 7029 | _xhr.send(data); |
||
| 7030 | } else { |
||
| 7031 | if (_xhr.sendAsBinary) { // Gecko |
||
| 7032 | _xhr.sendAsBinary(data); |
||
| 7033 | } else { // other browsers having support for typed arrays |
||
| 7034 | (function() { |
||
| 7035 | // mimic Gecko's sendAsBinary |
||
| 7036 | var ui8a = new Uint8Array(data.length); |
||
| 7037 | for (var i = 0; i < data.length; i++) { |
||
| 7038 | ui8a[i] = (data.charCodeAt(i) & 0xff); |
||
| 7039 | } |
||
| 7040 | _xhr.send(ui8a.buffer); |
||
| 7041 | }()); |
||
| 7042 | } |
||
| 7043 | } |
||
| 7044 | |||
| 7045 | target.trigger('loadstart'); |
||
| 7046 | }, |
||
| 7047 | |||
| 7048 | getStatus: function() { |
||
| 7049 | // according to W3C spec it should return 0 for readyState < 3, but instead it throws an exception |
||
| 7050 | try { |
||
| 7051 | if (_xhr) { |
||
| 7052 | return _xhr.status; |
||
| 7053 | } |
||
| 7054 | } catch(ex) {} |
||
| 7055 | return 0; |
||
| 7056 | }, |
||
| 7057 | |||
| 7058 | getResponse: function(responseType) { |
||
| 7059 | var I = this.getRuntime(); |
||
| 7060 | |||
| 7061 | try { |
||
| 7062 | switch (responseType) { |
||
| 7063 | case 'blob': |
||
| 7064 | var file = new File(I.uid, _xhr.response); |
||
| 7065 | |||
| 7066 | // try to extract file name from content-disposition if possible (might be - not, if CORS for example) |
||
| 7067 | var disposition = _xhr.getResponseHeader('Content-Disposition'); |
||
| 7068 | if (disposition) { |
||
| 7069 | // extract filename from response header if available |
||
| 7070 | var match = disposition.match(/filename=([\'\"'])([^\1]+)\1/); |
||
| 7071 | if (match) { |
||
| 7072 | _filename = match[2]; |
||
| 7073 | } |
||
| 7074 | } |
||
| 7075 | file.name = _filename; |
||
| 7076 | |||
| 7077 | // pre-webkit Opera doesn't set type property on the blob response |
||
| 7078 | if (!file.type) { |
||
| 7079 | file.type = Mime.getFileMime(_filename); |
||
| 7080 | } |
||
| 7081 | return file; |
||
| 7082 | |||
| 7083 | case 'json': |
||
| 7084 | if (!Env.can('return_response_type', 'json')) { |
||
| 7085 | return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null; |
||
| 7086 | } |
||
| 7087 | return _xhr.response; |
||
| 7088 | |||
| 7089 | case 'document': |
||
| 7090 | return _getDocument(_xhr); |
||
| 7091 | |||
| 7092 | default: |
||
| 7093 | return _xhr.responseText !== '' ? _xhr.responseText : null; // against the specs, but for consistency across the runtimes |
||
| 7094 | } |
||
| 7095 | } catch(ex) { |
||
| 7096 | return null; |
||
| 7097 | } |
||
| 7098 | }, |
||
| 7099 | |||
| 7100 | getAllResponseHeaders: function() { |
||
| 7101 | try { |
||
| 7102 | return _xhr.getAllResponseHeaders(); |
||
| 7103 | } catch(ex) {} |
||
| 7104 | return ''; |
||
| 7105 | }, |
||
| 7106 | |||
| 7107 | abort: function() { |
||
| 7108 | if (_xhr) { |
||
| 7109 | _xhr.abort(); |
||
| 7110 | } |
||
| 7111 | }, |
||
| 7112 | |||
| 7113 | destroy: function() { |
||
| 7114 | self = _filename = null; |
||
| 7115 | } |
||
| 7116 | }); |
||
| 7117 | |||
| 7118 | |||
| 7119 | // here we go... ugly fix for ugly bug |
||
| 7120 | function _preloadAndSend(meta, data) { |
||
| 7121 | var target = this, blob, fr; |
||
| 7122 | |||
| 7123 | // get original blob |
||
| 7124 | blob = data.getBlob().getSource(); |
||
| 7125 | |||
| 7126 | // preload blob in memory to be sent as binary string |
||
| 7127 | fr = new window.FileReader(); |
||
| 7128 | fr.onload = function() { |
||
| 7129 | // overwrite original blob |
||
| 7130 | data.append(data.getBlobName(), new Blob(null, { |
||
| 7131 | type: blob.type, |
||
| 7132 | data: fr.result |
||
| 7133 | })); |
||
| 7134 | // invoke send operation again |
||
| 7135 | self.send.call(target, meta, data); |
||
| 7136 | }; |
||
| 7137 | fr.readAsBinaryString(blob); |
||
| 7138 | } |
||
| 7139 | |||
| 7140 | |||
| 7141 | function _getNativeXHR() { |
||
| 7142 | if (window.XMLHttpRequest && !(Env.browser === 'IE' && Env.version < 8)) { // IE7 has native XHR but it's buggy |
||
| 7143 | return new window.XMLHttpRequest(); |
||
| 7144 | } else { |
||
| 7145 | return (function() { |
||
| 7146 | var progIDs = ['Msxml2.XMLHTTP.6.0', 'Microsoft.XMLHTTP']; // if 6.0 available, use it, otherwise failback to default 3.0 |
||
| 7147 | for (var i = 0; i < progIDs.length; i++) { |
||
| 7148 | try { |
||
| 7149 | return new ActiveXObject(progIDs[i]); |
||
| 7150 | } catch (ex) {} |
||
| 7151 | } |
||
| 7152 | })(); |
||
| 7153 | } |
||
| 7154 | } |
||
| 7155 | |||
| 7156 | // @credits Sergey Ilinsky (http://www.ilinsky.com/) |
||
| 7157 | function _getDocument(xhr) { |
||
| 7158 | var rXML = xhr.responseXML; |
||
| 7159 | var rText = xhr.responseText; |
||
| 7160 | |||
| 7161 | // Try parsing responseText (@see: http://www.ilinsky.com/articles/XMLHttpRequest/#bugs-ie-responseXML-content-type) |
||
| 7162 | if (Env.browser === 'IE' && rText && rXML && !rXML.documentElement && /[^\/]+\/[^\+]+\+xml/.test(xhr.getResponseHeader("Content-Type"))) { |
||
| 7163 | rXML = new window.ActiveXObject("Microsoft.XMLDOM"); |
||
| 7164 | rXML.async = false; |
||
| 7165 | rXML.validateOnParse = false; |
||
| 7166 | rXML.loadXML(rText); |
||
| 7167 | } |
||
| 7168 | |||
| 7169 | // Check if there is no error in document |
||
| 7170 | if (rXML) { |
||
| 7171 | if ((Env.browser === 'IE' && rXML.parseError !== 0) || !rXML.documentElement || rXML.documentElement.tagName === "parsererror") { |
||
| 7172 | return null; |
||
| 7173 | } |
||
| 7174 | } |
||
| 7175 | return rXML; |
||
| 7176 | } |
||
| 7177 | |||
| 7178 | |||
| 7179 | function _prepareMultipart(fd) { |
||
| 7180 | var boundary = '----moxieboundary' + new Date().getTime() |
||
| 7181 | , dashdash = '--' |
||
| 7182 | , crlf = '\r\n' |
||
| 7183 | , multipart = '' |
||
| 7184 | , I = this.getRuntime() |
||
| 7185 | ; |
||
| 7186 | |||
| 7187 | if (!I.can('send_binary_string')) { |
||
| 7188 | throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); |
||
| 7189 | } |
||
| 7190 | |||
| 7191 | _xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary); |
||
| 7192 | |||
| 7193 | // append multipart parameters |
||
| 7194 | fd.each(function(value, name) { |
||
| 7195 | // Firefox 3.6 failed to convert multibyte characters to UTF-8 in sendAsBinary(), |
||
| 7196 | // so we try it here ourselves with: unescape(encodeURIComponent(value)) |
||
| 7197 | if (value instanceof Blob) { |
||
| 7198 | // Build RFC2388 blob |
||
| 7199 | multipart += dashdash + boundary + crlf + |
||
| 7200 | 'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf + |
||
| 7201 | 'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf + |
||
| 7202 | value.getSource() + crlf; |
||
| 7203 | } else { |
||
| 7204 | multipart += dashdash + boundary + crlf + |
||
| 7205 | 'Content-Disposition: form-data; name="' + name + '"' + crlf + crlf + |
||
| 7206 | unescape(encodeURIComponent(value)) + crlf; |
||
| 7207 | } |
||
| 7208 | }); |
||
| 7209 | |||
| 7210 | multipart += dashdash + boundary + dashdash + crlf; |
||
| 7211 | |||
| 7212 | return multipart; |
||
| 7213 | } |
||
| 7214 | } |
||
| 7215 | |||
| 7216 | return (extensions.XMLHttpRequest = XMLHttpRequest); |
||
| 7217 | }); |
||
| 7218 | |||
| 7219 | // Included from: src/javascript/runtime/html5/utils/BinaryReader.js |
||
| 7220 | |||
| 7221 | /** |
||
| 7222 | * BinaryReader.js |
||
| 7223 | * |
||
| 7224 | * Copyright 2013, Moxiecode Systems AB |
||
| 7225 | * Released under GPL License. |
||
| 7226 | * |
||
| 7227 | * License: http://www.plupload.com/license |
||
| 7228 | * Contributing: http://www.plupload.com/contributing |
||
| 7229 | */ |
||
| 7230 | |||
| 7231 | /** |
||
| 7232 | @class moxie/runtime/html5/utils/BinaryReader |
||
| 7233 | @private |
||
| 7234 | */ |
||
| 7235 | define("moxie/runtime/html5/utils/BinaryReader", [], function() { |
||
| 7236 | return function() { |
||
| 7237 | var II = false, bin; |
||
| 7238 | |||
| 7239 | // Private functions |
||
| 7240 | function read(idx, size) { |
||
| 7241 | var mv = II ? 0 : -8 * (size - 1), sum = 0, i; |
||
| 7242 | |||
| 7243 | for (i = 0; i < size; i++) { |
||
| 7244 | sum |= (bin.charCodeAt(idx + i) << Math.abs(mv + i*8)); |
||
| 7245 | } |
||
| 7246 | |||
| 7247 | return sum; |
||
| 7248 | } |
||
| 7249 | |||
| 7250 | function putstr(segment, idx, length) { |
||
| 7251 | length = arguments.length === 3 ? length : bin.length - idx - 1; |
||
| 7252 | bin = bin.substr(0, idx) + segment + bin.substr(length + idx); |
||
| 7253 | } |
||
| 7254 | |||
| 7255 | function write(idx, num, size) { |
||
| 7256 | var str = '', mv = II ? 0 : -8 * (size - 1), i; |
||
| 7257 | |||
| 7258 | for (i = 0; i < size; i++) { |
||
| 7259 | str += String.fromCharCode((num >> Math.abs(mv + i*8)) & 255); |
||
| 7260 | } |
||
| 7261 | |||
| 7262 | putstr(str, idx, size); |
||
| 7263 | } |
||
| 7264 | |||
| 7265 | // Public functions |
||
| 7266 | return { |
||
| 7267 | II: function(order) { |
||
| 7268 | if (order === undefined) { |
||
| 7269 | return II; |
||
| 7270 | } else { |
||
| 7271 | II = order; |
||
| 7272 | } |
||
| 7273 | }, |
||
| 7274 | |||
| 7275 | init: function(binData) { |
||
| 7276 | II = false; |
||
| 7277 | bin = binData; |
||
| 7278 | }, |
||
| 7279 | |||
| 7280 | SEGMENT: function(idx, length, segment) { |
||
| 7281 | switch (arguments.length) { |
||
| 7282 | case 1: |
||
| 7283 | return bin.substr(idx, bin.length - idx - 1); |
||
| 7284 | case 2: |
||
| 7285 | return bin.substr(idx, length); |
||
| 7286 | case 3: |
||
| 7287 | putstr(segment, idx, length); |
||
| 7288 | break; |
||
| 7289 | default: return bin; |
||
| 7290 | } |
||
| 7291 | }, |
||
| 7292 | |||
| 7293 | BYTE: function(idx) { |
||
| 7294 | return read(idx, 1); |
||
| 7295 | }, |
||
| 7296 | |||
| 7297 | SHORT: function(idx) { |
||
| 7298 | return read(idx, 2); |
||
| 7299 | }, |
||
| 7300 | |||
| 7301 | LONG: function(idx, num) { |
||
| 7302 | if (num === undefined) { |
||
| 7303 | return read(idx, 4); |
||
| 7304 | } else { |
||
| 7305 | write(idx, num, 4); |
||
| 7306 | } |
||
| 7307 | }, |
||
| 7308 | |||
| 7309 | SLONG: function(idx) { // 2's complement notation |
||
| 7310 | var num = read(idx, 4); |
||
| 7311 | |||
| 7312 | return (num > 2147483647 ? num - 4294967296 : num); |
||
| 7313 | }, |
||
| 7314 | |||
| 7315 | STRING: function(idx, size) { |
||
| 7316 | var str = ''; |
||
| 7317 | |||
| 7318 | for (size += idx; idx < size; idx++) { |
||
| 7319 | str += String.fromCharCode(read(idx, 1)); |
||
| 7320 | } |
||
| 7321 | |||
| 7322 | return str; |
||
| 7323 | } |
||
| 7324 | }; |
||
| 7325 | }; |
||
| 7326 | }); |
||
| 7327 | |||
| 7328 | // Included from: src/javascript/runtime/html5/image/JPEGHeaders.js |
||
| 7329 | |||
| 7330 | /** |
||
| 7331 | * JPEGHeaders.js |
||
| 7332 | * |
||
| 7333 | * Copyright 2013, Moxiecode Systems AB |
||
| 7334 | * Released under GPL License. |
||
| 7335 | * |
||
| 7336 | * License: http://www.plupload.com/license |
||
| 7337 | * Contributing: http://www.plupload.com/contributing |
||
| 7338 | */ |
||
| 7339 | |||
| 7340 | /** |
||
| 7341 | @class moxie/runtime/html5/image/JPEGHeaders |
||
| 7342 | @private |
||
| 7343 | */ |
||
| 7344 | define("moxie/runtime/html5/image/JPEGHeaders", [ |
||
| 7345 | "moxie/runtime/html5/utils/BinaryReader" |
||
| 7346 | ], function(BinaryReader) { |
||
| 7347 | |||
| 7348 | return function JPEGHeaders(data) { |
||
| 7349 | var headers = [], read, idx, marker, length = 0; |
||
| 7350 | |||
| 7351 | read = new BinaryReader(); |
||
| 7352 | read.init(data); |
||
| 7353 | |||
| 7354 | // Check if data is jpeg |
||
| 7355 | if (read.SHORT(0) !== 0xFFD8) { |
||
| 7356 | return; |
||
| 7357 | } |
||
| 7358 | |||
| 7359 | idx = 2; |
||
| 7360 | |||
| 7361 | while (idx <= data.length) { |
||
| 7362 | marker = read.SHORT(idx); |
||
| 7363 | |||
| 7364 | // omit RST (restart) markers |
||
| 7365 | if (marker >= 0xFFD0 && marker <= 0xFFD7) { |
||
| 7366 | idx += 2; |
||
| 7367 | continue; |
||
| 7368 | } |
||
| 7369 | |||
| 7370 | // no headers allowed after SOS marker |
||
| 7371 | if (marker === 0xFFDA || marker === 0xFFD9) { |
||
| 7372 | break; |
||
| 7373 | } |
||
| 7374 | |||
| 7375 | length = read.SHORT(idx + 2) + 2; |
||
| 7376 | |||
| 7377 | // APPn marker detected |
||
| 7378 | if (marker >= 0xFFE1 && marker <= 0xFFEF) { |
||
| 7379 | headers.push({ |
||
| 7380 | hex: marker, |
||
| 7381 | name: 'APP' + (marker & 0x000F), |
||
| 7382 | start: idx, |
||
| 7383 | length: length, |
||
| 7384 | segment: read.SEGMENT(idx, length) |
||
| 7385 | }); |
||
| 7386 | } |
||
| 7387 | |||
| 7388 | idx += length; |
||
| 7389 | } |
||
| 7390 | |||
| 7391 | read.init(null); // free memory |
||
| 7392 | |||
| 7393 | return { |
||
| 7394 | headers: headers, |
||
| 7395 | |||
| 7396 | restore: function(data) { |
||
| 7397 | var max, i; |
||
| 7398 | |||
| 7399 | read.init(data); |
||
| 7400 | |||
| 7401 | idx = read.SHORT(2) == 0xFFE0 ? 4 + read.SHORT(4) : 2; |
||
| 7402 | |||
| 7403 | for (i = 0, max = headers.length; i < max; i++) { |
||
| 7404 | read.SEGMENT(idx, 0, headers[i].segment); |
||
| 7405 | idx += headers[i].length; |
||
| 7406 | } |
||
| 7407 | |||
| 7408 | data = read.SEGMENT(); |
||
| 7409 | read.init(null); |
||
| 7410 | return data; |
||
| 7411 | }, |
||
| 7412 | |||
| 7413 | strip: function(data) { |
||
| 7414 | var headers, jpegHeaders, i; |
||
| 7415 | |||
| 7416 | jpegHeaders = new JPEGHeaders(data); |
||
| 7417 | headers = jpegHeaders.headers; |
||
| 7418 | jpegHeaders.purge(); |
||
| 7419 | |||
| 7420 | read.init(data); |
||
| 7421 | |||
| 7422 | i = headers.length; |
||
| 7423 | while (i--) { |
||
| 7424 | read.SEGMENT(headers[i].start, headers[i].length, ''); |
||
| 7425 | } |
||
| 7426 | |||
| 7427 | data = read.SEGMENT(); |
||
| 7428 | read.init(null); |
||
| 7429 | return data; |
||
| 7430 | }, |
||
| 7431 | |||
| 7432 | get: function(name) { |
||
| 7433 | var array = []; |
||
| 7434 | |||
| 7435 | for (var i = 0, max = headers.length; i < max; i++) { |
||
| 7436 | if (headers[i].name === name.toUpperCase()) { |
||
| 7437 | array.push(headers[i].segment); |
||
| 7438 | } |
||
| 7439 | } |
||
| 7440 | return array; |
||
| 7441 | }, |
||
| 7442 | |||
| 7443 | set: function(name, segment) { |
||
| 7444 | var array = [], i, ii, max; |
||
| 7445 | |||
| 7446 | if (typeof(segment) === 'string') { |
||
| 7447 | array.push(segment); |
||
| 7448 | } else { |
||
| 7449 | array = segment; |
||
| 7450 | } |
||
| 7451 | |||
| 7452 | for (i = ii = 0, max = headers.length; i < max; i++) { |
||
| 7453 | if (headers[i].name === name.toUpperCase()) { |
||
| 7454 | headers[i].segment = array[ii]; |
||
| 7455 | headers[i].length = array[ii].length; |
||
| 7456 | ii++; |
||
| 7457 | } |
||
| 7458 | if (ii >= array.length) { |
||
| 7459 | break; |
||
| 7460 | } |
||
| 7461 | } |
||
| 7462 | }, |
||
| 7463 | |||
| 7464 | purge: function() { |
||
| 7465 | headers = []; |
||
| 7466 | read.init(null); |
||
| 7467 | read = null; |
||
| 7468 | } |
||
| 7469 | }; |
||
| 7470 | }; |
||
| 7471 | }); |
||
| 7472 | |||
| 7473 | // Included from: src/javascript/runtime/html5/image/ExifParser.js |
||
| 7474 | |||
| 7475 | /** |
||
| 7476 | * ExifParser.js |
||
| 7477 | * |
||
| 7478 | * Copyright 2013, Moxiecode Systems AB |
||
| 7479 | * Released under GPL License. |
||
| 7480 | * |
||
| 7481 | * License: http://www.plupload.com/license |
||
| 7482 | * Contributing: http://www.plupload.com/contributing |
||
| 7483 | */ |
||
| 7484 | |||
| 7485 | /** |
||
| 7486 | @class moxie/runtime/html5/image/ExifParser |
||
| 7487 | @private |
||
| 7488 | */ |
||
| 7489 | define("moxie/runtime/html5/image/ExifParser", [ |
||
| 7490 | "moxie/core/utils/Basic", |
||
| 7491 | "moxie/runtime/html5/utils/BinaryReader" |
||
| 7492 | ], function(Basic, BinaryReader) { |
||
| 7493 | |||
| 7494 | return function ExifParser() { |
||
| 7495 | // Private ExifParser fields |
||
| 7496 | var data, tags, Tiff, offsets = {}, tagDescs; |
||
| 7497 | |||
| 7498 | data = new BinaryReader(); |
||
| 7499 | |||
| 7500 | tags = { |
||
| 7501 | tiff : { |
||
| 7502 | /* |
||
| 7503 | The image orientation viewed in terms of rows and columns. |
||
| 7504 | |||
| 7505 | 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. |
||
| 7506 | 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. |
||
| 7507 | 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. |
||
| 7508 | 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. |
||
| 7509 | 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. |
||
| 7510 | 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. |
||
| 7511 | 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. |
||
| 7512 | 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. |
||
| 7513 | */ |
||
| 7514 | 0x0112: 'Orientation', |
||
| 7515 | 0x010E: 'ImageDescription', |
||
| 7516 | 0x010F: 'Make', |
||
| 7517 | 0x0110: 'Model', |
||
| 7518 | 0x0131: 'Software', |
||
| 7519 | 0x8769: 'ExifIFDPointer', |
||
| 7520 | 0x8825: 'GPSInfoIFDPointer' |
||
| 7521 | }, |
||
| 7522 | exif : { |
||
| 7523 | 0x9000: 'ExifVersion', |
||
| 7524 | 0xA001: 'ColorSpace', |
||
| 7525 | 0xA002: 'PixelXDimension', |
||
| 7526 | 0xA003: 'PixelYDimension', |
||
| 7527 | 0x9003: 'DateTimeOriginal', |
||
| 7528 | 0x829A: 'ExposureTime', |
||
| 7529 | 0x829D: 'FNumber', |
||
| 7530 | 0x8827: 'ISOSpeedRatings', |
||
| 7531 | 0x9201: 'ShutterSpeedValue', |
||
| 7532 | 0x9202: 'ApertureValue' , |
||
| 7533 | 0x9207: 'MeteringMode', |
||
| 7534 | 0x9208: 'LightSource', |
||
| 7535 | 0x9209: 'Flash', |
||
| 7536 | 0x920A: 'FocalLength', |
||
| 7537 | 0xA402: 'ExposureMode', |
||
| 7538 | 0xA403: 'WhiteBalance', |
||
| 7539 | 0xA406: 'SceneCaptureType', |
||
| 7540 | 0xA404: 'DigitalZoomRatio', |
||
| 7541 | 0xA408: 'Contrast', |
||
| 7542 | 0xA409: 'Saturation', |
||
| 7543 | 0xA40A: 'Sharpness' |
||
| 7544 | }, |
||
| 7545 | gps : { |
||
| 7546 | 0x0000: 'GPSVersionID', |
||
| 7547 | 0x0001: 'GPSLatitudeRef', |
||
| 7548 | 0x0002: 'GPSLatitude', |
||
| 7549 | 0x0003: 'GPSLongitudeRef', |
||
| 7550 | 0x0004: 'GPSLongitude' |
||
| 7551 | } |
||
| 7552 | }; |
||
| 7553 | |||
| 7554 | tagDescs = { |
||
| 7555 | 'ColorSpace': { |
||
| 7556 | 1: 'sRGB', |
||
| 7557 | 0: 'Uncalibrated' |
||
| 7558 | }, |
||
| 7559 | |||
| 7560 | 'MeteringMode': { |
||
| 7561 | 0: 'Unknown', |
||
| 7562 | 1: 'Average', |
||
| 7563 | 2: 'CenterWeightedAverage', |
||
| 7564 | 3: 'Spot', |
||
| 7565 | 4: 'MultiSpot', |
||
| 7566 | 5: 'Pattern', |
||
| 7567 | 6: 'Partial', |
||
| 7568 | 255: 'Other' |
||
| 7569 | }, |
||
| 7570 | |||
| 7571 | 'LightSource': { |
||
| 7572 | 1: 'Daylight', |
||
| 7573 | 2: 'Fliorescent', |
||
| 7574 | 3: 'Tungsten', |
||
| 7575 | 4: 'Flash', |
||
| 7576 | 9: 'Fine weather', |
||
| 7577 | 10: 'Cloudy weather', |
||
| 7578 | 11: 'Shade', |
||
| 7579 | 12: 'Daylight fluorescent (D 5700 - 7100K)', |
||
| 7580 | 13: 'Day white fluorescent (N 4600 -5400K)', |
||
| 7581 | 14: 'Cool white fluorescent (W 3900 - 4500K)', |
||
| 7582 | 15: 'White fluorescent (WW 3200 - 3700K)', |
||
| 7583 | 17: 'Standard light A', |
||
| 7584 | 18: 'Standard light B', |
||
| 7585 | 19: 'Standard light C', |
||
| 7586 | 20: 'D55', |
||
| 7587 | 21: 'D65', |
||
| 7588 | 22: 'D75', |
||
| 7589 | 23: 'D50', |
||
| 7590 | 24: 'ISO studio tungsten', |
||
| 7591 | 255: 'Other' |
||
| 7592 | }, |
||
| 7593 | |||
| 7594 | 'Flash': { |
||
| 7595 | 0x0000: 'Flash did not fire.', |
||
| 7596 | 0x0001: 'Flash fired.', |
||
| 7597 | 0x0005: 'Strobe return light not detected.', |
||
| 7598 | 0x0007: 'Strobe return light detected.', |
||
| 7599 | 0x0009: 'Flash fired, compulsory flash mode', |
||
| 7600 | 0x000D: 'Flash fired, compulsory flash mode, return light not detected', |
||
| 7601 | 0x000F: 'Flash fired, compulsory flash mode, return light detected', |
||
| 7602 | 0x0010: 'Flash did not fire, compulsory flash mode', |
||
| 7603 | 0x0018: 'Flash did not fire, auto mode', |
||
| 7604 | 0x0019: 'Flash fired, auto mode', |
||
| 7605 | 0x001D: 'Flash fired, auto mode, return light not detected', |
||
| 7606 | 0x001F: 'Flash fired, auto mode, return light detected', |
||
| 7607 | 0x0020: 'No flash function', |
||
| 7608 | 0x0041: 'Flash fired, red-eye reduction mode', |
||
| 7609 | 0x0045: 'Flash fired, red-eye reduction mode, return light not detected', |
||
| 7610 | 0x0047: 'Flash fired, red-eye reduction mode, return light detected', |
||
| 7611 | 0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode', |
||
| 7612 | 0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected', |
||
| 7613 | 0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected', |
||
| 7614 | 0x0059: 'Flash fired, auto mode, red-eye reduction mode', |
||
| 7615 | 0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode', |
||
| 7616 | 0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode' |
||
| 7617 | }, |
||
| 7618 | |||
| 7619 | 'ExposureMode': { |
||
| 7620 | 0: 'Auto exposure', |
||
| 7621 | 1: 'Manual exposure', |
||
| 7622 | 2: 'Auto bracket' |
||
| 7623 | }, |
||
| 7624 | |||
| 7625 | 'WhiteBalance': { |
||
| 7626 | 0: 'Auto white balance', |
||
| 7627 | 1: 'Manual white balance' |
||
| 7628 | }, |
||
| 7629 | |||
| 7630 | 'SceneCaptureType': { |
||
| 7631 | 0: 'Standard', |
||
| 7632 | 1: 'Landscape', |
||
| 7633 | 2: 'Portrait', |
||
| 7634 | 3: 'Night scene' |
||
| 7635 | }, |
||
| 7636 | |||
| 7637 | 'Contrast': { |
||
| 7638 | 0: 'Normal', |
||
| 7639 | 1: 'Soft', |
||
| 7640 | 2: 'Hard' |
||
| 7641 | }, |
||
| 7642 | |||
| 7643 | 'Saturation': { |
||
| 7644 | 0: 'Normal', |
||
| 7645 | 1: 'Low saturation', |
||
| 7646 | 2: 'High saturation' |
||
| 7647 | }, |
||
| 7648 | |||
| 7649 | 'Sharpness': { |
||
| 7650 | 0: 'Normal', |
||
| 7651 | 1: 'Soft', |
||
| 7652 | 2: 'Hard' |
||
| 7653 | }, |
||
| 7654 | |||
| 7655 | // GPS related |
||
| 7656 | 'GPSLatitudeRef': { |
||
| 7657 | N: 'North latitude', |
||
| 7658 | S: 'South latitude' |
||
| 7659 | }, |
||
| 7660 | |||
| 7661 | 'GPSLongitudeRef': { |
||
| 7662 | E: 'East longitude', |
||
| 7663 | W: 'West longitude' |
||
| 7664 | } |
||
| 7665 | }; |
||
| 7666 | |||
| 7667 | function extractTags(IFD_offset, tags2extract) { |
||
| 7668 | var length = data.SHORT(IFD_offset), i, ii, |
||
| 7669 | tag, type, count, tagOffset, offset, value, values = [], hash = {}; |
||
| 7670 | |||
| 7671 | for (i = 0; i < length; i++) { |
||
| 7672 | // Set binary reader pointer to beginning of the next tag |
||
| 7673 | offset = tagOffset = IFD_offset + 12 * i + 2; |
||
| 7674 | |||
| 7675 | tag = tags2extract[data.SHORT(offset)]; |
||
| 7676 | |||
| 7677 | if (tag === undefined) { |
||
| 7678 | continue; // Not the tag we requested |
||
| 7679 | } |
||
| 7680 | |||
| 7681 | type = data.SHORT(offset+=2); |
||
| 7682 | count = data.LONG(offset+=2); |
||
| 7683 | |||
| 7684 | offset += 4; |
||
| 7685 | values = []; |
||
| 7686 | |||
| 7687 | switch (type) { |
||
| 7688 | case 1: // BYTE |
||
| 7689 | case 7: // UNDEFINED |
||
| 7690 | if (count > 4) { |
||
| 7691 | offset = data.LONG(offset) + offsets.tiffHeader; |
||
| 7692 | } |
||
| 7693 | |||
| 7694 | for (ii = 0; ii < count; ii++) { |
||
| 7695 | values[ii] = data.BYTE(offset + ii); |
||
| 7696 | } |
||
| 7697 | |||
| 7698 | break; |
||
| 7699 | |||
| 7700 | case 2: // STRING |
||
| 7701 | if (count > 4) { |
||
| 7702 | offset = data.LONG(offset) + offsets.tiffHeader; |
||
| 7703 | } |
||
| 7704 | |||
| 7705 | hash[tag] = data.STRING(offset, count - 1); |
||
| 7706 | |||
| 7707 | continue; |
||
| 7708 | |||
| 7709 | case 3: // SHORT |
||
| 7710 | if (count > 2) { |
||
| 7711 | offset = data.LONG(offset) + offsets.tiffHeader; |
||
| 7712 | } |
||
| 7713 | |||
| 7714 | for (ii = 0; ii < count; ii++) { |
||
| 7715 | values[ii] = data.SHORT(offset + ii*2); |
||
| 7716 | } |
||
| 7717 | |||
| 7718 | break; |
||
| 7719 | |||
| 7720 | case 4: // LONG |
||
| 7721 | if (count > 1) { |
||
| 7722 | offset = data.LONG(offset) + offsets.tiffHeader; |
||
| 7723 | } |
||
| 7724 | |||
| 7725 | for (ii = 0; ii < count; ii++) { |
||
| 7726 | values[ii] = data.LONG(offset + ii*4); |
||
| 7727 | } |
||
| 7728 | |||
| 7729 | break; |
||
| 7730 | |||
| 7731 | case 5: // RATIONAL |
||
| 7732 | offset = data.LONG(offset) + offsets.tiffHeader; |
||
| 7733 | |||
| 7734 | for (ii = 0; ii < count; ii++) { |
||
| 7735 | values[ii] = data.LONG(offset + ii*4) / data.LONG(offset + ii*4 + 4); |
||
| 7736 | } |
||
| 7737 | |||
| 7738 | break; |
||
| 7739 | |||
| 7740 | case 9: // SLONG |
||
| 7741 | offset = data.LONG(offset) + offsets.tiffHeader; |
||
| 7742 | |||
| 7743 | for (ii = 0; ii < count; ii++) { |
||
| 7744 | values[ii] = data.SLONG(offset + ii*4); |
||
| 7745 | } |
||
| 7746 | |||
| 7747 | break; |
||
| 7748 | |||
| 7749 | case 10: // SRATIONAL |
||
| 7750 | offset = data.LONG(offset) + offsets.tiffHeader; |
||
| 7751 | |||
| 7752 | for (ii = 0; ii < count; ii++) { |
||
| 7753 | values[ii] = data.SLONG(offset + ii*4) / data.SLONG(offset + ii*4 + 4); |
||
| 7754 | } |
||
| 7755 | |||
| 7756 | break; |
||
| 7757 | |||
| 7758 | default: |
||
| 7759 | continue; |
||
| 7760 | } |
||
| 7761 | |||
| 7762 | value = (count == 1 ? values[0] : values); |
||
| 7763 | |||
| 7764 | if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') { |
||
| 7765 | hash[tag] = tagDescs[tag][value]; |
||
| 7766 | } else { |
||
| 7767 | hash[tag] = value; |
||
| 7768 | } |
||
| 7769 | } |
||
| 7770 | |||
| 7771 | return hash; |
||
| 7772 | } |
||
| 7773 | |||
| 7774 | function getIFDOffsets() { |
||
| 7775 | var idx = offsets.tiffHeader; |
||
| 7776 | |||
| 7777 | // Set read order of multi-byte data |
||
| 7778 | data.II(data.SHORT(idx) == 0x4949); |
||
| 7779 | |||
| 7780 | // Check if always present bytes are indeed present |
||
| 7781 | if (data.SHORT(idx+=2) !== 0x002A) { |
||
| 7782 | return false; |
||
| 7783 | } |
||
| 7784 | |||
| 7785 | offsets.IFD0 = offsets.tiffHeader + data.LONG(idx += 2); |
||
| 7786 | Tiff = extractTags(offsets.IFD0, tags.tiff); |
||
| 7787 | |||
| 7788 | if ('ExifIFDPointer' in Tiff) { |
||
| 7789 | offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer; |
||
| 7790 | delete Tiff.ExifIFDPointer; |
||
| 7791 | } |
||
| 7792 | |||
| 7793 | if ('GPSInfoIFDPointer' in Tiff) { |
||
| 7794 | offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer; |
||
| 7795 | delete Tiff.GPSInfoIFDPointer; |
||
| 7796 | } |
||
| 7797 | return true; |
||
| 7798 | } |
||
| 7799 | |||
| 7800 | // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported |
||
| 7801 | function setTag(ifd, tag, value) { |
||
| 7802 | var offset, length, tagOffset, valueOffset = 0; |
||
| 7803 | |||
| 7804 | // If tag name passed translate into hex key |
||
| 7805 | if (typeof(tag) === 'string') { |
||
| 7806 | var tmpTags = tags[ifd.toLowerCase()]; |
||
| 7807 | for (var hex in tmpTags) { |
||
| 7808 | if (tmpTags[hex] === tag) { |
||
| 7809 | tag = hex; |
||
| 7810 | break; |
||
| 7811 | } |
||
| 7812 | } |
||
| 7813 | } |
||
| 7814 | offset = offsets[ifd.toLowerCase() + 'IFD']; |
||
| 7815 | length = data.SHORT(offset); |
||
| 7816 | |||
| 7817 | for (var i = 0; i < length; i++) { |
||
| 7818 | tagOffset = offset + 12 * i + 2; |
||
| 7819 | |||
| 7820 | if (data.SHORT(tagOffset) == tag) { |
||
| 7821 | valueOffset = tagOffset + 8; |
||
| 7822 | break; |
||
| 7823 | } |
||
| 7824 | } |
||
| 7825 | |||
| 7826 | if (!valueOffset) { |
||
| 7827 | return false; |
||
| 7828 | } |
||
| 7829 | |||
| 7830 | data.LONG(valueOffset, value); |
||
| 7831 | return true; |
||
| 7832 | } |
||
| 7833 | |||
| 7834 | |||
| 7835 | // Public functions |
||
| 7836 | return { |
||
| 7837 | init: function(segment) { |
||
| 7838 | // Reset internal data |
||
| 7839 | offsets = { |
||
| 7840 | tiffHeader: 10 |
||
| 7841 | }; |
||
| 7842 | |||
| 7843 | if (segment === undefined || !segment.length) { |
||
| 7844 | return false; |
||
| 7845 | } |
||
| 7846 | |||
| 7847 | data.init(segment); |
||
| 7848 | |||
| 7849 | // Check if that's APP1 and that it has EXIF |
||
| 7850 | if (data.SHORT(0) === 0xFFE1 && data.STRING(4, 5).toUpperCase() === "EXIF\0") { |
||
| 7851 | return getIFDOffsets(); |
||
| 7852 | } |
||
| 7853 | return false; |
||
| 7854 | }, |
||
| 7855 | |||
| 7856 | TIFF: function() { |
||
| 7857 | return Tiff; |
||
| 7858 | }, |
||
| 7859 | |||
| 7860 | EXIF: function() { |
||
| 7861 | var Exif; |
||
| 7862 | |||
| 7863 | // Populate EXIF hash |
||
| 7864 | Exif = extractTags(offsets.exifIFD, tags.exif); |
||
| 7865 | |||
| 7866 | // Fix formatting of some tags |
||
| 7867 | if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') { |
||
| 7868 | for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) { |
||
| 7869 | exifVersion += String.fromCharCode(Exif.ExifVersion[i]); |
||
| 7870 | } |
||
| 7871 | Exif.ExifVersion = exifVersion; |
||
| 7872 | } |
||
| 7873 | |||
| 7874 | return Exif; |
||
| 7875 | }, |
||
| 7876 | |||
| 7877 | GPS: function() { |
||
| 7878 | var GPS; |
||
| 7879 | |||
| 7880 | GPS = extractTags(offsets.gpsIFD, tags.gps); |
||
| 7881 | |||
| 7882 | // iOS devices (and probably some others) do not put in GPSVersionID tag (why?..) |
||
| 7883 | if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') { |
||
| 7884 | GPS.GPSVersionID = GPS.GPSVersionID.join('.'); |
||
| 7885 | } |
||
| 7886 | |||
| 7887 | return GPS; |
||
| 7888 | }, |
||
| 7889 | |||
| 7890 | setExif: function(tag, value) { |
||
| 7891 | // Right now only setting of width/height is possible |
||
| 7892 | if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') {return false;} |
||
| 7893 | |||
| 7894 | return setTag('exif', tag, value); |
||
| 7895 | }, |
||
| 7896 | |||
| 7897 | |||
| 7898 | getBinary: function() { |
||
| 7899 | return data.SEGMENT(); |
||
| 7900 | }, |
||
| 7901 | |||
| 7902 | purge: function() { |
||
| 7903 | data.init(null); |
||
| 7904 | data = Tiff = null; |
||
| 7905 | offsets = {}; |
||
| 7906 | } |
||
| 7907 | }; |
||
| 7908 | }; |
||
| 7909 | }); |
||
| 7910 | |||
| 7911 | // Included from: src/javascript/runtime/html5/image/JPEG.js |
||
| 7912 | |||
| 7913 | /** |
||
| 7914 | * JPEG.js |
||
| 7915 | * |
||
| 7916 | * Copyright 2013, Moxiecode Systems AB |
||
| 7917 | * Released under GPL License. |
||
| 7918 | * |
||
| 7919 | * License: http://www.plupload.com/license |
||
| 7920 | * Contributing: http://www.plupload.com/contributing |
||
| 7921 | */ |
||
| 7922 | |||
| 7923 | /** |
||
| 7924 | @class moxie/runtime/html5/image/JPEG |
||
| 7925 | @private |
||
| 7926 | */ |
||
| 7927 | define("moxie/runtime/html5/image/JPEG", [ |
||
| 7928 | "moxie/core/utils/Basic", |
||
| 7929 | "moxie/core/Exceptions", |
||
| 7930 | "moxie/runtime/html5/image/JPEGHeaders", |
||
| 7931 | "moxie/runtime/html5/utils/BinaryReader", |
||
| 7932 | "moxie/runtime/html5/image/ExifParser" |
||
| 7933 | ], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) { |
||
| 7934 | |||
| 7935 | function JPEG(binstr) { |
||
| 7936 | var _binstr, _br, _hm, _ep, _info, hasExif; |
||
| 7937 | |||
| 7938 | function _getDimensions() { |
||
| 7939 | var idx = 0, marker, length; |
||
| 7940 | |||
| 7941 | // examine all through the end, since some images might have very large APP segments |
||
| 7942 | while (idx <= _binstr.length) { |
||
| 7943 | marker = _br.SHORT(idx += 2); |
||
| 7944 | |||
| 7945 | if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn |
||
| 7946 | idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte) |
||
| 7947 | return { |
||
| 7948 | height: _br.SHORT(idx), |
||
| 7949 | width: _br.SHORT(idx += 2) |
||
| 7950 | }; |
||
| 7951 | } |
||
| 7952 | length = _br.SHORT(idx += 2); |
||
| 7953 | idx += length - 2; |
||
| 7954 | } |
||
| 7955 | return null; |
||
| 7956 | } |
||
| 7957 | |||
| 7958 | _binstr = binstr; |
||
| 7959 | |||
| 7960 | _br = new BinaryReader(); |
||
| 7961 | _br.init(_binstr); |
||
| 7962 | |||
| 7963 | // check if it is jpeg |
||
| 7964 | if (_br.SHORT(0) !== 0xFFD8) { |
||
| 7965 | throw new x.ImageError(x.ImageError.WRONG_FORMAT); |
||
| 7966 | } |
||
| 7967 | |||
| 7968 | // backup headers |
||
| 7969 | _hm = new JPEGHeaders(binstr); |
||
| 7970 | |||
| 7971 | // extract exif info |
||
| 7972 | _ep = new ExifParser(); |
||
| 7973 | hasExif = !!_ep.init(_hm.get('app1')[0]); |
||
| 7974 | |||
| 7975 | // get dimensions |
||
| 7976 | _info = _getDimensions.call(this); |
||
| 7977 | |||
| 7978 | Basic.extend(this, { |
||
| 7979 | type: 'image/jpeg', |
||
| 7980 | |||
| 7981 | size: _binstr.length, |
||
| 7982 | |||
| 7983 | width: _info && _info.width || 0, |
||
| 7984 | |||
| 7985 | height: _info && _info.height || 0, |
||
| 7986 | |||
| 7987 | setExif: function(tag, value) { |
||
| 7988 | if (!hasExif) { |
||
| 7989 | return false; // or throw an exception |
||
| 7990 | } |
||
| 7991 | |||
| 7992 | if (Basic.typeOf(tag) === 'object') { |
||
| 7993 | Basic.each(tag, function(value, tag) { |
||
| 7994 | _ep.setExif(tag, value); |
||
| 7995 | }); |
||
| 7996 | } else { |
||
| 7997 | _ep.setExif(tag, value); |
||
| 7998 | } |
||
| 7999 | |||
| 8000 | // update internal headers |
||
| 8001 | _hm.set('app1', _ep.getBinary()); |
||
| 8002 | }, |
||
| 8003 | |||
| 8004 | writeHeaders: function() { |
||
| 8005 | if (!arguments.length) { |
||
| 8006 | // if no arguments passed, update headers internally |
||
| 8007 | return (_binstr = _hm.restore(_binstr)); |
||
| 8008 | } |
||
| 8009 | return _hm.restore(arguments[0]); |
||
| 8010 | }, |
||
| 8011 | |||
| 8012 | stripHeaders: function(binstr) { |
||
| 8013 | return _hm.strip(binstr); |
||
| 8014 | }, |
||
| 8015 | |||
| 8016 | purge: function() { |
||
| 8017 | _purge.call(this); |
||
| 8018 | } |
||
| 8019 | }); |
||
| 8020 | |||
| 8021 | if (hasExif) { |
||
| 8022 | this.meta = { |
||
| 8023 | tiff: _ep.TIFF(), |
||
| 8024 | exif: _ep.EXIF(), |
||
| 8025 | gps: _ep.GPS() |
||
| 8026 | }; |
||
| 8027 | } |
||
| 8028 | |||
| 8029 | function _purge() { |
||
| 8030 | if (!_ep || !_hm || !_br) { |
||
| 8031 | return; // ignore any repeating purge requests |
||
| 8032 | } |
||
| 8033 | _ep.purge(); |
||
| 8034 | _hm.purge(); |
||
| 8035 | _br.init(null); |
||
| 8036 | _binstr = _info = _hm = _ep = _br = null; |
||
| 8037 | } |
||
| 8038 | } |
||
| 8039 | |||
| 8040 | return JPEG; |
||
| 8041 | }); |
||
| 8042 | |||
| 8043 | // Included from: src/javascript/runtime/html5/image/PNG.js |
||
| 8044 | |||
| 8045 | /** |
||
| 8046 | * PNG.js |
||
| 8047 | * |
||
| 8048 | * Copyright 2013, Moxiecode Systems AB |
||
| 8049 | * Released under GPL License. |
||
| 8050 | * |
||
| 8051 | * License: http://www.plupload.com/license |
||
| 8052 | * Contributing: http://www.plupload.com/contributing |
||
| 8053 | */ |
||
| 8054 | |||
| 8055 | /** |
||
| 8056 | @class moxie/runtime/html5/image/PNG |
||
| 8057 | @private |
||
| 8058 | */ |
||
| 8059 | define("moxie/runtime/html5/image/PNG", [ |
||
| 8060 | "moxie/core/Exceptions", |
||
| 8061 | "moxie/core/utils/Basic", |
||
| 8062 | "moxie/runtime/html5/utils/BinaryReader" |
||
| 8063 | ], function(x, Basic, BinaryReader) { |
||
| 8064 | |||
| 8065 | function PNG(binstr) { |
||
| 8066 | var _binstr, _br, _hm, _ep, _info; |
||
| 8067 | |||
| 8068 | _binstr = binstr; |
||
| 8069 | |||
| 8070 | _br = new BinaryReader(); |
||
| 8071 | _br.init(_binstr); |
||
| 8072 | |||
| 8073 | // check if it's png |
||
| 8074 | (function() { |
||
| 8075 | var idx = 0, i = 0 |
||
| 8076 | , signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A] |
||
| 8077 | ; |
||
| 8078 | |||
| 8079 | for (i = 0; i < signature.length; i++, idx += 2) { |
||
| 8080 | if (signature[i] != _br.SHORT(idx)) { |
||
| 8081 | throw new x.ImageError(x.ImageError.WRONG_FORMAT); |
||
| 8082 | } |
||
| 8083 | } |
||
| 8084 | }()); |
||
| 8085 | |||
| 8086 | function _getDimensions() { |
||
| 8087 | var chunk, idx; |
||
| 8088 | |||
| 8089 | chunk = _getChunkAt.call(this, 8); |
||
| 8090 | |||
| 8091 | if (chunk.type == 'IHDR') { |
||
| 8092 | idx = chunk.start; |
||
| 8093 | return { |
||
| 8094 | width: _br.LONG(idx), |
||
| 8095 | height: _br.LONG(idx += 4) |
||
| 8096 | }; |
||
| 8097 | } |
||
| 8098 | return null; |
||
| 8099 | } |
||
| 8100 | |||
| 8101 | function _purge() { |
||
| 8102 | if (!_br) { |
||
| 8103 | return; // ignore any repeating purge requests |
||
| 8104 | } |
||
| 8105 | _br.init(null); |
||
| 8106 | _binstr = _info = _hm = _ep = _br = null; |
||
| 8107 | } |
||
| 8108 | |||
| 8109 | _info = _getDimensions.call(this); |
||
| 8110 | |||
| 8111 | Basic.extend(this, { |
||
| 8112 | type: 'image/png', |
||
| 8113 | |||
| 8114 | size: _binstr.length, |
||
| 8115 | |||
| 8116 | width: _info.width, |
||
| 8117 | |||
| 8118 | height: _info.height, |
||
| 8119 | |||
| 8120 | purge: function() { |
||
| 8121 | _purge.call(this); |
||
| 8122 | } |
||
| 8123 | }); |
||
| 8124 | |||
| 8125 | // for PNG we can safely trigger purge automatically, as we do not keep any data for later |
||
| 8126 | _purge.call(this); |
||
| 8127 | |||
| 8128 | function _getChunkAt(idx) { |
||
| 8129 | var length, type, start, CRC; |
||
| 8130 | |||
| 8131 | length = _br.LONG(idx); |
||
| 8132 | type = _br.STRING(idx += 4, 4); |
||
| 8133 | start = idx += 4; |
||
| 8134 | CRC = _br.LONG(idx + length); |
||
| 8135 | |||
| 8136 | return { |
||
| 8137 | length: length, |
||
| 8138 | type: type, |
||
| 8139 | start: start, |
||
| 8140 | CRC: CRC |
||
| 8141 | }; |
||
| 8142 | } |
||
| 8143 | } |
||
| 8144 | |||
| 8145 | return PNG; |
||
| 8146 | }); |
||
| 8147 | |||
| 8148 | // Included from: src/javascript/runtime/html5/image/ImageInfo.js |
||
| 8149 | |||
| 8150 | /** |
||
| 8151 | * ImageInfo.js |
||
| 8152 | * |
||
| 8153 | * Copyright 2013, Moxiecode Systems AB |
||
| 8154 | * Released under GPL License. |
||
| 8155 | * |
||
| 8156 | * License: http://www.plupload.com/license |
||
| 8157 | * Contributing: http://www.plupload.com/contributing |
||
| 8158 | */ |
||
| 8159 | |||
| 8160 | /** |
||
| 8161 | @class moxie/runtime/html5/image/ImageInfo |
||
| 8162 | @private |
||
| 8163 | */ |
||
| 8164 | define("moxie/runtime/html5/image/ImageInfo", [ |
||
| 8165 | "moxie/core/utils/Basic", |
||
| 8166 | "moxie/core/Exceptions", |
||
| 8167 | "moxie/runtime/html5/image/JPEG", |
||
| 8168 | "moxie/runtime/html5/image/PNG" |
||
| 8169 | ], function(Basic, x, JPEG, PNG) { |
||
| 8170 | /** |
||
| 8171 | Optional image investigation tool for HTML5 runtime. Provides the following features: |
||
| 8172 | - ability to distinguish image type (JPEG or PNG) by signature |
||
| 8173 | - ability to extract image width/height directly from it's internals, without preloading in memory (fast) |
||
| 8174 | - ability to extract APP headers from JPEGs (Exif, GPS, etc) |
||
| 8175 | - ability to replace width/height tags in extracted JPEG headers |
||
| 8176 | - ability to restore APP headers, that were for example stripped during image manipulation |
||
| 8177 | |||
| 8178 | @class ImageInfo |
||
| 8179 | @constructor |
||
| 8180 | @param {String} binstr Image source as binary string |
||
| 8181 | */ |
||
| 8182 | return function(binstr) { |
||
| 8183 | var _cs = [JPEG, PNG], _img; |
||
| 8184 | |||
| 8185 | // figure out the format, throw: ImageError.WRONG_FORMAT if not supported |
||
| 8186 | _img = (function() { |
||
| 8187 | for (var i = 0; i < _cs.length; i++) { |
||
| 8188 | try { |
||
| 8189 | return new _cs[i](binstr); |
||
| 8190 | } catch (ex) { |
||
| 8191 | // console.info(ex); |
||
| 8192 | } |
||
| 8193 | } |
||
| 8194 | throw new x.ImageError(x.ImageError.WRONG_FORMAT); |
||
| 8195 | }()); |
||
| 8196 | |||
| 8197 | Basic.extend(this, { |
||
| 8198 | /** |
||
| 8199 | Image Mime Type extracted from it's depths |
||
| 8200 | |||
| 8201 | @property type |
||
| 8202 | @type {String} |
||
| 8203 | @default '' |
||
| 8204 | */ |
||
| 8205 | type: '', |
||
| 8206 | |||
| 8207 | /** |
||
| 8208 | Image size in bytes |
||
| 8209 | |||
| 8210 | @property size |
||
| 8211 | @type {Number} |
||
| 8212 | @default 0 |
||
| 8213 | */ |
||
| 8214 | size: 0, |
||
| 8215 | |||
| 8216 | /** |
||
| 8217 | Image width extracted from image source |
||
| 8218 | |||
| 8219 | @property width |
||
| 8220 | @type {Number} |
||
| 8221 | @default 0 |
||
| 8222 | */ |
||
| 8223 | width: 0, |
||
| 8224 | |||
| 8225 | /** |
||
| 8226 | Image height extracted from image source |
||
| 8227 | |||
| 8228 | @property height |
||
| 8229 | @type {Number} |
||
| 8230 | @default 0 |
||
| 8231 | */ |
||
| 8232 | height: 0, |
||
| 8233 | |||
| 8234 | /** |
||
| 8235 | Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs. |
||
| 8236 | |||
| 8237 | @method setExif |
||
| 8238 | @param {String} tag Tag to set |
||
| 8239 | @param {Mixed} value Value to assign to the tag |
||
| 8240 | */ |
||
| 8241 | setExif: function() {}, |
||
| 8242 | |||
| 8243 | /** |
||
| 8244 | Restores headers to the source. |
||
| 8245 | |||
| 8246 | @method writeHeaders |
||
| 8247 | @param {String} data Image source as binary string |
||
| 8248 | @return {String} Updated binary string |
||
| 8249 | */ |
||
| 8250 | writeHeaders: function(data) { |
||
| 8251 | return data; |
||
| 8252 | }, |
||
| 8253 | |||
| 8254 | /** |
||
| 8255 | Strip all headers from the source. |
||
| 8256 | |||
| 8257 | @method stripHeaders |
||
| 8258 | @param {String} data Image source as binary string |
||
| 8259 | @return {String} Updated binary string |
||
| 8260 | */ |
||
| 8261 | stripHeaders: function(data) { |
||
| 8262 | return data; |
||
| 8263 | }, |
||
| 8264 | |||
| 8265 | /** |
||
| 8266 | Dispose resources. |
||
| 8267 | |||
| 8268 | @method purge |
||
| 8269 | */ |
||
| 8270 | purge: function() {} |
||
| 8271 | }); |
||
| 8272 | |||
| 8273 | Basic.extend(this, _img); |
||
| 8274 | |||
| 8275 | this.purge = function() { |
||
| 8276 | _img.purge(); |
||
| 8277 | _img = null; |
||
| 8278 | }; |
||
| 8279 | }; |
||
| 8280 | }); |
||
| 8281 | |||
| 8282 | // Included from: src/javascript/runtime/html5/image/MegaPixel.js |
||
| 8283 | |||
| 8284 | /** |
||
| 8285 | (The MIT License) |
||
| 8286 | |||
| 8287 | Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com>; |
||
| 8288 | |||
| 8289 | Permission is hereby granted, free of charge, to any person obtaining |
||
| 8290 | a copy of this software and associated documentation files (the |
||
| 8291 | 'Software'), to deal in the Software without restriction, including |
||
| 8292 | without limitation the rights to use, copy, modify, merge, publish, |
||
| 8293 | distribute, sublicense, and/or sell copies of the Software, and to |
||
| 8294 | permit persons to whom the Software is furnished to do so, subject to |
||
| 8295 | the following conditions: |
||
| 8296 | |||
| 8297 | The above copyright notice and this permission notice shall be |
||
| 8298 | included in all copies or substantial portions of the Software. |
||
| 8299 | |||
| 8300 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, |
||
| 8301 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
||
| 8302 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. |
||
| 8303 | IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY |
||
| 8304 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, |
||
| 8305 | TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE |
||
| 8306 | SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. |
||
| 8307 | */ |
||
| 8308 | |||
| 8309 | /** |
||
| 8310 | * Mega pixel image rendering library for iOS6 Safari |
||
| 8311 | * |
||
| 8312 | * Fixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel), |
||
| 8313 | * which causes unexpected subsampling when drawing it in canvas. |
||
| 8314 | * By using this library, you can safely render the image with proper stretching. |
||
| 8315 | * |
||
| 8316 | * Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com> |
||
| 8317 | * Released under the MIT license |
||
| 8318 | */ |
||
| 8319 | |||
| 8320 | /** |
||
| 8321 | @class moxie/runtime/html5/image/MegaPixel |
||
| 8322 | @private |
||
| 8323 | */ |
||
| 8324 | define("moxie/runtime/html5/image/MegaPixel", [], function() { |
||
| 8325 | |||
| 8326 | /** |
||
| 8327 | * Rendering image element (with resizing) into the canvas element |
||
| 8328 | */ |
||
| 8329 | function renderImageToCanvas(img, canvas, options) { |
||
| 8330 | var iw = img.naturalWidth, ih = img.naturalHeight; |
||
| 8331 | var width = options.width, height = options.height; |
||
| 8332 | var x = options.x || 0, y = options.y || 0; |
||
| 8333 | var ctx = canvas.getContext('2d'); |
||
| 8334 | if (detectSubsampling(img)) { |
||
| 8335 | iw /= 2; |
||
| 8336 | ih /= 2; |
||
| 8337 | } |
||
| 8338 | var d = 1024; // size of tiling canvas |
||
| 8339 | var tmpCanvas = document.createElement('canvas'); |
||
| 8340 | tmpCanvas.width = tmpCanvas.height = d; |
||
| 8341 | var tmpCtx = tmpCanvas.getContext('2d'); |
||
| 8342 | var vertSquashRatio = detectVerticalSquash(img, iw, ih); |
||
| 8343 | var sy = 0; |
||
| 8344 | while (sy < ih) { |
||
| 8345 | var sh = sy + d > ih ? ih - sy : d; |
||
| 8346 | var sx = 0; |
||
| 8347 | while (sx < iw) { |
||
| 8348 | var sw = sx + d > iw ? iw - sx : d; |
||
| 8349 | tmpCtx.clearRect(0, 0, d, d); |
||
| 8350 | tmpCtx.drawImage(img, -sx, -sy); |
||
| 8351 | var dx = (sx * width / iw + x) << 0; |
||
| 8352 | var dw = Math.ceil(sw * width / iw); |
||
| 8353 | var dy = (sy * height / ih / vertSquashRatio + y) << 0; |
||
| 8354 | var dh = Math.ceil(sh * height / ih / vertSquashRatio); |
||
| 8355 | ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh); |
||
| 8356 | sx += d; |
||
| 8357 | } |
||
| 8358 | sy += d; |
||
| 8359 | } |
||
| 8360 | tmpCanvas = tmpCtx = null; |
||
| 8361 | } |
||
| 8362 | |||
| 8363 | /** |
||
| 8364 | * Detect subsampling in loaded image. |
||
| 8365 | * In iOS, larger images than 2M pixels may be subsampled in rendering. |
||
| 8366 | */ |
||
| 8367 | function detectSubsampling(img) { |
||
| 8368 | var iw = img.naturalWidth, ih = img.naturalHeight; |
||
| 8369 | if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image |
||
| 8370 | var canvas = document.createElement('canvas'); |
||
| 8371 | canvas.width = canvas.height = 1; |
||
| 8372 | var ctx = canvas.getContext('2d'); |
||
| 8373 | ctx.drawImage(img, -iw + 1, 0); |
||
| 8374 | // subsampled image becomes half smaller in rendering size. |
||
| 8375 | // check alpha channel value to confirm image is covering edge pixel or not. |
||
| 8376 | // if alpha value is 0 image is not covering, hence subsampled. |
||
| 8377 | return ctx.getImageData(0, 0, 1, 1).data[3] === 0; |
||
| 8378 | } else { |
||
| 8379 | return false; |
||
| 8380 | } |
||
| 8381 | } |
||
| 8382 | |||
| 8383 | |||
| 8384 | /** |
||
| 8385 | * Detecting vertical squash in loaded image. |
||
| 8386 | * Fixes a bug which squash image vertically while drawing into canvas for some images. |
||
| 8387 | */ |
||
| 8388 | function detectVerticalSquash(img, iw, ih) { |
||
| 8389 | var canvas = document.createElement('canvas'); |
||
| 8390 | canvas.width = 1; |
||
| 8391 | canvas.height = ih; |
||
| 8392 | var ctx = canvas.getContext('2d'); |
||
| 8393 | ctx.drawImage(img, 0, 0); |
||
| 8394 | var data = ctx.getImageData(0, 0, 1, ih).data; |
||
| 8395 | // search image edge pixel position in case it is squashed vertically. |
||
| 8396 | var sy = 0; |
||
| 8397 | var ey = ih; |
||
| 8398 | var py = ih; |
||
| 8399 | while (py > sy) { |
||
| 8400 | var alpha = data[(py - 1) * 4 + 3]; |
||
| 8401 | if (alpha === 0) { |
||
| 8402 | ey = py; |
||
| 8403 | } else { |
||
| 8404 | sy = py; |
||
| 8405 | } |
||
| 8406 | py = (ey + sy) >> 1; |
||
| 8407 | } |
||
| 8408 | canvas = null; |
||
| 8409 | var ratio = (py / ih); |
||
| 8410 | return (ratio === 0) ? 1 : ratio; |
||
| 8411 | } |
||
| 8412 | |||
| 8413 | return { |
||
| 8414 | isSubsampled: detectSubsampling, |
||
| 8415 | renderTo: renderImageToCanvas |
||
| 8416 | }; |
||
| 8417 | }); |
||
| 8418 | |||
| 8419 | // Included from: src/javascript/runtime/html5/image/Image.js |
||
| 8420 | |||
| 8421 | /** |
||
| 8422 | * Image.js |
||
| 8423 | * |
||
| 8424 | * Copyright 2013, Moxiecode Systems AB |
||
| 8425 | * Released under GPL License. |
||
| 8426 | * |
||
| 8427 | * License: http://www.plupload.com/license |
||
| 8428 | * Contributing: http://www.plupload.com/contributing |
||
| 8429 | */ |
||
| 8430 | |||
| 8431 | /** |
||
| 8432 | @class moxie/runtime/html5/image/Image |
||
| 8433 | @private |
||
| 8434 | */ |
||
| 8435 | define("moxie/runtime/html5/image/Image", [ |
||
| 8436 | "moxie/runtime/html5/Runtime", |
||
| 8437 | "moxie/core/utils/Basic", |
||
| 8438 | "moxie/core/Exceptions", |
||
| 8439 | "moxie/core/utils/Encode", |
||
| 8440 | "moxie/file/File", |
||
| 8441 | "moxie/runtime/html5/image/ImageInfo", |
||
| 8442 | "moxie/runtime/html5/image/MegaPixel", |
||
| 8443 | "moxie/core/utils/Mime", |
||
| 8444 | "moxie/core/utils/Env" |
||
| 8445 | ], function(extensions, Basic, x, Encode, File, ImageInfo, MegaPixel, Mime, Env) { |
||
| 8446 | |||
| 8447 | function HTML5Image() { |
||
| 8448 | var me = this |
||
| 8449 | , _img, _imgInfo, _canvas, _binStr, _blob |
||
| 8450 | , _modified = false // is set true whenever image is modified |
||
| 8451 | , _preserveHeaders = true |
||
| 8452 | ; |
||
| 8453 | |||
| 8454 | Basic.extend(this, { |
||
| 8455 | loadFromBlob: function(blob) { |
||
| 8456 | var comp = this, I = comp.getRuntime() |
||
| 8457 | , asBinary = arguments.length > 1 ? arguments[1] : true |
||
| 8458 | ; |
||
| 8459 | |||
| 8460 | if (!I.can('access_binary')) { |
||
| 8461 | throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR); |
||
| 8462 | } |
||
| 8463 | |||
| 8464 | _blob = blob; |
||
| 8465 | |||
| 8466 | if (blob.isDetached()) { |
||
| 8467 | _binStr = blob.getSource(); |
||
| 8468 | _preload.call(this, _binStr); |
||
| 8469 | return; |
||
| 8470 | } else { |
||
| 8471 | _readAsDataUrl.call(this, blob.getSource(), function(dataUrl) { |
||
| 8472 | if (asBinary) { |
||
| 8473 | _binStr = _toBinary(dataUrl); |
||
| 8474 | } |
||
| 8475 | _preload.call(comp, dataUrl); |
||
| 8476 | }); |
||
| 8477 | } |
||
| 8478 | }, |
||
| 8479 | |||
| 8480 | loadFromImage: function(img, exact) { |
||
| 8481 | this.meta = img.meta; |
||
| 8482 | |||
| 8483 | _blob = new File(null, { |
||
| 8484 | name: img.name, |
||
| 8485 | size: img.size, |
||
| 8486 | type: img.type |
||
| 8487 | }); |
||
| 8488 | |||
| 8489 | _preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL()); |
||
| 8490 | }, |
||
| 8491 | |||
| 8492 | getInfo: function() { |
||
| 8493 | var I = this.getRuntime(), info; |
||
| 8494 | |||
| 8495 | if (!_imgInfo && _binStr && I.can('access_image_binary')) { |
||
| 8496 | _imgInfo = new ImageInfo(_binStr); |
||
| 8497 | } |
||
| 8498 | |||
| 8499 | info = { |
||
| 8500 | width: _getImg().width || 0, |
||
| 8501 | height: _getImg().height || 0, |
||
| 8502 | type: _blob.type || Mime.getFileMime(_blob.name), |
||
| 8503 | size: _binStr && _binStr.length || _blob.size || 0, |
||
| 8504 | name: _blob.name || '', |
||
| 8505 | meta: _imgInfo && _imgInfo.meta || this.meta || {} |
||
| 8506 | }; |
||
| 8507 | |||
| 8508 | return info; |
||
| 8509 | }, |
||
| 8510 | |||
| 8511 | downsize: function() { |
||
| 8512 | _downsize.apply(this, arguments); |
||
| 8513 | }, |
||
| 8514 | |||
| 8515 | getAsCanvas: function() { |
||
| 8516 | if (_canvas) { |
||
| 8517 | _canvas.id = this.uid + '_canvas'; |
||
| 8518 | } |
||
| 8519 | return _canvas; |
||
| 8520 | }, |
||
| 8521 | |||
| 8522 | getAsBlob: function(type, quality) { |
||
| 8523 | if (type !== this.type) { |
||
| 8524 | // if different mime type requested prepare image for conversion |
||
| 8525 | _downsize.call(this, this.width, this.height, false); |
||
| 8526 | } |
||
| 8527 | return new File(null, { |
||
| 8528 | name: _blob.name || '', |
||
| 8529 | type: type, |
||
| 8530 | data: me.getAsBinaryString.call(this, type, quality) |
||
| 8531 | }); |
||
| 8532 | }, |
||
| 8533 | |||
| 8534 | getAsDataURL: function(type) { |
||
| 8535 | var quality = arguments[1] || 90; |
||
| 8536 | |||
| 8537 | // if image has not been modified, return the source right away |
||
| 8538 | if (!_modified) { |
||
| 8539 | return _img.src; |
||
| 8540 | } |
||
| 8541 | |||
| 8542 | if ('image/jpeg' !== type) { |
||
| 8543 | return _canvas.toDataURL('image/png'); |
||
| 8544 | } else { |
||
| 8545 | try { |
||
| 8546 | // older Geckos used to result in an exception on quality argument |
||
| 8547 | return _canvas.toDataURL('image/jpeg', quality/100); |
||
| 8548 | } catch (ex) { |
||
| 8549 | return _canvas.toDataURL('image/jpeg'); |
||
| 8550 | } |
||
| 8551 | } |
||
| 8552 | }, |
||
| 8553 | |||
| 8554 | getAsBinaryString: function(type, quality) { |
||
| 8555 | // if image has not been modified, return the source right away |
||
| 8556 | if (!_modified) { |
||
| 8557 | // if image was not loaded from binary string |
||
| 8558 | if (!_binStr) { |
||
| 8559 | _binStr = _toBinary(me.getAsDataURL(type, quality)); |
||
| 8560 | } |
||
| 8561 | return _binStr; |
||
| 8562 | } |
||
| 8563 | |||
| 8564 | if ('image/jpeg' !== type) { |
||
| 8565 | _binStr = _toBinary(me.getAsDataURL(type, quality)); |
||
| 8566 | } else { |
||
| 8567 | var dataUrl; |
||
| 8568 | |||
| 8569 | // if jpeg |
||
| 8570 | if (!quality) { |
||
| 8571 | quality = 90; |
||
| 8572 | } |
||
| 8573 | |||
| 8574 | try { |
||
| 8575 | // older Geckos used to result in an exception on quality argument |
||
| 8576 | dataUrl = _canvas.toDataURL('image/jpeg', quality/100); |
||
| 8577 | } catch (ex) { |
||
| 8578 | dataUrl = _canvas.toDataURL('image/jpeg'); |
||
| 8579 | } |
||
| 8580 | |||
| 8581 | _binStr = _toBinary(dataUrl); |
||
| 8582 | |||
| 8583 | if (_imgInfo) { |
||
| 8584 | _binStr = _imgInfo.stripHeaders(_binStr); |
||
| 8585 | |||
| 8586 | if (_preserveHeaders) { |
||
| 8587 | // update dimensions info in exif |
||
| 8588 | if (_imgInfo.meta && _imgInfo.meta.exif) { |
||
| 8589 | _imgInfo.setExif({ |
||
| 8590 | PixelXDimension: this.width, |
||
| 8591 | PixelYDimension: this.height |
||
| 8592 | }); |
||
| 8593 | } |
||
| 8594 | |||
| 8595 | // re-inject the headers |
||
| 8596 | _binStr = _imgInfo.writeHeaders(_binStr); |
||
| 8597 | } |
||
| 8598 | |||
| 8599 | // will be re-created from fresh on next getInfo call |
||
| 8600 | _imgInfo.purge(); |
||
| 8601 | _imgInfo = null; |
||
| 8602 | } |
||
| 8603 | } |
||
| 8604 | |||
| 8605 | _modified = false; |
||
| 8606 | |||
| 8607 | return _binStr; |
||
| 8608 | }, |
||
| 8609 | |||
| 8610 | destroy: function() { |
||
| 8611 | me = null; |
||
| 8612 | _purge.call(this); |
||
| 8613 | this.getRuntime().getShim().removeInstance(this.uid); |
||
| 8614 | } |
||
| 8615 | }); |
||
| 8616 | |||
| 8617 | |||
| 8618 | function _getImg() { |
||
| 8619 | if (!_canvas && !_img) { |
||
| 8620 | throw new x.ImageError(x.DOMException.INVALID_STATE_ERR); |
||
| 8621 | } |
||
| 8622 | return _canvas || _img; |
||
| 8623 | } |
||
| 8624 | |||
| 8625 | |||
| 8626 | function _toBinary(str) { |
||
| 8627 | return Encode.atob(str.substring(str.indexOf('base64,') + 7)); |
||
| 8628 | } |
||
| 8629 | |||
| 8630 | |||
| 8631 | function _toDataUrl(str, type) { |
||
| 8632 | return 'data:' + (type || '') + ';base64,' + Encode.btoa(str); |
||
| 8633 | } |
||
| 8634 | |||
| 8635 | |||
| 8636 | function _preload(str) { |
||
| 8637 | var comp = this; |
||
| 8638 | |||
| 8639 | _img = new Image(); |
||
| 8640 | _img.onerror = function() { |
||
| 8641 | _purge.call(this); |
||
| 8642 | comp.trigger('error', x.ImageError.WRONG_FORMAT); |
||
| 8643 | }; |
||
| 8644 | _img.onload = function() { |
||
| 8645 | comp.trigger('load'); |
||
| 8646 | }; |
||
| 8647 | |||
| 8648 | _img.src = /^data:[^;]*;base64,/.test(str) ? str : _toDataUrl(str, _blob.type); |
||
| 8649 | } |
||
| 8650 | |||
| 8651 | |||
| 8652 | function _readAsDataUrl(file, callback) { |
||
| 8653 | var comp = this, fr; |
||
| 8654 | |||
| 8655 | // use FileReader if it's available |
||
| 8656 | if (window.FileReader) { |
||
| 8657 | fr = new FileReader(); |
||
| 8658 | fr.onload = function() { |
||
| 8659 | callback(this.result); |
||
| 8660 | }; |
||
| 8661 | fr.onerror = function() { |
||
| 8662 | comp.trigger('error', x.ImageError.WRONG_FORMAT); |
||
| 8663 | }; |
||
| 8664 | fr.readAsDataURL(file); |
||
| 8665 | } else { |
||
| 8666 | return callback(file.getAsDataURL()); |
||
| 8667 | } |
||
| 8668 | } |
||
| 8669 | |||
| 8670 | function _downsize(width, height, crop, preserveHeaders) { |
||
| 8671 | var self = this |
||
| 8672 | , scale |
||
| 8673 | , mathFn |
||
| 8674 | , x = 0 |
||
| 8675 | , y = 0 |
||
| 8676 | , img |
||
| 8677 | , destWidth |
||
| 8678 | , destHeight |
||
| 8679 | , orientation |
||
| 8680 | ; |
||
| 8681 | |||
| 8682 | _preserveHeaders = preserveHeaders; // we will need to check this on export (see getAsBinaryString()) |
||
| 8683 | |||
| 8684 | // take into account orientation tag |
||
| 8685 | orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1; |
||
| 8686 | |||
| 8687 | if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation |
||
| 8688 | // swap dimensions |
||
| 8689 | var tmp = width; |
||
| 8690 | width = height; |
||
| 8691 | height = tmp; |
||
| 8692 | } |
||
| 8693 | |||
| 8694 | img = _getImg(); |
||
| 8695 | |||
| 8696 | // unify dimensions |
||
| 8697 | if (!crop) { |
||
| 8698 | scale = Math.min(width/img.width, height/img.height); |
||
| 8699 | } else { |
||
| 8700 | // one of the dimensions may exceed the actual image dimensions - we need to take the smallest value |
||
| 8701 | width = Math.min(width, img.width); |
||
| 8702 | height = Math.min(height, img.height); |
||
| 8703 | |||
| 8704 | scale = Math.max(width/img.width, height/img.height); |
||
| 8705 | } |
||
| 8706 | |||
| 8707 | // we only downsize here |
||
| 8708 | if (scale > 1 && !crop && preserveHeaders) { |
||
| 8709 | this.trigger('Resize'); |
||
| 8710 | return; |
||
| 8711 | } |
||
| 8712 | |||
| 8713 | // prepare canvas if necessary |
||
| 8714 | if (!_canvas) { |
||
| 8715 | _canvas = document.createElement("canvas"); |
||
| 8716 | } |
||
| 8717 | |||
| 8718 | // calculate dimensions of proportionally resized image |
||
| 8719 | destWidth = Math.round(img.width * scale); |
||
| 8720 | destHeight = Math.round(img.height * scale); |
||
| 8721 | |||
| 8722 | // scale image and canvas |
||
| 8723 | if (crop) { |
||
| 8724 | _canvas.width = width; |
||
| 8725 | _canvas.height = height; |
||
| 8726 | |||
| 8727 | // if dimensions of the resulting image still larger than canvas, center it |
||
| 8728 | if (destWidth > width) { |
||
| 8729 | x = Math.round((destWidth - width) / 2); |
||
| 8730 | } |
||
| 8731 | |||
| 8732 | if (destHeight > height) { |
||
| 8733 | y = Math.round((destHeight - height) / 2); |
||
| 8734 | } |
||
| 8735 | } else { |
||
| 8736 | _canvas.width = destWidth; |
||
| 8737 | _canvas.height = destHeight; |
||
| 8738 | } |
||
| 8739 | |||
| 8740 | // rotate if required, according to orientation tag |
||
| 8741 | if (!_preserveHeaders) { |
||
| 8742 | _rotateToOrientaion(_canvas.width, _canvas.height, orientation); |
||
| 8743 | } |
||
| 8744 | |||
| 8745 | _drawToCanvas.call(this, img, _canvas, -x, -y, destWidth, destHeight); |
||
| 8746 | |||
| 8747 | this.width = _canvas.width; |
||
| 8748 | this.height = _canvas.height; |
||
| 8749 | |||
| 8750 | _modified = true; |
||
| 8751 | self.trigger('Resize'); |
||
| 8752 | } |
||
| 8753 | |||
| 8754 | |||
| 8755 | function _drawToCanvas(img, canvas, x, y, w, h) { |
||
| 8756 | if (Env.OS === 'iOS') { |
||
| 8757 | // avoid squish bug in iOS6 |
||
| 8758 | MegaPixel.renderTo(img, canvas, { width: w, height: h, x: x, y: y }); |
||
| 8759 | } else { |
||
| 8760 | var ctx = canvas.getContext('2d'); |
||
| 8761 | ctx.drawImage(img, x, y, w, h); |
||
| 8762 | } |
||
| 8763 | } |
||
| 8764 | |||
| 8765 | |||
| 8766 | /** |
||
| 8767 | * Transform canvas coordination according to specified frame size and orientation |
||
| 8768 | * Orientation value is from EXIF tag |
||
| 8769 | * @author Shinichi Tomita <shinichi.tomita@gmail.com> |
||
| 8770 | */ |
||
| 8771 | function _rotateToOrientaion(width, height, orientation) { |
||
| 8772 | switch (orientation) { |
||
| 8773 | case 5: |
||
| 8774 | case 6: |
||
| 8775 | case 7: |
||
| 8776 | case 8: |
||
| 8777 | _canvas.width = height; |
||
| 8778 | _canvas.height = width; |
||
| 8779 | break; |
||
| 8780 | default: |
||
| 8781 | _canvas.width = width; |
||
| 8782 | _canvas.height = height; |
||
| 8783 | } |
||
| 8784 | |||
| 8785 | /** |
||
| 8786 | 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side. |
||
| 8787 | 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side. |
||
| 8788 | 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side. |
||
| 8789 | 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side. |
||
| 8790 | 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top. |
||
| 8791 | 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top. |
||
| 8792 | 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom. |
||
| 8793 | 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom. |
||
| 8794 | */ |
||
| 8795 | |||
| 8796 | var ctx = _canvas.getContext('2d'); |
||
| 8797 | switch (orientation) { |
||
| 8798 | case 2: |
||
| 8799 | // horizontal flip |
||
| 8800 | ctx.translate(width, 0); |
||
| 8801 | ctx.scale(-1, 1); |
||
| 8802 | break; |
||
| 8803 | case 3: |
||
| 8804 | // 180 rotate left |
||
| 8805 | ctx.translate(width, height); |
||
| 8806 | ctx.rotate(Math.PI); |
||
| 8807 | break; |
||
| 8808 | case 4: |
||
| 8809 | // vertical flip |
||
| 8810 | ctx.translate(0, height); |
||
| 8811 | ctx.scale(1, -1); |
||
| 8812 | break; |
||
| 8813 | case 5: |
||
| 8814 | // vertical flip + 90 rotate right |
||
| 8815 | ctx.rotate(0.5 * Math.PI); |
||
| 8816 | ctx.scale(1, -1); |
||
| 8817 | break; |
||
| 8818 | case 6: |
||
| 8819 | // 90 rotate right |
||
| 8820 | ctx.rotate(0.5 * Math.PI); |
||
| 8821 | ctx.translate(0, -height); |
||
| 8822 | break; |
||
| 8823 | case 7: |
||
| 8824 | // horizontal flip + 90 rotate right |
||
| 8825 | ctx.rotate(0.5 * Math.PI); |
||
| 8826 | ctx.translate(width, -height); |
||
| 8827 | ctx.scale(-1, 1); |
||
| 8828 | break; |
||
| 8829 | case 8: |
||
| 8830 | // 90 rotate left |
||
| 8831 | ctx.rotate(-0.5 * Math.PI); |
||
| 8832 | ctx.translate(-width, 0); |
||
| 8833 | break; |
||
| 8834 | } |
||
| 8835 | } |
||
| 8836 | |||
| 8837 | |||
| 8838 | function _purge() { |
||
| 8839 | if (_imgInfo) { |
||
| 8840 | _imgInfo.purge(); |
||
| 8841 | _imgInfo = null; |
||
| 8842 | } |
||
| 8843 | _binStr = _img = _canvas = _blob = null; |
||
| 8844 | _modified = false; |
||
| 8845 | } |
||
| 8846 | } |
||
| 8847 | |||
| 8848 | return (extensions.Image = HTML5Image); |
||
| 8849 | }); |
||
| 8850 | |||
| 8851 | // Included from: src/javascript/runtime/flash/Runtime.js |
||
| 8852 | |||
| 8853 | /** |
||
| 8854 | * Runtime.js |
||
| 8855 | * |
||
| 8856 | * Copyright 2013, Moxiecode Systems AB |
||
| 8857 | * Released under GPL License. |
||
| 8858 | * |
||
| 8859 | * License: http://www.plupload.com/license |
||
| 8860 | * Contributing: http://www.plupload.com/contributing |
||
| 8861 | */ |
||
| 8862 | |||
| 8863 | /*global ActiveXObject:true */ |
||
| 8864 | |||
| 8865 | /** |
||
| 8866 | Defines constructor for Flash runtime. |
||
| 8867 | |||
| 8868 | @class moxie/runtime/flash/Runtime |
||
| 8869 | @private |
||
| 8870 | */ |
||
| 8871 | define("moxie/runtime/flash/Runtime", [ |
||
| 8872 | "moxie/core/utils/Basic", |
||
| 8873 | "moxie/core/utils/Env", |
||
| 8874 | "moxie/core/utils/Dom", |
||
| 8875 | "moxie/core/Exceptions", |
||
| 8876 | "moxie/runtime/Runtime" |
||
| 8877 | ], function(Basic, Env, Dom, x, Runtime) { |
||
| 8878 | |||
| 8879 | var type = 'flash', extensions = {}; |
||
| 8880 | |||
| 8881 | /** |
||
| 8882 | Get the version of the Flash Player |
||
| 8883 | |||
| 8884 | @method getShimVersion |
||
| 8885 | @private |
||
| 8886 | @return {Number} Flash Player version |
||
| 8887 | */ |
||
| 8888 | function getShimVersion() { |
||
| 8889 | var version; |
||
| 8890 | |||
| 8891 | try { |
||
| 8892 | version = navigator.plugins['Shockwave Flash']; |
||
| 8893 | version = version.description; |
||
| 8894 | } catch (e1) { |
||
| 8895 | try { |
||
| 8896 | version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version'); |
||
| 8897 | } catch (e2) { |
||
| 8898 | version = '0.0'; |
||
| 8899 | } |
||
| 8900 | } |
||
| 8901 | version = version.match(/\d+/g); |
||
| 8902 | return parseFloat(version[0] + '.' + version[1]); |
||
| 8903 | } |
||
| 8904 | |||
| 8905 | /** |
||
| 8906 | Constructor for the Flash Runtime |
||
| 8907 | |||
| 8908 | @class FlashRuntime |
||
| 8909 | @extends Runtime |
||
| 8910 | */ |
||
| 8911 | function FlashRuntime(options) { |
||
| 8912 | var I = this, initTimer; |
||
| 8913 | |||
| 8914 | options = Basic.extend({ swf_url: Env.swf_url }, options); |
||
| 8915 | |||
| 8916 | Runtime.call(this, options, type, { |
||
| 8917 | access_binary: function(value) { |
||
| 8918 | return value && I.mode === 'browser'; |
||
| 8919 | }, |
||
| 8920 | access_image_binary: function(value) { |
||
| 8921 | return value && I.mode === 'browser'; |
||
| 8922 | }, |
||
| 8923 | display_media: Runtime.capTrue, |
||
| 8924 | do_cors: Runtime.capTrue, |
||
| 8925 | drag_and_drop: false, |
||
| 8926 | report_upload_progress: function() { |
||
| 8927 | return I.mode === 'client'; |
||
| 8928 | }, |
||
| 8929 | resize_image: Runtime.capTrue, |
||
| 8930 | return_response_headers: false, |
||
| 8931 | return_response_type: function(responseType) { |
||
| 8932 | if (responseType === 'json' && !!window.JSON) { |
||
| 8933 | return true; |
||
| 8934 | } |
||
| 8935 | return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser'; |
||
| 8936 | }, |
||
| 8937 | return_status_code: function(code) { |
||
| 8938 | return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]); |
||
| 8939 | }, |
||
| 8940 | select_file: Runtime.capTrue, |
||
| 8941 | select_multiple: Runtime.capTrue, |
||
| 8942 | send_binary_string: function(value) { |
||
| 8943 | return value && I.mode === 'browser'; |
||
| 8944 | }, |
||
| 8945 | send_browser_cookies: function(value) { |
||
| 8946 | return value && I.mode === 'browser'; |
||
| 8947 | }, |
||
| 8948 | send_custom_headers: function(value) { |
||
| 8949 | return value && I.mode === 'browser'; |
||
| 8950 | }, |
||
| 8951 | send_multipart: Runtime.capTrue, |
||
| 8952 | slice_blob: function(value) { |
||
| 8953 | return value && I.mode === 'browser'; |
||
| 8954 | }, |
||
| 8955 | stream_upload: function(value) { |
||
| 8956 | return value && I.mode === 'browser'; |
||
| 8957 | }, |
||
| 8958 | summon_file_dialog: false, |
||
| 8959 | upload_filesize: function(size) { |
||
| 8960 | return Basic.parseSizeStr(size) <= 2097152 || I.mode === 'client'; |
||
| 8961 | }, |
||
| 8962 | use_http_method: function(methods) { |
||
| 8963 | return !Basic.arrayDiff(methods, ['GET', 'POST']); |
||
| 8964 | } |
||
| 8965 | }, { |
||
| 8966 | // capabilities that require specific mode |
||
| 8967 | access_binary: function(value) { |
||
| 8968 | return value ? 'browser' : 'client'; |
||
| 8969 | }, |
||
| 8970 | access_image_binary: function(value) { |
||
| 8971 | return value ? 'browser' : 'client'; |
||
| 8972 | }, |
||
| 8973 | report_upload_progress: function(value) { |
||
| 8974 | return value ? 'browser' : 'client'; |
||
| 8975 | }, |
||
| 8976 | return_response_type: function(responseType) { |
||
| 8977 | return Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) ? 'browser' : ['client', 'browser']; |
||
| 8978 | }, |
||
| 8979 | return_status_code: function(code) { |
||
| 8980 | return Basic.arrayDiff(code, [200, 404]) ? 'browser' : ['client', 'browser']; |
||
| 8981 | }, |
||
| 8982 | send_binary_string: function(value) { |
||
| 8983 | return value ? 'browser' : 'client'; |
||
| 8984 | }, |
||
| 8985 | send_browser_cookies: function(value) { |
||
| 8986 | return value ? 'browser' : 'client'; |
||
| 8987 | }, |
||
| 8988 | send_custom_headers: function(value) { |
||
| 8989 | return value ? 'browser' : 'client'; |
||
| 8990 | }, |
||
| 8991 | stream_upload: function(value) { |
||
| 8992 | return value ? 'client' : 'browser'; |
||
| 8993 | }, |
||
| 8994 | upload_filesize: function(size) { |
||
| 8995 | return Basic.parseSizeStr(size) >= 2097152 ? 'client' : 'browser'; |
||
| 8996 | } |
||
| 8997 | }, 'client'); |
||
| 8998 | |||
| 8999 | |||
| 9000 | // minimal requirement for Flash Player version |
||
| 9001 | if (getShimVersion() < 10) { |
||
| 9002 | this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before |
||
| 9003 | } |
||
| 9004 | |||
| 9005 | |||
| 9006 | Basic.extend(this, { |
||
| 9007 | |||
| 9008 | getShim: function() { |
||
| 9009 | return Dom.get(this.uid); |
||
| 9010 | }, |
||
| 9011 | |||
| 9012 | shimExec: function(component, action) { |
||
| 9013 | var args = [].slice.call(arguments, 2); |
||
| 9014 | return I.getShim().exec(this.uid, component, action, args); |
||
| 9015 | }, |
||
| 9016 | |||
| 9017 | init: function() { |
||
| 9018 | var html, el, container; |
||
| 9019 | |||
| 9020 | container = this.getShimContainer(); |
||
| 9021 | |||
| 9022 | // if not the minimal height, shims are not initialized in older browsers (e.g FF3.6, IE6,7,8, Safari 4.0,5.0, etc) |
||
| 9023 | Basic.extend(container.style, { |
||
| 9024 | position: 'absolute', |
||
| 9025 | top: '-8px', |
||
| 9026 | left: '-8px', |
||
| 9027 | width: '9px', |
||
| 9028 | height: '9px', |
||
| 9029 | overflow: 'hidden' |
||
| 9030 | }); |
||
| 9031 | |||
| 9032 | // insert flash object |
||
| 9033 | html = '<object id="' + this.uid + '" type="application/x-shockwave-flash" data="' + options.swf_url + '" '; |
||
| 9034 | |||
| 9035 | if (Env.browser === 'IE') { |
||
| 9036 | html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" '; |
||
| 9037 | } |
||
| 9038 | |||
| 9039 | html += 'width="100%" height="100%" style="outline:0">' + |
||
| 9040 | '<param name="movie" value="' + options.swf_url + '" />' + |
||
| 9041 | '<param name="flashvars" value="uid=' + escape(this.uid) + '&target=' + Env.global_event_dispatcher + '" />' + |
||
| 9042 | '<param name="wmode" value="transparent" />' + |
||
| 9043 | '<param name="allowscriptaccess" value="always" />' + |
||
| 9044 | '</object>'; |
||
| 9045 | |||
| 9046 | if (Env.browser === 'IE') { |
||
| 9047 | el = document.createElement('div'); |
||
| 9048 | container.appendChild(el); |
||
| 9049 | el.outerHTML = html; |
||
| 9050 | el = container = null; // just in case |
||
| 9051 | } else { |
||
| 9052 | container.innerHTML = html; |
||
| 9053 | } |
||
| 9054 | |||
| 9055 | // Init is dispatched by the shim |
||
| 9056 | initTimer = setTimeout(function() { |
||
| 9057 | if (I && !I.initialized) { // runtime might be already destroyed by this moment |
||
| 9058 | I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); |
||
| 9059 | } |
||
| 9060 | }, 5000); |
||
| 9061 | }, |
||
| 9062 | |||
| 9063 | destroy: (function(destroy) { // extend default destroy method |
||
| 9064 | return function() { |
||
| 9065 | destroy.call(I); |
||
| 9066 | clearTimeout(initTimer); // initialization check might be still onwait |
||
| 9067 | options = initTimer = destroy = I = null; |
||
| 9068 | }; |
||
| 9069 | }(this.destroy)) |
||
| 9070 | |||
| 9071 | }, extensions); |
||
| 9072 | } |
||
| 9073 | |||
| 9074 | Runtime.addConstructor(type, FlashRuntime); |
||
| 9075 | |||
| 9076 | return extensions; |
||
| 9077 | }); |
||
| 9078 | |||
| 9079 | // Included from: src/javascript/runtime/flash/file/Blob.js |
||
| 9080 | |||
| 9081 | /** |
||
| 9082 | * Blob.js |
||
| 9083 | * |
||
| 9084 | * Copyright 2013, Moxiecode Systems AB |
||
| 9085 | * Released under GPL License. |
||
| 9086 | * |
||
| 9087 | * License: http://www.plupload.com/license |
||
| 9088 | * Contributing: http://www.plupload.com/contributing |
||
| 9089 | */ |
||
| 9090 | |||
| 9091 | /** |
||
| 9092 | @class moxie/runtime/flash/file/Blob |
||
| 9093 | @private |
||
| 9094 | */ |
||
| 9095 | define("moxie/runtime/flash/file/Blob", [ |
||
| 9096 | "moxie/runtime/flash/Runtime", |
||
| 9097 | "moxie/file/Blob" |
||
| 9098 | ], function(extensions, Blob) { |
||
| 9099 | |||
| 9100 | var FlashBlob = { |
||
| 9101 | slice: function(blob, start, end, type) { |
||
| 9102 | var self = this.getRuntime(); |
||
| 9103 | |||
| 9104 | if (start < 0) { |
||
| 9105 | start = Math.max(blob.size + start, 0); |
||
| 9106 | } else if (start > 0) { |
||
| 9107 | start = Math.min(start, blob.size); |
||
| 9108 | } |
||
| 9109 | |||
| 9110 | if (end < 0) { |
||
| 9111 | end = Math.max(blob.size + end, 0); |
||
| 9112 | } else if (end > 0) { |
||
| 9113 | end = Math.min(end, blob.size); |
||
| 9114 | } |
||
| 9115 | |||
| 9116 | blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || ''); |
||
| 9117 | |||
| 9118 | if (blob) { |
||
| 9119 | blob = new Blob(self.uid, blob); |
||
| 9120 | } |
||
| 9121 | return blob; |
||
| 9122 | } |
||
| 9123 | }; |
||
| 9124 | |||
| 9125 | return (extensions.Blob = FlashBlob); |
||
| 9126 | }); |
||
| 9127 | |||
| 9128 | // Included from: src/javascript/runtime/flash/file/FileInput.js |
||
| 9129 | |||
| 9130 | /** |
||
| 9131 | * FileInput.js |
||
| 9132 | * |
||
| 9133 | * Copyright 2013, Moxiecode Systems AB |
||
| 9134 | * Released under GPL License. |
||
| 9135 | * |
||
| 9136 | * License: http://www.plupload.com/license |
||
| 9137 | * Contributing: http://www.plupload.com/contributing |
||
| 9138 | */ |
||
| 9139 | |||
| 9140 | /** |
||
| 9141 | @class moxie/runtime/flash/file/FileInput |
||
| 9142 | @private |
||
| 9143 | */ |
||
| 9144 | define("moxie/runtime/flash/file/FileInput", [ |
||
| 9145 | "moxie/runtime/flash/Runtime" |
||
| 9146 | ], function(extensions) { |
||
| 9147 | |||
| 9148 | var FileInput = { |
||
| 9149 | init: function(options) { |
||
| 9150 | this.getRuntime().shimExec.call(this, 'FileInput', 'init', { |
||
| 9151 | name: options.name, |
||
| 9152 | accept: options.accept, |
||
| 9153 | multiple: options.multiple |
||
| 9154 | }); |
||
| 9155 | this.trigger('ready'); |
||
| 9156 | } |
||
| 9157 | }; |
||
| 9158 | |||
| 9159 | return (extensions.FileInput = FileInput); |
||
| 9160 | }); |
||
| 9161 | |||
| 9162 | // Included from: src/javascript/runtime/flash/file/FileReader.js |
||
| 9163 | |||
| 9164 | /** |
||
| 9165 | * FileReader.js |
||
| 9166 | * |
||
| 9167 | * Copyright 2013, Moxiecode Systems AB |
||
| 9168 | * Released under GPL License. |
||
| 9169 | * |
||
| 9170 | * License: http://www.plupload.com/license |
||
| 9171 | * Contributing: http://www.plupload.com/contributing |
||
| 9172 | */ |
||
| 9173 | |||
| 9174 | /** |
||
| 9175 | @class moxie/runtime/flash/file/FileReader |
||
| 9176 | @private |
||
| 9177 | */ |
||
| 9178 | define("moxie/runtime/flash/file/FileReader", [ |
||
| 9179 | "moxie/runtime/flash/Runtime", |
||
| 9180 | "moxie/core/utils/Encode" |
||
| 9181 | ], function(extensions, Encode) { |
||
| 9182 | |||
| 9183 | var _result = ''; |
||
| 9184 | |||
| 9185 | function _formatData(data, op) { |
||
| 9186 | switch (op) { |
||
| 9187 | case 'readAsText': |
||
| 9188 | return Encode.atob(data, 'utf8'); |
||
| 9189 | case 'readAsBinaryString': |
||
| 9190 | return Encode.atob(data); |
||
| 9191 | case 'readAsDataURL': |
||
| 9192 | return data; |
||
| 9193 | } |
||
| 9194 | return null; |
||
| 9195 | } |
||
| 9196 | |||
| 9197 | var FileReader = { |
||
| 9198 | read: function(op, blob) { |
||
| 9199 | var target = this, self = target.getRuntime(); |
||
| 9200 | |||
| 9201 | // special prefix for DataURL read mode |
||
| 9202 | if (op === 'readAsDataURL') { |
||
| 9203 | _result = 'data:' + (blob.type || '') + ';base64,'; |
||
| 9204 | } |
||
| 9205 | |||
| 9206 | target.bind('Progress', function(e, data) { |
||
| 9207 | if (data) { |
||
| 9208 | _result += _formatData(data, op); |
||
| 9209 | } |
||
| 9210 | }); |
||
| 9211 | |||
| 9212 | return self.shimExec.call(this, 'FileReader', 'readAsBase64', blob.uid); |
||
| 9213 | }, |
||
| 9214 | |||
| 9215 | getResult: function() { |
||
| 9216 | return _result; |
||
| 9217 | }, |
||
| 9218 | |||
| 9219 | destroy: function() { |
||
| 9220 | _result = null; |
||
| 9221 | } |
||
| 9222 | }; |
||
| 9223 | |||
| 9224 | return (extensions.FileReader = FileReader); |
||
| 9225 | }); |
||
| 9226 | |||
| 9227 | // Included from: src/javascript/runtime/flash/file/FileReaderSync.js |
||
| 9228 | |||
| 9229 | /** |
||
| 9230 | * FileReaderSync.js |
||
| 9231 | * |
||
| 9232 | * Copyright 2013, Moxiecode Systems AB |
||
| 9233 | * Released under GPL License. |
||
| 9234 | * |
||
| 9235 | * License: http://www.plupload.com/license |
||
| 9236 | * Contributing: http://www.plupload.com/contributing |
||
| 9237 | */ |
||
| 9238 | |||
| 9239 | /** |
||
| 9240 | @class moxie/runtime/flash/file/FileReaderSync |
||
| 9241 | @private |
||
| 9242 | */ |
||
| 9243 | define("moxie/runtime/flash/file/FileReaderSync", [ |
||
| 9244 | "moxie/runtime/flash/Runtime", |
||
| 9245 | "moxie/core/utils/Encode" |
||
| 9246 | ], function(extensions, Encode) { |
||
| 9247 | |||
| 9248 | function _formatData(data, op) { |
||
| 9249 | switch (op) { |
||
| 9250 | case 'readAsText': |
||
| 9251 | return Encode.atob(data, 'utf8'); |
||
| 9252 | case 'readAsBinaryString': |
||
| 9253 | return Encode.atob(data); |
||
| 9254 | case 'readAsDataURL': |
||
| 9255 | return data; |
||
| 9256 | } |
||
| 9257 | return null; |
||
| 9258 | } |
||
| 9259 | |||
| 9260 | var FileReaderSync = { |
||
| 9261 | read: function(op, blob) { |
||
| 9262 | var result, self = this.getRuntime(); |
||
| 9263 | |||
| 9264 | result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid); |
||
| 9265 | if (!result) { |
||
| 9266 | return null; // or throw ex |
||
| 9267 | } |
||
| 9268 | |||
| 9269 | // special prefix for DataURL read mode |
||
| 9270 | if (op === 'readAsDataURL') { |
||
| 9271 | result = 'data:' + (blob.type || '') + ';base64,' + result; |
||
| 9272 | } |
||
| 9273 | |||
| 9274 | return _formatData(result, op, blob.type); |
||
| 9275 | } |
||
| 9276 | }; |
||
| 9277 | |||
| 9278 | return (extensions.FileReaderSync = FileReaderSync); |
||
| 9279 | }); |
||
| 9280 | |||
| 9281 | // Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js |
||
| 9282 | |||
| 9283 | /** |
||
| 9284 | * XMLHttpRequest.js |
||
| 9285 | * |
||
| 9286 | * Copyright 2013, Moxiecode Systems AB |
||
| 9287 | * Released under GPL License. |
||
| 9288 | * |
||
| 9289 | * License: http://www.plupload.com/license |
||
| 9290 | * Contributing: http://www.plupload.com/contributing |
||
| 9291 | */ |
||
| 9292 | |||
| 9293 | /** |
||
| 9294 | @class moxie/runtime/flash/xhr/XMLHttpRequest |
||
| 9295 | @private |
||
| 9296 | */ |
||
| 9297 | define("moxie/runtime/flash/xhr/XMLHttpRequest", [ |
||
| 9298 | "moxie/runtime/flash/Runtime", |
||
| 9299 | "moxie/core/utils/Basic", |
||
| 9300 | "moxie/file/Blob", |
||
| 9301 | "moxie/file/File", |
||
| 9302 | "moxie/file/FileReaderSync", |
||
| 9303 | "moxie/xhr/FormData", |
||
| 9304 | "moxie/runtime/Transporter" |
||
| 9305 | ], function(extensions, Basic, Blob, File, FileReaderSync, FormData, Transporter) { |
||
| 9306 | |||
| 9307 | var XMLHttpRequest = { |
||
| 9308 | |||
| 9309 | send: function(meta, data) { |
||
| 9310 | var target = this, self = target.getRuntime(); |
||
| 9311 | |||
| 9312 | function send() { |
||
| 9313 | meta.transport = self.mode; |
||
| 9314 | self.shimExec.call(target, 'XMLHttpRequest', 'send', meta, data); |
||
| 9315 | } |
||
| 9316 | |||
| 9317 | |||
| 9318 | function appendBlob(name, blob) { |
||
| 9319 | self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid); |
||
| 9320 | data = null; |
||
| 9321 | send(); |
||
| 9322 | } |
||
| 9323 | |||
| 9324 | |||
| 9325 | function attachBlob(blob, cb) { |
||
| 9326 | var tr = new Transporter(); |
||
| 9327 | |||
| 9328 | tr.bind("TransportingComplete", function() { |
||
| 9329 | cb(this.result); |
||
| 9330 | }); |
||
| 9331 | |||
| 9332 | tr.transport(blob.getSource(), blob.type, { |
||
| 9333 | ruid: self.uid |
||
| 9334 | }); |
||
| 9335 | } |
||
| 9336 | |||
| 9337 | // copy over the headers if any |
||
| 9338 | if (!Basic.isEmptyObj(meta.headers)) { |
||
| 9339 | Basic.each(meta.headers, function(value, header) { |
||
| 9340 | self.shimExec.call(target, 'XMLHttpRequest', 'setRequestHeader', header, value.toString()); // Silverlight doesn't accept integers into the arguments of type object |
||
| 9341 | }); |
||
| 9342 | } |
||
| 9343 | |||
| 9344 | // transfer over multipart params and blob itself |
||
| 9345 | if (data instanceof FormData) { |
||
| 9346 | var blobField; |
||
| 9347 | data.each(function(value, name) { |
||
| 9348 | if (value instanceof Blob) { |
||
| 9349 | blobField = name; |
||
| 9350 | } else { |
||
| 9351 | self.shimExec.call(target, 'XMLHttpRequest', 'append', name, value); |
||
| 9352 | } |
||
| 9353 | }); |
||
| 9354 | |||
| 9355 | if (!data.hasBlob()) { |
||
| 9356 | data = null; |
||
| 9357 | send(); |
||
| 9358 | } else { |
||
| 9359 | var blob = data.getBlob(); |
||
| 9360 | if (blob.isDetached()) { |
||
| 9361 | attachBlob(blob, function(attachedBlob) { |
||
| 9362 | blob.destroy(); |
||
| 9363 | appendBlob(blobField, attachedBlob); |
||
| 9364 | }); |
||
| 9365 | } else { |
||
| 9366 | appendBlob(blobField, blob); |
||
| 9367 | } |
||
| 9368 | } |
||
| 9369 | } else if (data instanceof Blob) { |
||
| 9370 | if (data.isDetached()) { |
||
| 9371 | attachBlob(data, function(attachedBlob) { |
||
| 9372 | data.destroy(); |
||
| 9373 | data = attachedBlob.uid; |
||
| 9374 | send(); |
||
| 9375 | }); |
||
| 9376 | } else { |
||
| 9377 | data = data.uid; |
||
| 9378 | send(); |
||
| 9379 | } |
||
| 9380 | } else { |
||
| 9381 | send(); |
||
| 9382 | } |
||
| 9383 | }, |
||
| 9384 | |||
| 9385 | getResponse: function(responseType) { |
||
| 9386 | var frs, blob, self = this.getRuntime(); |
||
| 9387 | |||
| 9388 | blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob'); |
||
| 9389 | |||
| 9390 | if (blob) { |
||
| 9391 | blob = new File(self.uid, blob); |
||
| 9392 | |||
| 9393 | if ('blob' === responseType) { |
||
| 9394 | return blob; |
||
| 9395 | } |
||
| 9396 | |||
| 9397 | try { |
||
| 9398 | frs = new FileReaderSync(); |
||
| 9399 | |||
| 9400 | if (!!~Basic.inArray(responseType, ["", "text"])) { |
||
| 9401 | return frs.readAsText(blob); |
||
| 9402 | } else if ('json' === responseType && !!window.JSON) { |
||
| 9403 | return JSON.parse(frs.readAsText(blob)); |
||
| 9404 | } |
||
| 9405 | } finally { |
||
| 9406 | blob.destroy(); |
||
| 9407 | } |
||
| 9408 | } |
||
| 9409 | return null; |
||
| 9410 | }, |
||
| 9411 | |||
| 9412 | abort: function(upload_complete_flag) { |
||
| 9413 | var self = this.getRuntime(); |
||
| 9414 | |||
| 9415 | self.shimExec.call(this, 'XMLHttpRequest', 'abort'); |
||
| 9416 | |||
| 9417 | this.dispatchEvent('readystatechange'); |
||
| 9418 | // this.dispatchEvent('progress'); |
||
| 9419 | this.dispatchEvent('abort'); |
||
| 9420 | |||
| 9421 | //if (!upload_complete_flag) { |
||
| 9422 | // this.dispatchEvent('uploadprogress'); |
||
| 9423 | //} |
||
| 9424 | } |
||
| 9425 | }; |
||
| 9426 | |||
| 9427 | return (extensions.XMLHttpRequest = XMLHttpRequest); |
||
| 9428 | }); |
||
| 9429 | |||
| 9430 | // Included from: src/javascript/runtime/flash/runtime/Transporter.js |
||
| 9431 | |||
| 9432 | /** |
||
| 9433 | * Transporter.js |
||
| 9434 | * |
||
| 9435 | * Copyright 2013, Moxiecode Systems AB |
||
| 9436 | * Released under GPL License. |
||
| 9437 | * |
||
| 9438 | * License: http://www.plupload.com/license |
||
| 9439 | * Contributing: http://www.plupload.com/contributing |
||
| 9440 | */ |
||
| 9441 | |||
| 9442 | /** |
||
| 9443 | @class moxie/runtime/flash/runtime/Transporter |
||
| 9444 | @private |
||
| 9445 | */ |
||
| 9446 | define("moxie/runtime/flash/runtime/Transporter", [ |
||
| 9447 | "moxie/runtime/flash/Runtime", |
||
| 9448 | "moxie/file/Blob" |
||
| 9449 | ], function(extensions, Blob) { |
||
| 9450 | |||
| 9451 | var Transporter = { |
||
| 9452 | getAsBlob: function(type) { |
||
| 9453 | var self = this.getRuntime() |
||
| 9454 | , blob = self.shimExec.call(this, 'Transporter', 'getAsBlob', type) |
||
| 9455 | ; |
||
| 9456 | if (blob) { |
||
| 9457 | return new Blob(self.uid, blob); |
||
| 9458 | } |
||
| 9459 | return null; |
||
| 9460 | } |
||
| 9461 | }; |
||
| 9462 | |||
| 9463 | return (extensions.Transporter = Transporter); |
||
| 9464 | }); |
||
| 9465 | |||
| 9466 | // Included from: src/javascript/runtime/flash/image/Image.js |
||
| 9467 | |||
| 9468 | /** |
||
| 9469 | * Image.js |
||
| 9470 | * |
||
| 9471 | * Copyright 2013, Moxiecode Systems AB |
||
| 9472 | * Released under GPL License. |
||
| 9473 | * |
||
| 9474 | * License: http://www.plupload.com/license |
||
| 9475 | * Contributing: http://www.plupload.com/contributing |
||
| 9476 | */ |
||
| 9477 | |||
| 9478 | /** |
||
| 9479 | @class moxie/runtime/flash/image/Image |
||
| 9480 | @private |
||
| 9481 | */ |
||
| 9482 | define("moxie/runtime/flash/image/Image", [ |
||
| 9483 | "moxie/runtime/flash/Runtime", |
||
| 9484 | "moxie/core/utils/Basic", |
||
| 9485 | "moxie/runtime/Transporter", |
||
| 9486 | "moxie/file/Blob", |
||
| 9487 | "moxie/file/FileReaderSync" |
||
| 9488 | ], function(extensions, Basic, Transporter, Blob, FileReaderSync) { |
||
| 9489 | |||
| 9490 | var Image = { |
||
| 9491 | loadFromBlob: function(blob) { |
||
| 9492 | var comp = this, self = comp.getRuntime(); |
||
| 9493 | |||
| 9494 | function exec(srcBlob) { |
||
| 9495 | self.shimExec.call(comp, 'Image', 'loadFromBlob', srcBlob.uid); |
||
| 9496 | comp = self = null; |
||
| 9497 | } |
||
| 9498 | |||
| 9499 | if (blob.isDetached()) { // binary string |
||
| 9500 | var tr = new Transporter(); |
||
| 9501 | tr.bind("TransportingComplete", function() { |
||
| 9502 | exec(tr.result.getSource()); |
||
| 9503 | }); |
||
| 9504 | tr.transport(blob.getSource(), blob.type, { ruid: self.uid }); |
||
| 9505 | } else { |
||
| 9506 | exec(blob.getSource()); |
||
| 9507 | } |
||
| 9508 | }, |
||
| 9509 | |||
| 9510 | loadFromImage: function(img) { |
||
| 9511 | var self = this.getRuntime(); |
||
| 9512 | return self.shimExec.call(this, 'Image', 'loadFromImage', img.uid); |
||
| 9513 | }, |
||
| 9514 | |||
| 9515 | getAsBlob: function(type, quality) { |
||
| 9516 | var self = this.getRuntime() |
||
| 9517 | , blob = self.shimExec.call(this, 'Image', 'getAsBlob', type, quality) |
||
| 9518 | ; |
||
| 9519 | if (blob) { |
||
| 9520 | return new Blob(self.uid, blob); |
||
| 9521 | } |
||
| 9522 | return null; |
||
| 9523 | }, |
||
| 9524 | |||
| 9525 | getAsDataURL: function() { |
||
| 9526 | var self = this.getRuntime() |
||
| 9527 | , blob = self.Image.getAsBlob.apply(this, arguments) |
||
| 9528 | , frs |
||
| 9529 | ; |
||
| 9530 | if (!blob) { |
||
| 9531 | return null; |
||
| 9532 | } |
||
| 9533 | frs = new FileReaderSync(); |
||
| 9534 | return frs.readAsDataURL(blob); |
||
| 9535 | } |
||
| 9536 | }; |
||
| 9537 | |||
| 9538 | return (extensions.Image = Image); |
||
| 9539 | }); |
||
| 9540 | |||
| 9541 | // Included from: src/javascript/runtime/silverlight/Runtime.js |
||
| 9542 | |||
| 9543 | /** |
||
| 9544 | * RunTime.js |
||
| 9545 | * |
||
| 9546 | * Copyright 2013, Moxiecode Systems AB |
||
| 9547 | * Released under GPL License. |
||
| 9548 | * |
||
| 9549 | * License: http://www.plupload.com/license |
||
| 9550 | * Contributing: http://www.plupload.com/contributing |
||
| 9551 | */ |
||
| 9552 | |||
| 9553 | /*global ActiveXObject:true */ |
||
| 9554 | |||
| 9555 | /** |
||
| 9556 | Defines constructor for Silverlight runtime. |
||
| 9557 | |||
| 9558 | @class moxie/runtime/silverlight/Runtime |
||
| 9559 | @private |
||
| 9560 | */ |
||
| 9561 | define("moxie/runtime/silverlight/Runtime", [ |
||
| 9562 | "moxie/core/utils/Basic", |
||
| 9563 | "moxie/core/utils/Env", |
||
| 9564 | "moxie/core/utils/Dom", |
||
| 9565 | "moxie/core/Exceptions", |
||
| 9566 | "moxie/runtime/Runtime" |
||
| 9567 | ], function(Basic, Env, Dom, x, Runtime) { |
||
| 9568 | |||
| 9569 | var type = "silverlight", extensions = {}; |
||
| 9570 | |||
| 9571 | function isInstalled(version) { |
||
| 9572 | var isVersionSupported = false, control = null, actualVer, |
||
| 9573 | actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0; |
||
| 9574 | |||
| 9575 | try { |
||
| 9576 | try { |
||
| 9577 | control = new ActiveXObject('AgControl.AgControl'); |
||
| 9578 | |||
| 9579 | if (control.IsVersionSupported(version)) { |
||
| 9580 | isVersionSupported = true; |
||
| 9581 | } |
||
| 9582 | |||
| 9583 | control = null; |
||
| 9584 | } catch (e) { |
||
| 9585 | var plugin = navigator.plugins["Silverlight Plug-In"]; |
||
| 9586 | |||
| 9587 | if (plugin) { |
||
| 9588 | actualVer = plugin.description; |
||
| 9589 | |||
| 9590 | if (actualVer === "1.0.30226.2") { |
||
| 9591 | actualVer = "2.0.30226.2"; |
||
| 9592 | } |
||
| 9593 | |||
| 9594 | actualVerArray = actualVer.split("."); |
||
| 9595 | |||
| 9596 | while (actualVerArray.length > 3) { |
||
| 9597 | actualVerArray.pop(); |
||
| 9598 | } |
||
| 9599 | |||
| 9600 | while ( actualVerArray.length < 4) { |
||
| 9601 | actualVerArray.push(0); |
||
| 9602 | } |
||
| 9603 | |||
| 9604 | reqVerArray = version.split("."); |
||
| 9605 | |||
| 9606 | while (reqVerArray.length > 4) { |
||
| 9607 | reqVerArray.pop(); |
||
| 9608 | } |
||
| 9609 | |||
| 9610 | do { |
||
| 9611 | requiredVersionPart = parseInt(reqVerArray[index], 10); |
||
| 9612 | actualVersionPart = parseInt(actualVerArray[index], 10); |
||
| 9613 | index++; |
||
| 9614 | } while (index < reqVerArray.length && requiredVersionPart === actualVersionPart); |
||
| 9615 | |||
| 9616 | if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) { |
||
| 9617 | isVersionSupported = true; |
||
| 9618 | } |
||
| 9619 | } |
||
| 9620 | } |
||
| 9621 | } catch (e2) { |
||
| 9622 | isVersionSupported = false; |
||
| 9623 | } |
||
| 9624 | |||
| 9625 | return isVersionSupported; |
||
| 9626 | } |
||
| 9627 | |||
| 9628 | /** |
||
| 9629 | Constructor for the Silverlight Runtime |
||
| 9630 | |||
| 9631 | @class SilverlightRuntime |
||
| 9632 | @extends Runtime |
||
| 9633 | */ |
||
| 9634 | function SilverlightRuntime(options) { |
||
| 9635 | var I = this, initTimer; |
||
| 9636 | |||
| 9637 | options = Basic.extend({ xap_url: Env.xap_url }, options); |
||
| 9638 | |||
| 9639 | Runtime.call(this, options, type, { |
||
| 9640 | access_binary: Runtime.capTrue, |
||
| 9641 | access_image_binary: Runtime.capTrue, |
||
| 9642 | display_media: Runtime.capTrue, |
||
| 9643 | do_cors: Runtime.capTrue, |
||
| 9644 | drag_and_drop: false, |
||
| 9645 | report_upload_progress: Runtime.capTrue, |
||
| 9646 | resize_image: Runtime.capTrue, |
||
| 9647 | return_response_headers: function(value) { |
||
| 9648 | return value && I.mode === 'client'; |
||
| 9649 | }, |
||
| 9650 | return_response_type: function(responseType) { |
||
| 9651 | if (responseType !== 'json') { |
||
| 9652 | return true; |
||
| 9653 | } else { |
||
| 9654 | return !!window.JSON; |
||
| 9655 | } |
||
| 9656 | }, |
||
| 9657 | return_status_code: function(code) { |
||
| 9658 | return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]); |
||
| 9659 | }, |
||
| 9660 | select_file: Runtime.capTrue, |
||
| 9661 | select_multiple: Runtime.capTrue, |
||
| 9662 | send_binary_string: Runtime.capTrue, |
||
| 9663 | send_browser_cookies: function(value) { |
||
| 9664 | return value && I.mode === 'browser'; |
||
| 9665 | }, |
||
| 9666 | send_custom_headers: function(value) { |
||
| 9667 | return value && I.mode === 'client'; |
||
| 9668 | }, |
||
| 9669 | send_multipart: Runtime.capTrue, |
||
| 9670 | slice_blob: Runtime.capTrue, |
||
| 9671 | stream_upload: true, |
||
| 9672 | summon_file_dialog: false, |
||
| 9673 | upload_filesize: Runtime.capTrue, |
||
| 9674 | use_http_method: function(methods) { |
||
| 9675 | return I.mode === 'client' || !Basic.arrayDiff(methods, ['GET', 'POST']); |
||
| 9676 | } |
||
| 9677 | }, { |
||
| 9678 | // capabilities that require specific mode |
||
| 9679 | return_response_headers: function(value) { |
||
| 9680 | return value ? 'client' : 'browser'; |
||
| 9681 | }, |
||
| 9682 | return_status_code: function(code) { |
||
| 9683 | return Basic.arrayDiff(code, [200, 404]) ? 'client' : ['client', 'browser']; |
||
| 9684 | }, |
||
| 9685 | send_browser_cookies: function(value) { |
||
| 9686 | return value ? 'browser' : 'client'; |
||
| 9687 | }, |
||
| 9688 | send_custom_headers: function(value) { |
||
| 9689 | return value ? 'client' : 'browser'; |
||
| 9690 | }, |
||
| 9691 | use_http_method: function(methods) { |
||
| 9692 | return Basic.arrayDiff(methods, ['GET', 'POST']) ? 'client' : ['client', 'browser']; |
||
| 9693 | } |
||
| 9694 | }); |
||
| 9695 | |||
| 9696 | |||
| 9697 | // minimal requirement |
||
| 9698 | if (!isInstalled('2.0.31005.0') || Env.browser === 'Opera') { |
||
| 9699 | this.mode = false; |
||
| 9700 | } |
||
| 9701 | |||
| 9702 | |||
| 9703 | Basic.extend(this, { |
||
| 9704 | getShim: function() { |
||
| 9705 | return Dom.get(this.uid).content.Moxie; |
||
| 9706 | }, |
||
| 9707 | |||
| 9708 | shimExec: function(component, action) { |
||
| 9709 | var args = [].slice.call(arguments, 2); |
||
| 9710 | return I.getShim().exec(this.uid, component, action, args); |
||
| 9711 | }, |
||
| 9712 | |||
| 9713 | init : function() { |
||
| 9714 | var container; |
||
| 9715 | |||
| 9716 | container = this.getShimContainer(); |
||
| 9717 | |||
| 9718 | container.innerHTML = '<object id="' + this.uid + '" data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%" style="outline:none;">' + |
||
| 9719 | '<param name="source" value="' + options.xap_url + '"/>' + |
||
| 9720 | '<param name="background" value="Transparent"/>' + |
||
| 9721 | '<param name="windowless" value="true"/>' + |
||
| 9722 | '<param name="enablehtmlaccess" value="true"/>' + |
||
| 9723 | '<param name="initParams" value="uid=' + this.uid + ',target=' + Env.global_event_dispatcher + '"/>' + |
||
| 9724 | '</object>'; |
||
| 9725 | |||
| 9726 | // Init is dispatched by the shim |
||
| 9727 | initTimer = setTimeout(function() { |
||
| 9728 | if (I && !I.initialized) { // runtime might be already destroyed by this moment |
||
| 9729 | I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR)); |
||
| 9730 | } |
||
| 9731 | }, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac) |
||
| 9732 | }, |
||
| 9733 | |||
| 9734 | destroy: (function(destroy) { // extend default destroy method |
||
| 9735 | return function() { |
||
| 9736 | destroy.call(I); |
||
| 9737 | clearTimeout(initTimer); // initialization check might be still onwait |
||
| 9738 | options = initTimer = destroy = I = null; |
||
| 9739 | }; |
||
| 9740 | }(this.destroy)) |
||
| 9741 | |||
| 9742 | }, extensions); |
||
| 9743 | } |
||
| 9744 | |||
| 9745 | Runtime.addConstructor(type, SilverlightRuntime); |
||
| 9746 | |||
| 9747 | return extensions; |
||
| 9748 | }); |
||
| 9749 | |||
| 9750 | // Included from: src/javascript/runtime/silverlight/file/Blob.js |
||
| 9751 | |||
| 9752 | /** |
||
| 9753 | * Blob.js |
||
| 9754 | * |
||
| 9755 | * Copyright 2013, Moxiecode Systems AB |
||
| 9756 | * Released under GPL License. |
||
| 9757 | * |
||
| 9758 | * License: http://www.plupload.com/license |
||
| 9759 | * Contributing: http://www.plupload.com/contributing |
||
| 9760 | */ |
||
| 9761 | |||
| 9762 | /** |
||
| 9763 | @class moxie/runtime/silverlight/file/Blob |
||
| 9764 | @private |
||
| 9765 | */ |
||
| 9766 | define("moxie/runtime/silverlight/file/Blob", [ |
||
| 9767 | "moxie/runtime/silverlight/Runtime", |
||
| 9768 | "moxie/core/utils/Basic", |
||
| 9769 | "moxie/runtime/flash/file/Blob" |
||
| 9770 | ], function(extensions, Basic, Blob) { |
||
| 9771 | return (extensions.Blob = Basic.extend({}, Blob)); |
||
| 9772 | }); |
||
| 9773 | |||
| 9774 | // Included from: src/javascript/runtime/silverlight/file/FileInput.js |
||
| 9775 | |||
| 9776 | /** |
||
| 9777 | * FileInput.js |
||
| 9778 | * |
||
| 9779 | * Copyright 2013, Moxiecode Systems AB |
||
| 9780 | * Released under GPL License. |
||
| 9781 | * |
||
| 9782 | * License: http://www.plupload.com/license |
||
| 9783 | * Contributing: http://www.plupload.com/contributing |
||
| 9784 | */ |
||
| 9785 | |||
| 9786 | /** |
||
| 9787 | @class moxie/runtime/silverlight/file/FileInput |
||
| 9788 | @private |
||
| 9789 | */ |
||
| 9790 | define("moxie/runtime/silverlight/file/FileInput", [ |
||
| 9791 | "moxie/runtime/silverlight/Runtime" |
||
| 9792 | ], function(extensions) { |
||
| 9793 | |||
| 9794 | var FileInput = { |
||
| 9795 | init: function(options) { |
||
| 9796 | |||
| 9797 | function toFilters(accept) { |
||
| 9798 | var filter = ''; |
||
| 9799 | for (var i = 0; i < accept.length; i++) { |
||
| 9800 | filter += (filter !== '' ? '|' : '') + accept[i].title + " | *." + accept[i].extensions.replace(/,/g, ';*.'); |
||
| 9801 | } |
||
| 9802 | return filter; |
||
| 9803 | } |
||
| 9804 | |||
| 9805 | this.getRuntime().shimExec.call(this, 'FileInput', 'init', toFilters(options.accept), options.name, options.multiple); |
||
| 9806 | this.trigger('ready'); |
||
| 9807 | } |
||
| 9808 | }; |
||
| 9809 | |||
| 9810 | return (extensions.FileInput = FileInput); |
||
| 9811 | }); |
||
| 9812 | |||
| 9813 | // Included from: src/javascript/runtime/silverlight/file/FileDrop.js |
||
| 9814 | |||
| 9815 | /** |
||
| 9816 | * FileDrop.js |
||
| 9817 | * |
||
| 9818 | * Copyright 2013, Moxiecode Systems AB |
||
| 9819 | * Released under GPL License. |
||
| 9820 | * |
||
| 9821 | * License: http://www.plupload.com/license |
||
| 9822 | * Contributing: http://www.plupload.com/contributing |
||
| 9823 | */ |
||
| 9824 | |||
| 9825 | /** |
||
| 9826 | @class moxie/runtime/silverlight/file/FileDrop |
||
| 9827 | @private |
||
| 9828 | */ |
||
| 9829 | define("moxie/runtime/silverlight/file/FileDrop", [ |
||
| 9830 | "moxie/runtime/silverlight/Runtime", |
||
| 9831 | "moxie/core/utils/Dom", |
||
| 9832 | "moxie/core/utils/Events" |
||
| 9833 | ], function(extensions, Dom, Events) { |
||
| 9834 | |||
| 9835 | // not exactly useful, since works only in safari (...crickets...) |
||
| 9836 | var FileDrop = { |
||
| 9837 | init: function() { |
||
| 9838 | var comp = this, self = comp.getRuntime(), dropZone; |
||
| 9839 | |||
| 9840 | dropZone = self.getShimContainer(); |
||
| 9841 | |||
| 9842 | Events.addEvent(dropZone, 'dragover', function(e) { |
||
| 9843 | e.preventDefault(); |
||
| 9844 | e.stopPropagation(); |
||
| 9845 | e.dataTransfer.dropEffect = 'copy'; |
||
| 9846 | }, comp.uid); |
||
| 9847 | |||
| 9848 | Events.addEvent(dropZone, 'dragenter', function(e) { |
||
| 9849 | e.preventDefault(); |
||
| 9850 | var flag = Dom.get(self.uid).dragEnter(e); |
||
| 9851 | // If handled, then stop propagation of event in DOM |
||
| 9852 | if (flag) { |
||
| 9853 | e.stopPropagation(); |
||
| 9854 | } |
||
| 9855 | }, comp.uid); |
||
| 9856 | |||
| 9857 | Events.addEvent(dropZone, 'drop', function(e) { |
||
| 9858 | e.preventDefault(); |
||
| 9859 | var flag = Dom.get(self.uid).dragDrop(e); |
||
| 9860 | // If handled, then stop propagation of event in DOM |
||
| 9861 | if (flag) { |
||
| 9862 | e.stopPropagation(); |
||
| 9863 | } |
||
| 9864 | }, comp.uid); |
||
| 9865 | |||
| 9866 | return self.shimExec.call(this, 'FileDrop', 'init'); |
||
| 9867 | } |
||
| 9868 | }; |
||
| 9869 | |||
| 9870 | return (extensions.FileDrop = FileDrop); |
||
| 9871 | }); |
||
| 9872 | |||
| 9873 | // Included from: src/javascript/runtime/silverlight/file/FileReader.js |
||
| 9874 | |||
| 9875 | /** |
||
| 9876 | * FileReader.js |
||
| 9877 | * |
||
| 9878 | * Copyright 2013, Moxiecode Systems AB |
||
| 9879 | * Released under GPL License. |
||
| 9880 | * |
||
| 9881 | * License: http://www.plupload.com/license |
||
| 9882 | * Contributing: http://www.plupload.com/contributing |
||
| 9883 | */ |
||
| 9884 | |||
| 9885 | /** |
||
| 9886 | @class moxie/runtime/silverlight/file/FileReader |
||
| 9887 | @private |
||
| 9888 | */ |
||
| 9889 | define("moxie/runtime/silverlight/file/FileReader", [ |
||
| 9890 | "moxie/runtime/silverlight/Runtime", |
||
| 9891 | "moxie/core/utils/Basic", |
||
| 9892 | "moxie/runtime/flash/file/FileReader" |
||
| 9893 | ], function(extensions, Basic, FileReader) { |
||
| 9894 | return (extensions.FileReader = Basic.extend({}, FileReader)); |
||
| 9895 | }); |
||
| 9896 | |||
| 9897 | // Included from: src/javascript/runtime/silverlight/file/FileReaderSync.js |
||
| 9898 | |||
| 9899 | /** |
||
| 9900 | * FileReaderSync.js |
||
| 9901 | * |
||
| 9902 | * Copyright 2013, Moxiecode Systems AB |
||
| 9903 | * Released under GPL License. |
||
| 9904 | * |
||
| 9905 | * License: http://www.plupload.com/license |
||
| 9906 | * Contributing: http://www.plupload.com/contributing |
||
| 9907 | */ |
||
| 9908 | |||
| 9909 | /** |
||
| 9910 | @class moxie/runtime/silverlight/file/FileReaderSync |
||
| 9911 | @private |
||
| 9912 | */ |
||
| 9913 | define("moxie/runtime/silverlight/file/FileReaderSync", [ |
||
| 9914 | "moxie/runtime/silverlight/Runtime", |
||
| 9915 | "moxie/core/utils/Basic", |
||
| 9916 | "moxie/runtime/flash/file/FileReaderSync" |
||
| 9917 | ], function(extensions, Basic, FileReaderSync) { |
||
| 9918 | return (extensions.FileReaderSync = Basic.extend({}, FileReaderSync)); |
||
| 9919 | }); |
||
| 9920 | |||
| 9921 | // Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js |
||
| 9922 | |||
| 9923 | /** |
||
| 9924 | * XMLHttpRequest.js |
||
| 9925 | * |
||
| 9926 | * Copyright 2013, Moxiecode Systems AB |
||
| 9927 | * Released under GPL License. |
||
| 9928 | * |
||
| 9929 | * License: http://www.plupload.com/license |
||
| 9930 | * Contributing: http://www.plupload.com/contributing |
||
| 9931 | */ |
||
| 9932 | |||
| 9933 | /** |
||
| 9934 | @class moxie/runtime/silverlight/xhr/XMLHttpRequest |
||
| 9935 | @private |
||
| 9936 | */ |
||
| 9937 | define("moxie/runtime/silverlight/xhr/XMLHttpRequest", [ |
||
| 9938 | "moxie/runtime/silverlight/Runtime", |
||
| 9939 | "moxie/core/utils/Basic", |
||
| 9940 | "moxie/runtime/flash/xhr/XMLHttpRequest" |
||
| 9941 | ], function(extensions, Basic, XMLHttpRequest) { |
||
| 9942 | return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest)); |
||
| 9943 | }); |
||
| 9944 | |||
| 9945 | // Included from: src/javascript/runtime/silverlight/runtime/Transporter.js |
||
| 9946 | |||
| 9947 | /** |
||
| 9948 | * Transporter.js |
||
| 9949 | * |
||
| 9950 | * Copyright 2013, Moxiecode Systems AB |
||
| 9951 | * Released under GPL License. |
||
| 9952 | * |
||
| 9953 | * License: http://www.plupload.com/license |
||
| 9954 | * Contributing: http://www.plupload.com/contributing |
||
| 9955 | */ |
||
| 9956 | |||
| 9957 | /** |
||
| 9958 | @class moxie/runtime/silverlight/runtime/Transporter |
||
| 9959 | @private |
||
| 9960 | */ |
||
| 9961 | define("moxie/runtime/silverlight/runtime/Transporter", [ |
||
| 9962 | "moxie/runtime/silverlight/Runtime", |
||
| 9963 | "moxie/core/utils/Basic", |
||
| 9964 | "moxie/runtime/flash/runtime/Transporter" |
||
| 9965 | ], function(extensions, Basic, Transporter) { |
||
| 9966 | return (extensions.Transporter = Basic.extend({}, Transporter)); |
||
| 9967 | }); |
||
| 9968 | |||
| 9969 | // Included from: src/javascript/runtime/silverlight/image/Image.js |
||
| 9970 | |||
| 9971 | /** |
||
| 9972 | * Image.js |
||
| 9973 | * |
||
| 9974 | * Copyright 2013, Moxiecode Systems AB |
||
| 9975 | * Released under GPL License. |
||
| 9976 | * |
||
| 9977 | * License: http://www.plupload.com/license |
||
| 9978 | * Contributing: http://www.plupload.com/contributing |
||
| 9979 | */ |
||
| 9980 | |||
| 9981 | /** |
||
| 9982 | @class moxie/runtime/silverlight/image/Image |
||
| 9983 | @private |
||
| 9984 | */ |
||
| 9985 | define("moxie/runtime/silverlight/image/Image", [ |
||
| 9986 | "moxie/runtime/silverlight/Runtime", |
||
| 9987 | "moxie/core/utils/Basic", |
||
| 9988 | "moxie/runtime/flash/image/Image" |
||
| 9989 | ], function(extensions, Basic, Image) { |
||
| 9990 | return (extensions.Image = Basic.extend({}, Image, { |
||
| 9991 | |||
| 9992 | getInfo: function() { |
||
| 9993 | var self = this.getRuntime() |
||
| 9994 | , grps = ['tiff', 'exif', 'gps'] |
||
| 9995 | , info = { meta: {} } |
||
| 9996 | , rawInfo = self.shimExec.call(this, 'Image', 'getInfo') |
||
| 9997 | ; |
||
| 9998 | |||
| 9999 | if (rawInfo.meta) { |
||
| 10000 | Basic.each(grps, function(grp) { |
||
| 10001 | var meta = rawInfo.meta[grp] |
||
| 10002 | , tag |
||
| 10003 | , i |
||
| 10004 | , length |
||
| 10005 | , value |
||
| 10006 | ; |
||
| 10007 | if (meta && meta.keys) { |
||
| 10008 | info.meta[grp] = {}; |
||
| 10009 | for (i = 0, length = meta.keys.length; i < length; i++) { |
||
| 10010 | tag = meta.keys[i]; |
||
| 10011 | value = meta[tag]; |
||
| 10012 | if (value) { |
||
| 10013 | // convert numbers |
||
| 10014 | if (/^(\d|[1-9]\d+)$/.test(value)) { // integer (make sure doesn't start with zero) |
||
| 10015 | value = parseInt(value, 10); |
||
| 10016 | } else if (/^\d*\.\d+$/.test(value)) { // double |
||
| 10017 | value = parseFloat(value); |
||
| 10018 | } |
||
| 10019 | info.meta[grp][tag] = value; |
||
| 10020 | } |
||
| 10021 | } |
||
| 10022 | } |
||
| 10023 | }); |
||
| 10024 | } |
||
| 10025 | |||
| 10026 | info.width = parseInt(rawInfo.width, 10); |
||
| 10027 | info.height = parseInt(rawInfo.height, 10); |
||
| 10028 | info.size = parseInt(rawInfo.size, 10); |
||
| 10029 | info.type = rawInfo.type; |
||
| 10030 | info.name = rawInfo.name; |
||
| 10031 | |||
| 10032 | return info; |
||
| 10033 | } |
||
| 10034 | })); |
||
| 10035 | }); |
||
| 10036 | |||
| 10037 | // Included from: src/javascript/runtime/html4/Runtime.js |
||
| 10038 | |||
| 10039 | /** |
||
| 10040 | * Runtime.js |
||
| 10041 | * |
||
| 10042 | * Copyright 2013, Moxiecode Systems AB |
||
| 10043 | * Released under GPL License. |
||
| 10044 | * |
||
| 10045 | * License: http://www.plupload.com/license |
||
| 10046 | * Contributing: http://www.plupload.com/contributing |
||
| 10047 | */ |
||
| 10048 | |||
| 10049 | /*global File:true */ |
||
| 10050 | |||
| 10051 | /** |
||
| 10052 | Defines constructor for HTML4 runtime. |
||
| 10053 | |||
| 10054 | @class moxie/runtime/html4/Runtime |
||
| 10055 | @private |
||
| 10056 | */ |
||
| 10057 | define("moxie/runtime/html4/Runtime", [ |
||
| 10058 | "moxie/core/utils/Basic", |
||
| 10059 | "moxie/core/Exceptions", |
||
| 10060 | "moxie/runtime/Runtime", |
||
| 10061 | "moxie/core/utils/Env" |
||
| 10062 | ], function(Basic, x, Runtime, Env) { |
||
| 10063 | |||
| 10064 | var type = 'html4', extensions = {}; |
||
| 10065 | |||
| 10066 | function Html4Runtime(options) { |
||
| 10067 | var I = this |
||
| 10068 | , Test = Runtime.capTest |
||
| 10069 | , True = Runtime.capTrue |
||
| 10070 | ; |
||
| 10071 | |||
| 10072 | Runtime.call(this, options, type, { |
||
| 10073 | access_binary: Test(window.FileReader || window.File && File.getAsDataURL), |
||
| 10074 | access_image_binary: false, |
||
| 10075 | display_media: Test(extensions.Image && (Env.can('create_canvas') || Env.can('use_data_uri_over32kb'))), |
||
| 10076 | do_cors: false, |
||
| 10077 | drag_and_drop: false, |
||
| 10078 | filter_by_extension: Test(function() { // if you know how to feature-detect this, please suggest |
||
| 10079 | return (Env.browser === 'Chrome' && Env.version >= 28) || (Env.browser === 'IE' && Env.version >= 10); |
||
| 10080 | }()), |
||
| 10081 | resize_image: function() { |
||
| 10082 | return extensions.Image && I.can('access_binary') && Env.can('create_canvas'); |
||
| 10083 | }, |
||
| 10084 | report_upload_progress: false, |
||
| 10085 | return_response_headers: false, |
||
| 10086 | return_response_type: function(responseType) { |
||
| 10087 | if (responseType === 'json' && !!window.JSON) { |
||
| 10088 | return true; |
||
| 10089 | } |
||
| 10090 | return !!~Basic.inArray(responseType, ['text', 'document', '']); |
||
| 10091 | }, |
||
| 10092 | return_status_code: function(code) { |
||
| 10093 | return !Basic.arrayDiff(code, [200, 404]); |
||
| 10094 | }, |
||
| 10095 | select_file: function() { |
||
| 10096 | return Env.can('use_fileinput'); |
||
| 10097 | }, |
||
| 10098 | select_multiple: false, |
||
| 10099 | send_binary_string: false, |
||
| 10100 | send_custom_headers: false, |
||
| 10101 | send_multipart: true, |
||
| 10102 | slice_blob: false, |
||
| 10103 | stream_upload: function() { |
||
| 10104 | return I.can('select_file'); |
||
| 10105 | }, |
||
| 10106 | summon_file_dialog: Test(function() { // yeah... some dirty sniffing here... |
||
| 10107 | return (Env.browser === 'Firefox' && Env.version >= 4) || |
||
| 10108 | (Env.browser === 'Opera' && Env.version >= 12) || |
||
| 10109 | !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']); |
||
| 10110 | }()), |
||
| 10111 | upload_filesize: True, |
||
| 10112 | use_http_method: function(methods) { |
||
| 10113 | return !Basic.arrayDiff(methods, ['GET', 'POST']); |
||
| 10114 | } |
||
| 10115 | }); |
||
| 10116 | |||
| 10117 | |||
| 10118 | Basic.extend(this, { |
||
| 10119 | init : function() { |
||
| 10120 | this.trigger("Init"); |
||
| 10121 | }, |
||
| 10122 | |||
| 10123 | destroy: (function(destroy) { // extend default destroy method |
||
| 10124 | return function() { |
||
| 10125 | destroy.call(I); |
||
| 10126 | destroy = I = null; |
||
| 10127 | }; |
||
| 10128 | }(this.destroy)) |
||
| 10129 | }); |
||
| 10130 | |||
| 10131 | Basic.extend(this.getShim(), extensions); |
||
| 10132 | } |
||
| 10133 | |||
| 10134 | Runtime.addConstructor(type, Html4Runtime); |
||
| 10135 | |||
| 10136 | return extensions; |
||
| 10137 | }); |
||
| 10138 | |||
| 10139 | // Included from: src/javascript/runtime/html4/file/FileInput.js |
||
| 10140 | |||
| 10141 | /** |
||
| 10142 | * FileInput.js |
||
| 10143 | * |
||
| 10144 | * Copyright 2013, Moxiecode Systems AB |
||
| 10145 | * Released under GPL License. |
||
| 10146 | * |
||
| 10147 | * License: http://www.plupload.com/license |
||
| 10148 | * Contributing: http://www.plupload.com/contributing |
||
| 10149 | */ |
||
| 10150 | |||
| 10151 | /** |
||
| 10152 | @class moxie/runtime/html4/file/FileInput |
||
| 10153 | @private |
||
| 10154 | */ |
||
| 10155 | define("moxie/runtime/html4/file/FileInput", [ |
||
| 10156 | "moxie/runtime/html4/Runtime", |
||
| 10157 | "moxie/core/utils/Basic", |
||
| 10158 | "moxie/core/utils/Dom", |
||
| 10159 | "moxie/core/utils/Events", |
||
| 10160 | "moxie/core/utils/Mime", |
||
| 10161 | "moxie/core/utils/Env" |
||
| 10162 | ], function(extensions, Basic, Dom, Events, Mime, Env) { |
||
| 10163 | |||
| 10164 | function FileInput() { |
||
| 10165 | var _uid, _files = [], _mimes = [], _options; |
||
| 10166 | |||
| 10167 | function addInput() { |
||
| 10168 | var comp = this, I = comp.getRuntime(), shimContainer, browseButton, currForm, form, input, uid; |
||
| 10169 | |||
| 10170 | uid = Basic.guid('uid_'); |
||
| 10171 | |||
| 10172 | shimContainer = I.getShimContainer(); // we get new ref everytime to avoid memory leaks in IE |
||
| 10173 | |||
| 10174 | if (_uid) { // move previous form out of the view |
||
| 10175 | currForm = Dom.get(_uid + '_form'); |
||
| 10176 | if (currForm) { |
||
| 10177 | Basic.extend(currForm.style, { top: '100%' }); |
||
| 10178 | } |
||
| 10179 | } |
||
| 10180 | |||
| 10181 | // build form in DOM, since innerHTML version not able to submit file for some reason |
||
| 10182 | form = document.createElement('form'); |
||
| 10183 | form.setAttribute('id', uid + '_form'); |
||
| 10184 | form.setAttribute('method', 'post'); |
||
| 10185 | form.setAttribute('enctype', 'multipart/form-data'); |
||
| 10186 | form.setAttribute('encoding', 'multipart/form-data'); |
||
| 10187 | |||
| 10188 | Basic.extend(form.style, { |
||
| 10189 | overflow: 'hidden', |
||
| 10190 | position: 'absolute', |
||
| 10191 | top: 0, |
||
| 10192 | left: 0, |
||
| 10193 | width: '100%', |
||
| 10194 | height: '100%' |
||
| 10195 | }); |
||
| 10196 | |||
| 10197 | input = document.createElement('input'); |
||
| 10198 | input.setAttribute('id', uid); |
||
| 10199 | input.setAttribute('type', 'file'); |
||
| 10200 | input.setAttribute('name', _options.name || 'Filedata'); |
||
| 10201 | input.setAttribute('accept', _mimes.join(',')); |
||
| 10202 | |||
| 10203 | Basic.extend(input.style, { |
||
| 10204 | fontSize: '999px', |
||
| 10205 | opacity: 0 |
||
| 10206 | }); |
||
| 10207 | |||
| 10208 | form.appendChild(input); |
||
| 10209 | shimContainer.appendChild(form); |
||
| 10210 | |||
| 10211 | // prepare file input to be placed underneath the browse_button element |
||
| 10212 | Basic.extend(input.style, { |
||
| 10213 | position: 'absolute', |
||
| 10214 | top: 0, |
||
| 10215 | left: 0, |
||
| 10216 | width: '100%', |
||
| 10217 | height: '100%' |
||
| 10218 | }); |
||
| 10219 | |||
| 10220 | if (Env.browser === 'IE' && Env.version < 10) { |
||
| 10221 | Basic.extend(input.style, { |
||
| 10222 | filter : "progid:DXImageTransform.Microsoft.Alpha(opacity=0)" |
||
| 10223 | }); |
||
| 10224 | } |
||
| 10225 | |||
| 10226 | input.onchange = function() { // there should be only one handler for this |
||
| 10227 | var file; |
||
| 10228 | |||
| 10229 | if (!this.value) { |
||
| 10230 | return; |
||
| 10231 | } |
||
| 10232 | |||
| 10233 | if (this.files) { |
||
| 10234 | file = this.files[0]; |
||
| 10235 | } else { |
||
| 10236 | file = { |
||
| 10237 | name: this.value |
||
| 10238 | }; |
||
| 10239 | } |
||
| 10240 | |||
| 10241 | _files = [file]; |
||
| 10242 | |||
| 10243 | this.onchange = function() {}; // clear event handler |
||
| 10244 | addInput.call(comp); |
||
| 10245 | |||
| 10246 | // after file is initialized as o.File, we need to update form and input ids |
||
| 10247 | comp.bind('change', function onChange() { |
||
| 10248 | var input = Dom.get(uid), form = Dom.get(uid + '_form'), file; |
||
| 10249 | |||
| 10250 | comp.unbind('change', onChange); |
||
| 10251 | |||
| 10252 | if (comp.files.length && input && form) { |
||
| 10253 | file = comp.files[0]; |
||
| 10254 | |||
| 10255 | input.setAttribute('id', file.uid); |
||
| 10256 | form.setAttribute('id', file.uid + '_form'); |
||
| 10257 | |||
| 10258 | // set upload target |
||
| 10259 | form.setAttribute('target', file.uid + '_iframe'); |
||
| 10260 | } |
||
| 10261 | input = form = null; |
||
| 10262 | }, 998); |
||
| 10263 | |||
| 10264 | input = form = null; |
||
| 10265 | comp.trigger('change'); |
||
| 10266 | }; |
||
| 10267 | |||
| 10268 | |||
| 10269 | // route click event to the input |
||
| 10270 | if (I.can('summon_file_dialog')) { |
||
| 10271 | browseButton = Dom.get(_options.browse_button); |
||
| 10272 | Events.removeEvent(browseButton, 'click', comp.uid); |
||
| 10273 | Events.addEvent(browseButton, 'click', function(e) { |
||
| 10274 | if (input && !input.disabled) { // for some reason FF (up to 8.0.1 so far) lets to click disabled input[type=file] |
||
| 10275 | input.click(); |
||
| 10276 | } |
||
| 10277 | e.preventDefault(); |
||
| 10278 | }, comp.uid); |
||
| 10279 | } |
||
| 10280 | |||
| 10281 | _uid = uid; |
||
| 10282 | |||
| 10283 | shimContainer = currForm = browseButton = null; |
||
| 10284 | } |
||
| 10285 | |||
| 10286 | Basic.extend(this, { |
||
| 10287 | init: function(options) { |
||
| 10288 | var comp = this, I = comp.getRuntime(), shimContainer; |
||
| 10289 | |||
| 10290 | // figure out accept string |
||
| 10291 | _options = options; |
||
| 10292 | _mimes = options.accept.mimes || Mime.extList2mimes(options.accept, I.can('filter_by_extension')); |
||
| 10293 | |||
| 10294 | shimContainer = I.getShimContainer(); |
||
| 10295 | |||
| 10296 | (function() { |
||
| 10297 | var browseButton, zIndex, top; |
||
| 10298 | |||
| 10299 | browseButton = Dom.get(options.browse_button); |
||
| 10300 | |||
| 10301 | // Route click event to the input[type=file] element for browsers that support such behavior |
||
| 10302 | if (I.can('summon_file_dialog')) { |
||
| 10303 | if (Dom.getStyle(browseButton, 'position') === 'static') { |
||
| 10304 | browseButton.style.position = 'relative'; |
||
| 10305 | } |
||
| 10306 | |||
| 10307 | zIndex = parseInt(Dom.getStyle(browseButton, 'z-index'), 10) || 1; |
||
| 10308 | |||
| 10309 | browseButton.style.zIndex = zIndex; |
||
| 10310 | shimContainer.style.zIndex = zIndex - 1; |
||
| 10311 | } |
||
| 10312 | |||
| 10313 | /* Since we have to place input[type=file] on top of the browse_button for some browsers, |
||
| 10314 | browse_button loses interactivity, so we restore it here */ |
||
| 10315 | top = I.can('summon_file_dialog') ? browseButton : shimContainer; |
||
| 10316 | |||
| 10317 | Events.addEvent(top, 'mouseover', function() { |
||
| 10318 | comp.trigger('mouseenter'); |
||
| 10319 | }, comp.uid); |
||
| 10320 | |||
| 10321 | Events.addEvent(top, 'mouseout', function() { |
||
| 10322 | comp.trigger('mouseleave'); |
||
| 10323 | }, comp.uid); |
||
| 10324 | |||
| 10325 | Events.addEvent(top, 'mousedown', function() { |
||
| 10326 | comp.trigger('mousedown'); |
||
| 10327 | }, comp.uid); |
||
| 10328 | |||
| 10329 | Events.addEvent(Dom.get(options.container), 'mouseup', function() { |
||
| 10330 | comp.trigger('mouseup'); |
||
| 10331 | }, comp.uid); |
||
| 10332 | |||
| 10333 | browseButton = null; |
||
| 10334 | }()); |
||
| 10335 | |||
| 10336 | addInput.call(this); |
||
| 10337 | |||
| 10338 | shimContainer = null; |
||
| 10339 | |||
| 10340 | // trigger ready event asynchronously |
||
| 10341 | comp.trigger({ |
||
| 10342 | type: 'ready', |
||
| 10343 | async: true |
||
| 10344 | }); |
||
| 10345 | }, |
||
| 10346 | |||
| 10347 | getFiles: function() { |
||
| 10348 | return _files; |
||
| 10349 | }, |
||
| 10350 | |||
| 10351 | disable: function(state) { |
||
| 10352 | var input; |
||
| 10353 | |||
| 10354 | if ((input = Dom.get(_uid))) { |
||
| 10355 | input.disabled = !!state; |
||
| 10356 | } |
||
| 10357 | }, |
||
| 10358 | |||
| 10359 | destroy: function() { |
||
| 10360 | var I = this.getRuntime() |
||
| 10361 | , shim = I.getShim() |
||
| 10362 | , shimContainer = I.getShimContainer() |
||
| 10363 | ; |
||
| 10364 | |||
| 10365 | Events.removeAllEvents(shimContainer, this.uid); |
||
| 10366 | Events.removeAllEvents(_options && Dom.get(_options.container), this.uid); |
||
| 10367 | Events.removeAllEvents(_options && Dom.get(_options.browse_button), this.uid); |
||
| 10368 | |||
| 10369 | if (shimContainer) { |
||
| 10370 | shimContainer.innerHTML = ''; |
||
| 10371 | } |
||
| 10372 | |||
| 10373 | shim.removeInstance(this.uid); |
||
| 10374 | |||
| 10375 | _uid = _files = _mimes = _options = shimContainer = shim = null; |
||
| 10376 | } |
||
| 10377 | }); |
||
| 10378 | } |
||
| 10379 | |||
| 10380 | return (extensions.FileInput = FileInput); |
||
| 10381 | }); |
||
| 10382 | |||
| 10383 | // Included from: src/javascript/runtime/html4/file/FileReader.js |
||
| 10384 | |||
| 10385 | /** |
||
| 10386 | * FileReader.js |
||
| 10387 | * |
||
| 10388 | * Copyright 2013, Moxiecode Systems AB |
||
| 10389 | * Released under GPL License. |
||
| 10390 | * |
||
| 10391 | * License: http://www.plupload.com/license |
||
| 10392 | * Contributing: http://www.plupload.com/contributing |
||
| 10393 | */ |
||
| 10394 | |||
| 10395 | /** |
||
| 10396 | @class moxie/runtime/html4/file/FileReader |
||
| 10397 | @private |
||
| 10398 | */ |
||
| 10399 | define("moxie/runtime/html4/file/FileReader", [ |
||
| 10400 | "moxie/runtime/html4/Runtime", |
||
| 10401 | "moxie/runtime/html5/file/FileReader" |
||
| 10402 | ], function(extensions, FileReader) { |
||
| 10403 | return (extensions.FileReader = FileReader); |
||
| 10404 | }); |
||
| 10405 | |||
| 10406 | // Included from: src/javascript/runtime/html4/xhr/XMLHttpRequest.js |
||
| 10407 | |||
| 10408 | /** |
||
| 10409 | * XMLHttpRequest.js |
||
| 10410 | * |
||
| 10411 | * Copyright 2013, Moxiecode Systems AB |
||
| 10412 | * Released under GPL License. |
||
| 10413 | * |
||
| 10414 | * License: http://www.plupload.com/license |
||
| 10415 | * Contributing: http://www.plupload.com/contributing |
||
| 10416 | */ |
||
| 10417 | |||
| 10418 | /** |
||
| 10419 | @class moxie/runtime/html4/xhr/XMLHttpRequest |
||
| 10420 | @private |
||
| 10421 | */ |
||
| 10422 | define("moxie/runtime/html4/xhr/XMLHttpRequest", [ |
||
| 10423 | "moxie/runtime/html4/Runtime", |
||
| 10424 | "moxie/core/utils/Basic", |
||
| 10425 | "moxie/core/utils/Dom", |
||
| 10426 | "moxie/core/utils/Url", |
||
| 10427 | "moxie/core/Exceptions", |
||
| 10428 | "moxie/core/utils/Events", |
||
| 10429 | "moxie/file/Blob", |
||
| 10430 | "moxie/xhr/FormData" |
||
| 10431 | ], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) { |
||
| 10432 | |||
| 10433 | function XMLHttpRequest() { |
||
| 10434 | var _status, _response, _iframe; |
||
| 10435 | |||
| 10436 | function cleanup(cb) { |
||
| 10437 | var target = this, uid, form, inputs, i, hasFile = false; |
||
| 10438 | |||
| 10439 | if (!_iframe) { |
||
| 10440 | return; |
||
| 10441 | } |
||
| 10442 | |||
| 10443 | uid = _iframe.id.replace(/_iframe$/, ''); |
||
| 10444 | |||
| 10445 | form = Dom.get(uid + '_form'); |
||
| 10446 | if (form) { |
||
| 10447 | inputs = form.getElementsByTagName('input'); |
||
| 10448 | i = inputs.length; |
||
| 10449 | |||
| 10450 | while (i--) { |
||
| 10451 | switch (inputs[i].getAttribute('type')) { |
||
| 10452 | case 'hidden': |
||
| 10453 | inputs[i].parentNode.removeChild(inputs[i]); |
||
| 10454 | break; |
||
| 10455 | case 'file': |
||
| 10456 | hasFile = true; // flag the case for later |
||
| 10457 | break; |
||
| 10458 | } |
||
| 10459 | } |
||
| 10460 | inputs = []; |
||
| 10461 | |||
| 10462 | if (!hasFile) { // we need to keep the form for sake of possible retries |
||
| 10463 | form.parentNode.removeChild(form); |
||
| 10464 | } |
||
| 10465 | form = null; |
||
| 10466 | } |
||
| 10467 | |||
| 10468 | // without timeout, request is marked as canceled (in console) |
||
| 10469 | setTimeout(function() { |
||
| 10470 | Events.removeEvent(_iframe, 'load', target.uid); |
||
| 10471 | if (_iframe.parentNode) { // #382 |
||
| 10472 | _iframe.parentNode.removeChild(_iframe); |
||
| 10473 | } |
||
| 10474 | |||
| 10475 | // check if shim container has any other children, if - not, remove it as well |
||
| 10476 | var shimContainer = target.getRuntime().getShimContainer(); |
||
| 10477 | if (!shimContainer.children.length) { |
||
| 10478 | shimContainer.parentNode.removeChild(shimContainer); |
||
| 10479 | } |
||
| 10480 | |||
| 10481 | shimContainer = _iframe = null; |
||
| 10482 | cb(); |
||
| 10483 | }, 1); |
||
| 10484 | } |
||
| 10485 | |||
| 10486 | Basic.extend(this, { |
||
| 10487 | send: function(meta, data) { |
||
| 10488 | var target = this, I = target.getRuntime(), uid, form, input, blob; |
||
| 10489 | |||
| 10490 | _status = _response = null; |
||
| 10491 | |||
| 10492 | function createIframe() { |
||
| 10493 | var container = I.getShimContainer() || document.body |
||
| 10494 | , temp = document.createElement('div') |
||
| 10495 | ; |
||
| 10496 | |||
| 10497 | // IE 6 won't be able to set the name using setAttribute or iframe.name |
||
| 10498 | temp.innerHTML = '<iframe id="' + uid + '_iframe" name="' + uid + '_iframe" src="javascript:""" style="display:none"></iframe>'; |
||
| 10499 | _iframe = temp.firstChild; |
||
| 10500 | container.appendChild(_iframe); |
||
| 10501 | |||
| 10502 | /* _iframe.onreadystatechange = function() { |
||
| 10503 | console.info(_iframe.readyState); |
||
| 10504 | };*/ |
||
| 10505 | |||
| 10506 | Events.addEvent(_iframe, 'load', function() { // _iframe.onload doesn't work in IE lte 8 |
||
| 10507 | var el; |
||
| 10508 | |||
| 10509 | try { |
||
| 10510 | el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document; |
||
| 10511 | |||
| 10512 | // try to detect some standard error pages |
||
| 10513 | if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error |
||
| 10514 | _status = el.title.replace(/^(\d+).*$/, '$1'); |
||
| 10515 | } else { |
||
| 10516 | _status = 200; |
||
| 10517 | // get result |
||
| 10518 | _response = Basic.trim(el.body.innerHTML); |
||
| 10519 | |||
| 10520 | // we need to fire these at least once |
||
| 10521 | target.trigger({ |
||
| 10522 | type: 'progress', |
||
| 10523 | loaded: _response.length, |
||
| 10524 | total: _response.length |
||
| 10525 | }); |
||
| 10526 | |||
| 10527 | if (blob) { // if we were uploading a file |
||
| 10528 | target.trigger({ |
||
| 10529 | type: 'uploadprogress', |
||
| 10530 | loaded: blob.size || 1025, |
||
| 10531 | total: blob.size || 1025 |
||
| 10532 | }); |
||
| 10533 | } |
||
| 10534 | } |
||
| 10535 | } catch (ex) { |
||
| 10536 | if (Url.hasSameOrigin(meta.url)) { |
||
| 10537 | // if response is sent with error code, iframe in IE gets redirected to res://ieframe.dll/http_x.htm |
||
| 10538 | // which obviously results to cross domain error (wtf?) |
||
| 10539 | _status = 404; |
||
| 10540 | } else { |
||
| 10541 | cleanup.call(target, function() { |
||
| 10542 | target.trigger('error'); |
||
| 10543 | }); |
||
| 10544 | return; |
||
| 10545 | } |
||
| 10546 | } |
||
| 10547 | |||
| 10548 | cleanup.call(target, function() { |
||
| 10549 | target.trigger('load'); |
||
| 10550 | }); |
||
| 10551 | }, target.uid); |
||
| 10552 | } // end createIframe |
||
| 10553 | |||
| 10554 | // prepare data to be sent and convert if required |
||
| 10555 | if (data instanceof FormData && data.hasBlob()) { |
||
| 10556 | blob = data.getBlob(); |
||
| 10557 | uid = blob.uid; |
||
| 10558 | input = Dom.get(uid); |
||
| 10559 | form = Dom.get(uid + '_form'); |
||
| 10560 | if (!form) { |
||
| 10561 | throw new x.DOMException(x.DOMException.NOT_FOUND_ERR); |
||
| 10562 | } |
||
| 10563 | } else { |
||
| 10564 | uid = Basic.guid('uid_'); |
||
| 10565 | |||
| 10566 | form = document.createElement('form'); |
||
| 10567 | form.setAttribute('id', uid + '_form'); |
||
| 10568 | form.setAttribute('method', meta.method); |
||
| 10569 | form.setAttribute('enctype', 'multipart/form-data'); |
||
| 10570 | form.setAttribute('encoding', 'multipart/form-data'); |
||
| 10571 | form.setAttribute('target', uid + '_iframe'); |
||
| 10572 | |||
| 10573 | I.getShimContainer().appendChild(form); |
||
| 10574 | } |
||
| 10575 | |||
| 10576 | if (data instanceof FormData) { |
||
| 10577 | data.each(function(value, name) { |
||
| 10578 | if (value instanceof Blob) { |
||
| 10579 | if (input) { |
||
| 10580 | input.setAttribute('name', name); |
||
| 10581 | } |
||
| 10582 | } else { |
||
| 10583 | var hidden = document.createElement('input'); |
||
| 10584 | |||
| 10585 | Basic.extend(hidden, { |
||
| 10586 | type : 'hidden', |
||
| 10587 | name : name, |
||
| 10588 | value : value |
||
| 10589 | }); |
||
| 10590 | |||
| 10591 | // make sure that input[type="file"], if it's there, comes last |
||
| 10592 | if (input) { |
||
| 10593 | form.insertBefore(hidden, input); |
||
| 10594 | } else { |
||
| 10595 | form.appendChild(hidden); |
||
| 10596 | } |
||
| 10597 | } |
||
| 10598 | }); |
||
| 10599 | } |
||
| 10600 | |||
| 10601 | // set destination url |
||
| 10602 | form.setAttribute("action", meta.url); |
||
| 10603 | |||
| 10604 | createIframe(); |
||
| 10605 | form.submit(); |
||
| 10606 | target.trigger('loadstart'); |
||
| 10607 | }, |
||
| 10608 | |||
| 10609 | getStatus: function() { |
||
| 10610 | return _status; |
||
| 10611 | }, |
||
| 10612 | |||
| 10613 | getResponse: function(responseType) { |
||
| 10614 | if ('json' === responseType) { |
||
| 10615 | // strip off <pre>..</pre> tags that might be enclosing the response |
||
| 10616 | if (Basic.typeOf(_response) === 'string' && !!window.JSON) { |
||
| 10617 | try { |
||
| 10618 | return JSON.parse(_response.replace(/^\s*<pre[^>]*>/, '').replace(/<\/pre>\s*$/, '')); |
||
| 10619 | } catch (ex) { |
||
| 10620 | return null; |
||
| 10621 | } |
||
| 10622 | } |
||
| 10623 | } else if ('document' === responseType) { |
||
| 10624 | |||
| 10625 | } |
||
| 10626 | return _response; |
||
| 10627 | }, |
||
| 10628 | |||
| 10629 | abort: function() { |
||
| 10630 | var target = this; |
||
| 10631 | |||
| 10632 | if (_iframe && _iframe.contentWindow) { |
||
| 10633 | if (_iframe.contentWindow.stop) { // FireFox/Safari/Chrome |
||
| 10634 | _iframe.contentWindow.stop(); |
||
| 10635 | } else if (_iframe.contentWindow.document.execCommand) { // IE |
||
| 10636 | _iframe.contentWindow.document.execCommand('Stop'); |
||
| 10637 | } else { |
||
| 10638 | _iframe.src = "about:blank"; |
||
| 10639 | } |
||
| 10640 | } |
||
| 10641 | |||
| 10642 | cleanup.call(this, function() { |
||
| 10643 | // target.dispatchEvent('readystatechange'); |
||
| 10644 | target.dispatchEvent('abort'); |
||
| 10645 | }); |
||
| 10646 | } |
||
| 10647 | }); |
||
| 10648 | } |
||
| 10649 | |||
| 10650 | return (extensions.XMLHttpRequest = XMLHttpRequest); |
||
| 10651 | }); |
||
| 10652 | |||
| 10653 | // Included from: src/javascript/runtime/html4/image/Image.js |
||
| 10654 | |||
| 10655 | /** |
||
| 10656 | * Image.js |
||
| 10657 | * |
||
| 10658 | * Copyright 2013, Moxiecode Systems AB |
||
| 10659 | * Released under GPL License. |
||
| 10660 | * |
||
| 10661 | * License: http://www.plupload.com/license |
||
| 10662 | * Contributing: http://www.plupload.com/contributing |
||
| 10663 | */ |
||
| 10664 | |||
| 10665 | /** |
||
| 10666 | @class moxie/runtime/html4/image/Image |
||
| 10667 | @private |
||
| 10668 | */ |
||
| 10669 | define("moxie/runtime/html4/image/Image", [ |
||
| 10670 | "moxie/runtime/html4/Runtime", |
||
| 10671 | "moxie/runtime/html5/image/Image" |
||
| 10672 | ], function(extensions, Image) { |
||
| 10673 | return (extensions.Image = Image); |
||
| 10674 | }); |
||
| 10675 | |||
| 10676 | expose(["moxie/core/utils/Basic","moxie/core/I18n","moxie/core/utils/Mime","moxie/core/utils/Env","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/EventTarget","moxie/core/utils/Encode","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/file/File","moxie/file/FileInput","moxie/file/FileDrop","moxie/runtime/RuntimeTarget","moxie/file/FileReader","moxie/core/utils/Url","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/image/Image","moxie/core/utils/Events"]); |
||
| 10677 | })(this);/** |
||
| 10678 | * o.js |
||
| 10679 | * |
||
| 10680 | * Copyright 2013, Moxiecode Systems AB |
||
| 10681 | * Released under GPL License. |
||
| 10682 | * |
||
| 10683 | * License: http://www.plupload.com/license |
||
| 10684 | * Contributing: http://www.plupload.com/contributing |
||
| 10685 | */ |
||
| 10686 | |||
| 10687 | /*global moxie:true */ |
||
| 10688 | |||
| 10689 | /** |
||
| 10690 | Globally exposed namespace with the most frequently used public classes and handy methods. |
||
| 10691 | |||
| 10692 | @class o |
||
| 10693 | @static |
||
| 10694 | @private |
||
| 10695 | */ |
||
| 10696 | (function(exports) { |
||
| 10697 | "use strict"; |
||
| 10698 | |||
| 10699 | var o = {}, inArray = exports.moxie.core.utils.Basic.inArray; |
||
| 10700 | |||
| 10701 | // directly add some public classes |
||
| 10702 | // (we do it dynamically here, since for custom builds we cannot know beforehand what modules were included) |
||
| 10703 | (function addAlias(ns) { |
||
| 10704 | var name, itemType; |
||
| 10705 | for (name in ns) { |
||
| 10706 | itemType = typeof(ns[name]); |
||
| 10707 | if (itemType === 'object' && !~inArray(name, ['Exceptions', 'Env', 'Mime'])) { |
||
| 10708 | addAlias(ns[name]); |
||
| 10709 | } else if (itemType === 'function') { |
||
| 10710 | o[name] = ns[name]; |
||
| 10711 | } |
||
| 10712 | } |
||
| 10713 | })(exports.moxie); |
||
| 10714 | |||
| 10715 | // add some manually |
||
| 10716 | o.Env = exports.moxie.core.utils.Env; |
||
| 10717 | o.Mime = exports.moxie.core.utils.Mime; |
||
| 10718 | o.Exceptions = exports.moxie.core.Exceptions; |
||
| 10719 | |||
| 10720 | // expose globally |
||
| 10721 | exports.mOxie = o; |
||
| 10722 | if (!exports.o) { |
||
| 10723 | exports.o = o; |
||
| 10724 | } |
||
| 10725 | return o; |
||
| 10726 | })(this); |