webshims-rails 1.14.6 → 1.15.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/lib/webshims-rails/version.rb +2 -2
  3. data/vendor/assets/javascripts/webshims/polyfiller.js +145 -139
  4. data/vendor/assets/javascripts/webshims/shims/canvas-blob.js +97 -0
  5. data/vendor/assets/javascripts/webshims/shims/combos/1.js +13 -15
  6. data/vendor/assets/javascripts/webshims/shims/combos/10.js +29 -28
  7. data/vendor/assets/javascripts/webshims/shims/combos/11.js +2 -1
  8. data/vendor/assets/javascripts/webshims/shims/combos/12.js +22 -10
  9. data/vendor/assets/javascripts/webshims/shims/combos/13.js +22 -10
  10. data/vendor/assets/javascripts/webshims/shims/combos/15.js +28 -43
  11. data/vendor/assets/javascripts/webshims/shims/combos/16.js +41 -44
  12. data/vendor/assets/javascripts/webshims/shims/combos/17.js +2 -1
  13. data/vendor/assets/javascripts/webshims/shims/combos/2.js +40 -42
  14. data/vendor/assets/javascripts/webshims/shims/combos/21.js +98 -71
  15. data/vendor/assets/javascripts/webshims/shims/combos/22.js +9 -9
  16. data/vendor/assets/javascripts/webshims/shims/combos/23.js +13 -1
  17. data/vendor/assets/javascripts/webshims/shims/combos/25.js +141 -51
  18. data/vendor/assets/javascripts/webshims/shims/combos/27.js +66 -12
  19. data/vendor/assets/javascripts/webshims/shims/combos/28.js +1 -2
  20. data/vendor/assets/javascripts/webshims/shims/combos/3.js +27 -41
  21. data/vendor/assets/javascripts/webshims/shims/combos/30.js +27 -41
  22. data/vendor/assets/javascripts/webshims/shims/combos/31.js +27 -41
  23. data/vendor/assets/javascripts/webshims/shims/combos/34.js +36 -36
  24. data/vendor/assets/javascripts/webshims/shims/combos/4.js +27 -27
  25. data/vendor/assets/javascripts/webshims/shims/combos/5.js +2 -1
  26. data/vendor/assets/javascripts/webshims/shims/combos/6.js +2 -1
  27. data/vendor/assets/javascripts/webshims/shims/combos/7.js +40 -42
  28. data/vendor/assets/javascripts/webshims/shims/combos/8.js +40 -42
  29. data/vendor/assets/javascripts/webshims/shims/combos/9.js +29 -28
  30. data/vendor/assets/javascripts/webshims/shims/combos/98.js +4 -2
  31. data/vendor/assets/javascripts/webshims/shims/combos/99.js +4 -2
  32. data/vendor/assets/javascripts/webshims/shims/dom-extend.js +27 -27
  33. data/vendor/assets/javascripts/webshims/shims/es6.js +23 -29
  34. data/vendor/assets/javascripts/webshims/shims/{filereader.js → filereader-xhr.js} +66 -12
  35. data/vendor/assets/javascripts/webshims/shims/form-core.js +0 -14
  36. data/vendor/assets/javascripts/webshims/shims/form-number-date-ui.js +2 -1
  37. data/vendor/assets/javascripts/webshims/shims/form-shim-extend.js +1 -2
  38. data/vendor/assets/javascripts/webshims/shims/form-validation.js +18 -5
  39. data/vendor/assets/javascripts/webshims/shims/form-validators.js +15 -14
  40. data/vendor/assets/javascripts/webshims/shims/geolocation.js +41 -50
  41. data/vendor/assets/javascripts/webshims/shims/jme/controls.css +4 -4
  42. data/vendor/assets/javascripts/webshims/shims/jme/controls.scss +2 -1
  43. data/vendor/assets/javascripts/webshims/shims/jme/mediacontrols.js +4 -2
  44. data/vendor/assets/javascripts/webshims/shims/mediacapture-picker.js +42 -0
  45. data/vendor/assets/javascripts/webshims/shims/mediacapture.js +159 -0
  46. data/vendor/assets/javascripts/webshims/shims/mediaelement-core.js +13 -1
  47. data/vendor/assets/javascripts/webshims/shims/mediaelement-jaris.js +48 -12
  48. data/vendor/assets/javascripts/webshims/shims/mediaelement-yt.js +20 -8
  49. data/vendor/assets/javascripts/webshims/shims/{combos/26.js → moxie/js/moxie-html4.js} +2121 -1257
  50. data/vendor/assets/javascripts/webshims/shims/moxie/js/{moxie.js → moxie-swf.js} +1125 -1741
  51. data/vendor/assets/javascripts/webshims/shims/sticky.js +585 -0
  52. data/vendor/assets/javascripts/webshims/shims/styles/forms-picker.css +20 -0
  53. data/vendor/assets/javascripts/webshims/shims/styles/scss/forms-picker.scss +23 -0
  54. data/vendor/assets/javascripts/webshims/shims/styles/scss/shim.scss +74 -34
  55. data/vendor/assets/javascripts/webshims/shims/styles/shim-ext.css +78 -31
  56. data/vendor/assets/javascripts/webshims/shims/styles/shim.css +78 -31
  57. data/vendor/assets/javascripts/webshims/shims/swf/JarisFLVPlayer.swf +0 -0
  58. data/vendor/assets/javascripts/webshims/shims/track-ui.js +214 -111
  59. data/vendor/assets/javascripts/webshims/shims/track.js +9 -9
  60. data/vendor/assets/javascripts/webshims/shims/usermedia-core.js +27 -0
  61. data/vendor/assets/javascripts/webshims/shims/usermedia-shim.js +34 -37
  62. metadata +9 -8
  63. data/vendor/assets/javascripts/webshims/shims/jajax.js +0 -1262
  64. data/vendor/assets/javascripts/webshims/shims/moxie/silverlight/Moxie.cdn.xap +0 -0
  65. data/vendor/assets/javascripts/webshims/shims/moxie/silverlight/Moxie.min.xap +0 -0
@@ -2,13 +2,21 @@ webshims.register('mediaelement-yt', function($, webshims, window, document, und
2
2
  "use strict";
3
3
  var mediaelement = webshims.mediaelement;
4
4
  var ytAPI = $.Deferred();
5
+ var loadYTAPI = function(){
6
+ if(!window.YT){
7
+ webshims.loader.loadScript("https://www.youtube.com/player_api");
8
+ }
9
+ loadYTAPI = $.noop;
10
+ };
11
+ var modern = window.Modernizr;
12
+ var assumeYTBug = (!modern || !modern.videoautoplay) && /iP(hone|od|ad)|android/i.test(navigator.userAgent);
5
13
  window.onYouTubePlayerAPIReady = function() {
6
14
  ytAPI.resolve();
15
+ loadYTAPI = $.noop;
7
16
  };
8
17
  if(window.YT && YT.Player){
9
18
  window.onYouTubePlayerAPIReady();
10
19
  }
11
-
12
20
  var getProps = {
13
21
  paused: true,
14
22
  ended: false,
@@ -45,7 +53,6 @@ var getSetProps = {
45
53
  volume: 1,
46
54
  muted: false
47
55
  };
48
- var getSetPropKeys = Object.keys(getSetProps);
49
56
 
50
57
  var playerStateObj = $.extend({
51
58
  isActive: 'html5',
@@ -193,7 +200,6 @@ var getComputedDimension = (function(){
193
200
 
194
201
  var setElementDimension = function(data){
195
202
  var dims;
196
- var elem = data._elem;
197
203
  var box = data.shadowElem;
198
204
  if(data.isActive == 'third'){
199
205
  if(data && data._ytAPI && data._ytAPI.getPlaybackQuality){
@@ -439,9 +445,9 @@ var addYtAPI = function(mediaElm, elemId, data, ytParams){
439
445
  var currentTime = data._ytAPI.getCurrentTime();
440
446
  if(data.currentTime != currentTime){
441
447
  data.currentTime = currentTime;
442
- $(mediaElm).trigger('timeupdate');
448
+ $.event.trigger('timeupdate', null, mediaElm, true);
443
449
  }
444
- }, 350);
450
+ }, 270);
445
451
  };
446
452
 
447
453
  data._metatrys = 0;
@@ -569,7 +575,9 @@ mediaelement.createSWF = function(mediaElem, src, data){
569
575
  var ytParams = getYtParams(src.src);
570
576
  var hasControls = $.prop(mediaElem, 'controls');
571
577
  var attrStyle = {};
572
-
578
+
579
+ loadYTAPI();
580
+
573
581
  if((attrStyle.height = $.attr(mediaElem, 'height') || '') || (attrStyle.width = $.attr(mediaElem, 'width') || '')){
574
582
  $(mediaElem).css(attrStyle);
575
583
  webshims.warn("width or height content attributes used. Webshims prefers the usage of CSS (computed styles or inline styles) to detect size of a video/audio. It's really more powerfull.");
@@ -739,8 +747,12 @@ mediaelement.createSWF = function(mediaElem, src, data){
739
747
  var data = getYtDataFromElem(this);
740
748
  if(data){
741
749
  if(data._ytAPI && data._ytAPI[ytName]){
742
- data._ytAPI[ytName]();
743
- handlePlayPauseState(name, data);
750
+ if(assumeYTBug && !data.readyState && !data.networkState && data._ppFlag === undefined){
751
+ webshims.warn('youtube video play needs to be directly activated by user, if you use a video overlay set pointer-events to none.');
752
+ } else {
753
+ data._ytAPI[ytName]();
754
+ handlePlayPauseState(name, data);
755
+ }
744
756
  }
745
757
  } else {
746
758
  return mediaSup[name].prop._supvalue.apply(this, arguments);
@@ -5131,436 +5131,6 @@ define("moxie/xhr/XMLHttpRequest", [
5131
5131
  return XMLHttpRequest;
5132
5132
  });
5133
5133
 
5134
- // Included from: src/javascript/runtime/flash/Runtime.js
5135
-
5136
- /**
5137
- * Runtime.js
5138
- *
5139
- * Copyright 2013, Moxiecode Systems AB
5140
- * Released under GPL License.
5141
- *
5142
- * License: http://www.plupload.com/license
5143
- * Contributing: http://www.plupload.com/contributing
5144
- */
5145
-
5146
- /*global ActiveXObject:true */
5147
-
5148
- /**
5149
- Defines constructor for Flash runtime.
5150
-
5151
- @class moxie/runtime/flash/Runtime
5152
- @private
5153
- */
5154
- define("moxie/runtime/flash/Runtime", [
5155
- "moxie/core/utils/Basic",
5156
- "moxie/core/utils/Env",
5157
- "moxie/core/utils/Dom",
5158
- "moxie/core/Exceptions",
5159
- "moxie/runtime/Runtime"
5160
- ], function(Basic, Env, Dom, x, Runtime) {
5161
-
5162
- var type = 'flash', extensions = {};
5163
-
5164
- /**
5165
- Get the version of the Flash Player
5166
-
5167
- @method getShimVersion
5168
- @private
5169
- @return {Number} Flash Player version
5170
- */
5171
- function getShimVersion() {
5172
- var version;
5173
-
5174
- try {
5175
- version = navigator.plugins['Shockwave Flash'];
5176
- version = version.description;
5177
- } catch (e1) {
5178
- try {
5179
- version = new ActiveXObject('ShockwaveFlash.ShockwaveFlash').GetVariable('$version');
5180
- } catch (e2) {
5181
- version = '0.0';
5182
- }
5183
- }
5184
- version = version.match(/\d+/g);
5185
- return parseFloat(version[0] + '.' + version[1]);
5186
- }
5187
-
5188
- /**
5189
- Constructor for the Flash Runtime
5190
-
5191
- @class FlashRuntime
5192
- @extends Runtime
5193
- */
5194
- function FlashRuntime(options) {
5195
- var I = this, initTimer;
5196
-
5197
- options = Basic.extend({ swf_url: Env.swf_url }, options);
5198
-
5199
- Runtime.call(this, options, type, {
5200
- access_binary: function(value) {
5201
- return value && I.mode === 'browser';
5202
- },
5203
- access_image_binary: function(value) {
5204
- return value && I.mode === 'browser';
5205
- },
5206
- display_media: Runtime.capTrue,
5207
- do_cors: Runtime.capTrue,
5208
- drag_and_drop: false,
5209
- report_upload_progress: function() {
5210
- return I.mode === 'client';
5211
- },
5212
- resize_image: Runtime.capTrue,
5213
- return_response_headers: false,
5214
- return_response_type: function(responseType) {
5215
- if (responseType === 'json' && !!window.JSON) {
5216
- return true;
5217
- }
5218
- return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser';
5219
- },
5220
- return_status_code: function(code) {
5221
- return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]);
5222
- },
5223
- select_file: Runtime.capTrue,
5224
- select_multiple: Runtime.capTrue,
5225
- send_binary_string: function(value) {
5226
- return value && I.mode === 'browser';
5227
- },
5228
- send_browser_cookies: function(value) {
5229
- return value && I.mode === 'browser';
5230
- },
5231
- send_custom_headers: function(value) {
5232
- return value && I.mode === 'browser';
5233
- },
5234
- send_multipart: Runtime.capTrue,
5235
- slice_blob: function(value) {
5236
- return value && I.mode === 'browser';
5237
- },
5238
- stream_upload: function(value) {
5239
- return value && I.mode === 'browser';
5240
- },
5241
- summon_file_dialog: false,
5242
- upload_filesize: function(size) {
5243
- return Basic.parseSizeStr(size) <= 2097152 || I.mode === 'client';
5244
- },
5245
- use_http_method: function(methods) {
5246
- return !Basic.arrayDiff(methods, ['GET', 'POST']);
5247
- }
5248
- }, {
5249
- // capabilities that require specific mode
5250
- access_binary: function(value) {
5251
- return value ? 'browser' : 'client';
5252
- },
5253
- access_image_binary: function(value) {
5254
- return value ? 'browser' : 'client';
5255
- },
5256
- report_upload_progress: function(value) {
5257
- return value ? 'browser' : 'client';
5258
- },
5259
- return_response_type: function(responseType) {
5260
- return Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) ? 'browser' : ['client', 'browser'];
5261
- },
5262
- return_status_code: function(code) {
5263
- return Basic.arrayDiff(code, [200, 404]) ? 'browser' : ['client', 'browser'];
5264
- },
5265
- send_binary_string: function(value) {
5266
- return value ? 'browser' : 'client';
5267
- },
5268
- send_browser_cookies: function(value) {
5269
- return value ? 'browser' : 'client';
5270
- },
5271
- send_custom_headers: function(value) {
5272
- return value ? 'browser' : 'client';
5273
- },
5274
- stream_upload: function(value) {
5275
- return value ? 'client' : 'browser';
5276
- },
5277
- upload_filesize: function(size) {
5278
- return Basic.parseSizeStr(size) >= 2097152 ? 'client' : 'browser';
5279
- }
5280
- }, 'client');
5281
-
5282
-
5283
- // minimal requirement for Flash Player version
5284
- if (getShimVersion() < 10) {
5285
- this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before
5286
- }
5287
-
5288
-
5289
- Basic.extend(this, {
5290
-
5291
- getShim: function() {
5292
- return Dom.get(this.uid);
5293
- },
5294
-
5295
- shimExec: function(component, action) {
5296
- var args = [].slice.call(arguments, 2);
5297
- return I.getShim().exec(this.uid, component, action, args);
5298
- },
5299
-
5300
- init: function() {
5301
- var html, el, container;
5302
-
5303
- container = this.getShimContainer();
5304
-
5305
- // 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)
5306
- Basic.extend(container.style, {
5307
- position: 'absolute',
5308
- top: '-8px',
5309
- left: '-8px',
5310
- width: '9px',
5311
- height: '9px',
5312
- overflow: 'hidden'
5313
- });
5314
-
5315
- // insert flash object
5316
- html = '<object id="' + this.uid + '" type="application/x-shockwave-flash" data="' + options.swf_url + '" ';
5317
-
5318
- if (Env.browser === 'IE') {
5319
- html += 'classid="clsid:d27cdb6e-ae6d-11cf-96b8-444553540000" ';
5320
- }
5321
-
5322
- html += 'width="100%" height="100%" style="outline:0">' +
5323
- '<param name="movie" value="' + options.swf_url + '" />' +
5324
- '<param name="flashvars" value="uid=' + escape(this.uid) + '&target=' + Env.global_event_dispatcher + '" />' +
5325
- '<param name="wmode" value="transparent" />' +
5326
- '<param name="allowscriptaccess" value="always" />' +
5327
- '</object>';
5328
-
5329
- if (Env.browser === 'IE') {
5330
- el = document.createElement('div');
5331
- container.appendChild(el);
5332
- el.outerHTML = html;
5333
- el = container = null; // just in case
5334
- } else {
5335
- container.innerHTML = html;
5336
- }
5337
-
5338
- // Init is dispatched by the shim
5339
- initTimer = setTimeout(function() {
5340
- if (I && !I.initialized) { // runtime might be already destroyed by this moment
5341
- I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
5342
- }
5343
- }, 5000);
5344
- },
5345
-
5346
- destroy: (function(destroy) { // extend default destroy method
5347
- return function() {
5348
- destroy.call(I);
5349
- clearTimeout(initTimer); // initialization check might be still onwait
5350
- options = initTimer = destroy = I = null;
5351
- };
5352
- }(this.destroy))
5353
-
5354
- }, extensions);
5355
- }
5356
-
5357
- Runtime.addConstructor(type, FlashRuntime);
5358
-
5359
- return extensions;
5360
- });
5361
-
5362
- // Included from: src/javascript/runtime/flash/file/Blob.js
5363
-
5364
- /**
5365
- * Blob.js
5366
- *
5367
- * Copyright 2013, Moxiecode Systems AB
5368
- * Released under GPL License.
5369
- *
5370
- * License: http://www.plupload.com/license
5371
- * Contributing: http://www.plupload.com/contributing
5372
- */
5373
-
5374
- /**
5375
- @class moxie/runtime/flash/file/Blob
5376
- @private
5377
- */
5378
- define("moxie/runtime/flash/file/Blob", [
5379
- "moxie/runtime/flash/Runtime",
5380
- "moxie/file/Blob"
5381
- ], function(extensions, Blob) {
5382
-
5383
- var FlashBlob = {
5384
- slice: function(blob, start, end, type) {
5385
- var self = this.getRuntime();
5386
-
5387
- if (start < 0) {
5388
- start = Math.max(blob.size + start, 0);
5389
- } else if (start > 0) {
5390
- start = Math.min(start, blob.size);
5391
- }
5392
-
5393
- if (end < 0) {
5394
- end = Math.max(blob.size + end, 0);
5395
- } else if (end > 0) {
5396
- end = Math.min(end, blob.size);
5397
- }
5398
-
5399
- blob = self.shimExec.call(this, 'Blob', 'slice', start, end, type || '');
5400
-
5401
- if (blob) {
5402
- blob = new Blob(self.uid, blob);
5403
- }
5404
- return blob;
5405
- }
5406
- };
5407
-
5408
- return (extensions.Blob = FlashBlob);
5409
- });
5410
-
5411
- // Included from: src/javascript/runtime/flash/file/FileInput.js
5412
-
5413
- /**
5414
- * FileInput.js
5415
- *
5416
- * Copyright 2013, Moxiecode Systems AB
5417
- * Released under GPL License.
5418
- *
5419
- * License: http://www.plupload.com/license
5420
- * Contributing: http://www.plupload.com/contributing
5421
- */
5422
-
5423
- /**
5424
- @class moxie/runtime/flash/file/FileInput
5425
- @private
5426
- */
5427
- define("moxie/runtime/flash/file/FileInput", [
5428
- "moxie/runtime/flash/Runtime"
5429
- ], function(extensions) {
5430
-
5431
- var FileInput = {
5432
- init: function(options) {
5433
- this.getRuntime().shimExec.call(this, 'FileInput', 'init', {
5434
- name: options.name,
5435
- accept: options.accept,
5436
- multiple: options.multiple
5437
- });
5438
- this.trigger('ready');
5439
- }
5440
- };
5441
-
5442
- return (extensions.FileInput = FileInput);
5443
- });
5444
-
5445
- // Included from: src/javascript/runtime/flash/file/FileReader.js
5446
-
5447
- /**
5448
- * FileReader.js
5449
- *
5450
- * Copyright 2013, Moxiecode Systems AB
5451
- * Released under GPL License.
5452
- *
5453
- * License: http://www.plupload.com/license
5454
- * Contributing: http://www.plupload.com/contributing
5455
- */
5456
-
5457
- /**
5458
- @class moxie/runtime/flash/file/FileReader
5459
- @private
5460
- */
5461
- define("moxie/runtime/flash/file/FileReader", [
5462
- "moxie/runtime/flash/Runtime",
5463
- "moxie/core/utils/Encode"
5464
- ], function(extensions, Encode) {
5465
-
5466
- var _result = '';
5467
-
5468
- function _formatData(data, op) {
5469
- switch (op) {
5470
- case 'readAsText':
5471
- return Encode.atob(data, 'utf8');
5472
- case 'readAsBinaryString':
5473
- return Encode.atob(data);
5474
- case 'readAsDataURL':
5475
- return data;
5476
- }
5477
- return null;
5478
- }
5479
-
5480
- var FileReader = {
5481
- read: function(op, blob) {
5482
- var target = this, self = target.getRuntime();
5483
-
5484
- // special prefix for DataURL read mode
5485
- if (op === 'readAsDataURL') {
5486
- _result = 'data:' + (blob.type || '') + ';base64,';
5487
- }
5488
-
5489
- target.bind('Progress', function(e, data) {
5490
- if (data) {
5491
- _result += _formatData(data, op);
5492
- }
5493
- });
5494
-
5495
- return self.shimExec.call(this, 'FileReader', 'readAsBase64', blob.uid);
5496
- },
5497
-
5498
- getResult: function() {
5499
- return _result;
5500
- },
5501
-
5502
- destroy: function() {
5503
- _result = null;
5504
- }
5505
- };
5506
-
5507
- return (extensions.FileReader = FileReader);
5508
- });
5509
-
5510
- // Included from: src/javascript/runtime/flash/file/FileReaderSync.js
5511
-
5512
- /**
5513
- * FileReaderSync.js
5514
- *
5515
- * Copyright 2013, Moxiecode Systems AB
5516
- * Released under GPL License.
5517
- *
5518
- * License: http://www.plupload.com/license
5519
- * Contributing: http://www.plupload.com/contributing
5520
- */
5521
-
5522
- /**
5523
- @class moxie/runtime/flash/file/FileReaderSync
5524
- @private
5525
- */
5526
- define("moxie/runtime/flash/file/FileReaderSync", [
5527
- "moxie/runtime/flash/Runtime",
5528
- "moxie/core/utils/Encode"
5529
- ], function(extensions, Encode) {
5530
-
5531
- function _formatData(data, op) {
5532
- switch (op) {
5533
- case 'readAsText':
5534
- return Encode.atob(data, 'utf8');
5535
- case 'readAsBinaryString':
5536
- return Encode.atob(data);
5537
- case 'readAsDataURL':
5538
- return data;
5539
- }
5540
- return null;
5541
- }
5542
-
5543
- var FileReaderSync = {
5544
- read: function(op, blob) {
5545
- var result, self = this.getRuntime();
5546
-
5547
- result = self.shimExec.call(this, 'FileReaderSync', 'readAsBase64', blob.uid);
5548
- if (!result) {
5549
- return null; // or throw ex
5550
- }
5551
-
5552
- // special prefix for DataURL read mode
5553
- if (op === 'readAsDataURL') {
5554
- result = 'data:' + (blob.type || '') + ';base64,' + result;
5555
- }
5556
-
5557
- return _formatData(result, op, blob.type);
5558
- }
5559
- };
5560
-
5561
- return (extensions.FileReaderSync = FileReaderSync);
5562
- });
5563
-
5564
5134
  // Included from: src/javascript/runtime/Transporter.js
5565
5135
 
5566
5136
  /**
@@ -5698,10 +5268,10 @@ define("moxie/runtime/Transporter", [
5698
5268
  return Transporter;
5699
5269
  });
5700
5270
 
5701
- // Included from: src/javascript/runtime/flash/xhr/XMLHttpRequest.js
5271
+ // Included from: src/javascript/image/Image.js
5702
5272
 
5703
5273
  /**
5704
- * XMLHttpRequest.js
5274
+ * Image.js
5705
5275
  *
5706
5276
  * Copyright 2013, Moxiecode Systems AB
5707
5277
  * Released under GPL License.
@@ -5710,141 +5280,598 @@ define("moxie/runtime/Transporter", [
5710
5280
  * Contributing: http://www.plupload.com/contributing
5711
5281
  */
5712
5282
 
5713
- /**
5714
- @class moxie/runtime/flash/xhr/XMLHttpRequest
5715
- @private
5716
- */
5717
- define("moxie/runtime/flash/xhr/XMLHttpRequest", [
5718
- "moxie/runtime/flash/Runtime",
5283
+ define("moxie/image/Image", [
5719
5284
  "moxie/core/utils/Basic",
5285
+ "moxie/core/utils/Dom",
5286
+ "moxie/core/Exceptions",
5287
+ "moxie/file/FileReaderSync",
5288
+ "moxie/xhr/XMLHttpRequest",
5289
+ "moxie/runtime/Runtime",
5290
+ "moxie/runtime/RuntimeClient",
5291
+ "moxie/runtime/Transporter",
5292
+ "moxie/core/utils/Env",
5293
+ "moxie/core/EventTarget",
5720
5294
  "moxie/file/Blob",
5721
5295
  "moxie/file/File",
5722
- "moxie/file/FileReaderSync",
5723
- "moxie/xhr/FormData",
5724
- "moxie/runtime/Transporter"
5725
- ], function(extensions, Basic, Blob, File, FileReaderSync, FormData, Transporter) {
5726
-
5727
- var XMLHttpRequest = {
5296
+ "moxie/core/utils/Encode"
5297
+ ], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) {
5298
+ /**
5299
+ Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data.
5728
5300
 
5729
- send: function(meta, data) {
5730
- var target = this, self = target.getRuntime();
5301
+ @class Image
5302
+ @constructor
5303
+ @extends EventTarget
5304
+ */
5305
+ var dispatches = [
5306
+ 'progress',
5731
5307
 
5732
- function send() {
5733
- meta.transport = self.mode;
5734
- self.shimExec.call(target, 'XMLHttpRequest', 'send', meta, data);
5735
- }
5308
+ /**
5309
+ Dispatched when loading is complete.
5736
5310
 
5311
+ @event load
5312
+ @param {Object} event
5313
+ */
5314
+ 'load',
5737
5315
 
5738
- function appendBlob(name, blob) {
5739
- self.shimExec.call(target, 'XMLHttpRequest', 'appendBlob', name, blob.uid);
5740
- data = null;
5741
- send();
5742
- }
5316
+ 'error',
5743
5317
 
5318
+ /**
5319
+ Dispatched when resize operation is complete.
5320
+
5321
+ @event resize
5322
+ @param {Object} event
5323
+ */
5324
+ 'resize',
5744
5325
 
5745
- function attachBlob(blob, cb) {
5746
- var tr = new Transporter();
5326
+ /**
5327
+ Dispatched when visual representation of the image is successfully embedded
5328
+ into the corresponsing container.
5747
5329
 
5748
- tr.bind("TransportingComplete", function() {
5749
- cb(this.result);
5750
- });
5330
+ @event embedded
5331
+ @param {Object} event
5332
+ */
5333
+ 'embedded'
5334
+ ];
5751
5335
 
5752
- tr.transport(blob.getSource(), blob.type, {
5753
- ruid: self.uid
5754
- });
5755
- }
5336
+ function Image() {
5337
+ RuntimeClient.call(this);
5756
5338
 
5757
- // copy over the headers if any
5758
- if (!Basic.isEmptyObj(meta.headers)) {
5759
- Basic.each(meta.headers, function(value, header) {
5760
- self.shimExec.call(target, 'XMLHttpRequest', 'setRequestHeader', header, value.toString()); // Silverlight doesn't accept integers into the arguments of type object
5761
- });
5762
- }
5339
+ Basic.extend(this, {
5340
+ /**
5341
+ Unique id of the component
5763
5342
 
5764
- // transfer over multipart params and blob itself
5765
- if (data instanceof FormData) {
5766
- var blobField;
5767
- data.each(function(value, name) {
5768
- if (value instanceof Blob) {
5769
- blobField = name;
5770
- } else {
5771
- self.shimExec.call(target, 'XMLHttpRequest', 'append', name, value);
5772
- }
5773
- });
5343
+ @property uid
5344
+ @type {String}
5345
+ */
5346
+ uid: Basic.guid('uid_'),
5347
+
5348
+ /**
5349
+ Unique id of the connected runtime, if any.
5350
+
5351
+ @property ruid
5352
+ @type {String}
5353
+ */
5354
+ ruid: null,
5355
+
5356
+ /**
5357
+ Name of the file, that was used to create an image, if available. If not equals to empty string.
5358
+
5359
+ @property name
5360
+ @type {String}
5361
+ @default ""
5362
+ */
5363
+ name: "",
5364
+
5365
+ /**
5366
+ Size of the image in bytes. Actual value is set only after image is preloaded.
5367
+
5368
+ @property size
5369
+ @type {Number}
5370
+ @default 0
5371
+ */
5372
+ size: 0,
5373
+
5374
+ /**
5375
+ Width of the image. Actual value is set only after image is preloaded.
5376
+
5377
+ @property width
5378
+ @type {Number}
5379
+ @default 0
5380
+ */
5381
+ width: 0,
5382
+
5383
+ /**
5384
+ Height of the image. Actual value is set only after image is preloaded.
5385
+
5386
+ @property height
5387
+ @type {Number}
5388
+ @default 0
5389
+ */
5390
+ height: 0,
5391
+
5392
+ /**
5393
+ Mime type of the image. Currently only image/jpeg and image/png are supported. Actual value is set only after image is preloaded.
5394
+
5395
+ @property type
5396
+ @type {String}
5397
+ @default ""
5398
+ */
5399
+ type: "",
5400
+
5401
+ /**
5402
+ Holds meta info (Exif, GPS). Is populated only for image/jpeg. Actual value is set only after image is preloaded.
5403
+
5404
+ @property meta
5405
+ @type {Object}
5406
+ @default {}
5407
+ */
5408
+ meta: {},
5409
+
5410
+ /**
5411
+ Alias for load method, that takes another mOxie.Image object as a source (see load).
5412
+
5413
+ @method clone
5414
+ @param {Image} src Source for the image
5415
+ @param {Boolean} [exact=false] Whether to activate in-depth clone mode
5416
+ */
5417
+ clone: function() {
5418
+ this.load.apply(this, arguments);
5419
+ },
5420
+
5421
+ /**
5422
+ Loads image from various sources. Currently the source for new image can be: mOxie.Image, mOxie.Blob/mOxie.File,
5423
+ native Blob/File, dataUrl or URL. Depending on the type of the source, arguments - differ. When source is URL,
5424
+ Image will be downloaded from remote destination and loaded in memory.
5425
+
5426
+ @example
5427
+ var img = new mOxie.Image();
5428
+ img.onload = function() {
5429
+ var blob = img.getAsBlob();
5430
+
5431
+ var formData = new mOxie.FormData();
5432
+ formData.append('file', blob);
5433
+
5434
+ var xhr = new mOxie.XMLHttpRequest();
5435
+ xhr.onload = function() {
5436
+ // upload complete
5437
+ };
5438
+ xhr.open('post', 'upload.php');
5439
+ xhr.send(formData);
5440
+ };
5441
+ img.load("http://www.moxiecode.com/images/mox-logo.jpg"); // notice file extension (.jpg)
5442
+
5443
+
5444
+ @method load
5445
+ @param {Image|Blob|File|String} src Source for the image
5446
+ @param {Boolean|Object} [mixed]
5447
+ */
5448
+ load: function() {
5449
+ // this is here because to bind properly we need an uid first, which is created above
5450
+ this.bind('Load Resize', function() {
5451
+ _updateInfo.call(this);
5452
+ }, 999);
5453
+
5454
+ this.convertEventPropsToHandlers(dispatches);
5455
+
5456
+ _load.apply(this, arguments);
5457
+ },
5774
5458
 
5775
- if (!data.hasBlob()) {
5776
- data = null;
5777
- send();
5459
+ /**
5460
+ Downsizes the image to fit the specified width/height. If crop is supplied, image will be cropped to exact dimensions.
5461
+
5462
+ @method downsize
5463
+ @param {Number} width Resulting width
5464
+ @param {Number} [height=width] Resulting height (optional, if not supplied will default to width)
5465
+ @param {Boolean} [crop=false] Whether to crop the image to exact dimensions
5466
+ @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
5467
+ */
5468
+ downsize: function(opts) {
5469
+ var defaults = {
5470
+ width: this.width,
5471
+ height: this.height,
5472
+ crop: false,
5473
+ preserveHeaders: true
5474
+ };
5475
+
5476
+ if (typeof(opts) === 'object') {
5477
+ opts = Basic.extend(defaults, opts);
5778
5478
  } else {
5779
- var blob = data.getBlob();
5780
- if (blob.isDetached()) {
5781
- attachBlob(blob, function(attachedBlob) {
5782
- blob.destroy();
5783
- appendBlob(blobField, attachedBlob);
5784
- });
5479
+ opts = Basic.extend(defaults, {
5480
+ width: arguments[0],
5481
+ height: arguments[1],
5482
+ crop: arguments[2],
5483
+ preserveHeaders: arguments[3]
5484
+ });
5485
+ }
5486
+
5487
+ try {
5488
+ if (!this.size) { // only preloaded image objects can be used as source
5489
+ throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5490
+ }
5491
+
5492
+ // no way to reliably intercept the crash due to high resolution, so we simply avoid it
5493
+ if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
5494
+ throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
5495
+ }
5496
+
5497
+ this.getRuntime().exec.call(this, 'Image', 'downsize', opts.width, opts.height, opts.crop, opts.preserveHeaders);
5498
+ } catch(ex) {
5499
+ // for now simply trigger error event
5500
+ this.trigger('error', ex.code);
5501
+ }
5502
+ },
5503
+
5504
+ /**
5505
+ Alias for downsize(width, height, true). (see downsize)
5506
+
5507
+ @method crop
5508
+ @param {Number} width Resulting width
5509
+ @param {Number} [height=width] Resulting height (optional, if not supplied will default to width)
5510
+ @param {Boolean} [preserveHeaders=true] Whether to preserve meta headers (on JPEGs after resize)
5511
+ */
5512
+ crop: function(width, height, preserveHeaders) {
5513
+ this.downsize(width, height, true, preserveHeaders);
5514
+ },
5515
+
5516
+ getAsCanvas: function() {
5517
+ if (!Env.can('create_canvas')) {
5518
+ throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
5519
+ }
5520
+
5521
+ var runtime = this.connectRuntime(this.ruid);
5522
+ return runtime.exec.call(this, 'Image', 'getAsCanvas');
5523
+ },
5524
+
5525
+ /**
5526
+ Retrieves image in it's current state as mOxie.Blob object. Cannot be run on empty or image in progress (throws
5527
+ DOMException.INVALID_STATE_ERR).
5528
+
5529
+ @method getAsBlob
5530
+ @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
5531
+ @param {Number} [quality=90] Applicable only together with mime type image/jpeg
5532
+ @return {Blob} Image as Blob
5533
+ */
5534
+ getAsBlob: function(type, quality) {
5535
+ if (!this.size) {
5536
+ throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5537
+ }
5538
+
5539
+ if (!type) {
5540
+ type = 'image/jpeg';
5541
+ }
5542
+
5543
+ if (type === 'image/jpeg' && !quality) {
5544
+ quality = 90;
5545
+ }
5546
+
5547
+ return this.getRuntime().exec.call(this, 'Image', 'getAsBlob', type, quality);
5548
+ },
5549
+
5550
+ /**
5551
+ Retrieves image in it's current state as dataURL string. Cannot be run on empty or image in progress (throws
5552
+ DOMException.INVALID_STATE_ERR).
5553
+
5554
+ @method getAsDataURL
5555
+ @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
5556
+ @param {Number} [quality=90] Applicable only together with mime type image/jpeg
5557
+ @return {String} Image as dataURL string
5558
+ */
5559
+ getAsDataURL: function(type, quality) {
5560
+ if (!this.size) {
5561
+ throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5562
+ }
5563
+ return this.getRuntime().exec.call(this, 'Image', 'getAsDataURL', type, quality);
5564
+ },
5565
+
5566
+ /**
5567
+ Retrieves image in it's current state as binary string. Cannot be run on empty or image in progress (throws
5568
+ DOMException.INVALID_STATE_ERR).
5569
+
5570
+ @method getAsBinaryString
5571
+ @param {String} [type="image/jpeg"] Mime type of resulting blob. Can either be image/jpeg or image/png
5572
+ @param {Number} [quality=90] Applicable only together with mime type image/jpeg
5573
+ @return {String} Image as binary string
5574
+ */
5575
+ getAsBinaryString: function(type, quality) {
5576
+ var dataUrl = this.getAsDataURL(type, quality);
5577
+ return Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7));
5578
+ },
5579
+
5580
+ /**
5581
+ Embeds a visual representation of the image into the specified node. Depending on the runtime,
5582
+ it might be a canvas, an img node or a thrid party shim object (Flash or SilverLight - very rare,
5583
+ can be used in legacy browsers that do not have canvas or proper dataURI support).
5584
+
5585
+ @method embed
5586
+ @param {DOMElement} el DOM element to insert the image object into
5587
+ @param {Object} [options]
5588
+ @param {Number} [options.width] The width of an embed (defaults to the image width)
5589
+ @param {Number} [options.height] The height of an embed (defaults to the image height)
5590
+ @param {String} [type="image/jpeg"] Mime type
5591
+ @param {Number} [quality=90] Quality of an embed, if mime type is image/jpeg
5592
+ @param {Boolean} [crop=false] Whether to crop an embed to the specified dimensions
5593
+ */
5594
+ embed: function(el) {
5595
+ var self = this
5596
+ , imgCopy
5597
+ , type, quality, crop
5598
+ , options = arguments[1] || {}
5599
+ , width = this.width
5600
+ , height = this.height
5601
+ , runtime // this has to be outside of all the closures to contain proper runtime
5602
+ ;
5603
+
5604
+ function onResize() {
5605
+ // if possible, embed a canvas element directly
5606
+ if (Env.can('create_canvas')) {
5607
+ var canvas = imgCopy.getAsCanvas();
5608
+ if (canvas) {
5609
+ el.appendChild(canvas);
5610
+ canvas = null;
5611
+ imgCopy.destroy();
5612
+ self.trigger('embedded');
5613
+ return;
5614
+ }
5615
+ }
5616
+
5617
+ var dataUrl = imgCopy.getAsDataURL(type, quality);
5618
+ if (!dataUrl) {
5619
+ throw new x.ImageError(x.ImageError.WRONG_FORMAT);
5620
+ }
5621
+
5622
+ if (Env.can('use_data_uri_of', dataUrl.length)) {
5623
+ el.innerHTML = '<img src="' + dataUrl + '" width="' + imgCopy.width + '" height="' + imgCopy.height + '" />';
5624
+ imgCopy.destroy();
5625
+ self.trigger('embedded');
5785
5626
  } else {
5786
- appendBlob(blobField, blob);
5627
+ var tr = new Transporter();
5628
+
5629
+ tr.bind("TransportingComplete", function() {
5630
+ runtime = self.connectRuntime(this.result.ruid);
5631
+
5632
+ self.bind("Embedded", function() {
5633
+ // position and size properly
5634
+ Basic.extend(runtime.getShimContainer().style, {
5635
+ //position: 'relative',
5636
+ top: '0px',
5637
+ left: '0px',
5638
+ width: imgCopy.width + 'px',
5639
+ height: imgCopy.height + 'px'
5640
+ });
5641
+
5642
+ // some shims (Flash/SilverLight) reinitialize, if parent element is hidden, reordered or it's
5643
+ // position type changes (in Gecko), but since we basically need this only in IEs 6/7 and
5644
+ // sometimes 8 and they do not have this problem, we can comment this for now
5645
+ /*tr.bind("RuntimeInit", function(e, runtime) {
5646
+ tr.destroy();
5647
+ runtime.destroy();
5648
+ onResize.call(self); // re-feed our image data
5649
+ });*/
5650
+
5651
+ runtime = null;
5652
+ }, 999);
5653
+
5654
+ runtime.exec.call(self, "ImageView", "display", this.result.uid, width, height);
5655
+ imgCopy.destroy();
5656
+ });
5657
+
5658
+ tr.transport(Encode.atob(dataUrl.substring(dataUrl.indexOf('base64,') + 7)), type, Basic.extend({}, options, {
5659
+ required_caps: {
5660
+ display_media: true
5661
+ },
5662
+ runtime_order: 'flash,silverlight',
5663
+ container: el
5664
+ }));
5787
5665
  }
5788
5666
  }
5789
- } else if (data instanceof Blob) {
5790
- if (data.isDetached()) {
5791
- attachBlob(data, function(attachedBlob) {
5792
- data.destroy();
5793
- data = attachedBlob.uid;
5794
- send();
5667
+
5668
+ try {
5669
+ if (!(el = Dom.get(el))) {
5670
+ throw new x.DOMException(x.DOMException.INVALID_NODE_TYPE_ERR);
5671
+ }
5672
+
5673
+ if (!this.size) { // only preloaded image objects can be used as source
5674
+ throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5675
+ }
5676
+
5677
+ if (this.width > Image.MAX_RESIZE_WIDTH || this.height > Image.MAX_RESIZE_HEIGHT) {
5678
+ throw new x.ImageError(x.ImageError.MAX_RESOLUTION_ERR);
5679
+ }
5680
+
5681
+ type = options.type || this.type || 'image/jpeg';
5682
+ quality = options.quality || 90;
5683
+ crop = Basic.typeOf(options.crop) !== 'undefined' ? options.crop : false;
5684
+
5685
+ // figure out dimensions for the thumb
5686
+ if (options.width) {
5687
+ width = options.width;
5688
+ height = options.height || width;
5689
+ } else {
5690
+ // if container element has measurable dimensions, use them
5691
+ var dimensions = Dom.getSize(el);
5692
+ if (dimensions.w && dimensions.h) { // both should be > 0
5693
+ width = dimensions.w;
5694
+ height = dimensions.h;
5695
+ }
5696
+ }
5697
+
5698
+ imgCopy = new Image();
5699
+
5700
+ imgCopy.bind("Resize", function() {
5701
+ onResize.call(self);
5795
5702
  });
5796
- } else {
5797
- data = data.uid;
5798
- send();
5703
+
5704
+ imgCopy.bind("Load", function() {
5705
+ imgCopy.downsize(width, height, crop, false);
5706
+ });
5707
+
5708
+ imgCopy.clone(this, false);
5709
+
5710
+ return imgCopy;
5711
+ } catch(ex) {
5712
+ // for now simply trigger error event
5713
+ this.trigger('error', ex.code);
5799
5714
  }
5800
- } else {
5801
- send();
5715
+ },
5716
+
5717
+ /**
5718
+ Properly destroys the image and frees resources in use. If any. Recommended way to dispose mOxie.Image object.
5719
+
5720
+ @method destroy
5721
+ */
5722
+ destroy: function() {
5723
+ if (this.ruid) {
5724
+ this.getRuntime().exec.call(this, 'Image', 'destroy');
5725
+ this.disconnectRuntime();
5726
+ }
5727
+ this.unbindAll();
5802
5728
  }
5803
- },
5729
+ });
5804
5730
 
5805
- getResponse: function(responseType) {
5806
- var frs, blob, self = this.getRuntime();
5807
5731
 
5808
- blob = self.shimExec.call(this, 'XMLHttpRequest', 'getResponseAsBlob');
5732
+ function _updateInfo(info) {
5733
+ if (!info) {
5734
+ info = this.getRuntime().exec.call(this, 'Image', 'getInfo');
5735
+ }
5809
5736
 
5810
- if (blob) {
5811
- blob = new File(self.uid, blob);
5737
+ this.size = info.size;
5738
+ this.width = info.width;
5739
+ this.height = info.height;
5740
+ this.type = info.type;
5741
+ this.meta = info.meta;
5812
5742
 
5813
- if ('blob' === responseType) {
5814
- return blob;
5815
- }
5743
+ // update file name, only if empty
5744
+ if (this.name === '') {
5745
+ this.name = info.name;
5746
+ }
5747
+ }
5748
+
5816
5749
 
5817
- try {
5818
- frs = new FileReaderSync();
5750
+ function _load(src) {
5751
+ var srcType = Basic.typeOf(src);
5819
5752
 
5820
- if (!!~Basic.inArray(responseType, ["", "text"])) {
5821
- return frs.readAsText(blob);
5822
- } else if ('json' === responseType && !!window.JSON) {
5823
- return JSON.parse(frs.readAsText(blob));
5753
+ try {
5754
+ // if source is Image
5755
+ if (src instanceof Image) {
5756
+ if (!src.size) { // only preloaded image objects can be used as source
5757
+ throw new x.DOMException(x.DOMException.INVALID_STATE_ERR);
5758
+ }
5759
+ _loadFromImage.apply(this, arguments);
5760
+ }
5761
+ // if source is o.Blob/o.File
5762
+ else if (src instanceof Blob) {
5763
+ if (!~Basic.inArray(src.type, ['image/jpeg', 'image/png'])) {
5764
+ throw new x.ImageError(x.ImageError.WRONG_FORMAT);
5765
+ }
5766
+ _loadFromBlob.apply(this, arguments);
5767
+ }
5768
+ // if native blob/file
5769
+ else if (Basic.inArray(srcType, ['blob', 'file']) !== -1) {
5770
+ _load.call(this, new File(null, src), arguments[1]);
5771
+ }
5772
+ // if String
5773
+ else if (srcType === 'string') {
5774
+ // if dataUrl String
5775
+ if (/^data:[^;]*;base64,/.test(src)) {
5776
+ _load.call(this, new Blob(null, { data: src }), arguments[1]);
5777
+ }
5778
+ // else assume Url, either relative or absolute
5779
+ else {
5780
+ _loadFromUrl.apply(this, arguments);
5824
5781
  }
5825
- } finally {
5826
- blob.destroy();
5827
5782
  }
5783
+ // if source seems to be an img node
5784
+ else if (srcType === 'node' && src.nodeName.toLowerCase() === 'img') {
5785
+ _load.call(this, src.src, arguments[1]);
5786
+ }
5787
+ else {
5788
+ throw new x.DOMException(x.DOMException.TYPE_MISMATCH_ERR);
5789
+ }
5790
+ } catch(ex) {
5791
+ // for now simply trigger error event
5792
+ this.trigger('error', ex.code);
5828
5793
  }
5829
- return null;
5830
- },
5794
+ }
5795
+
5796
+
5797
+ function _loadFromImage(img, exact) {
5798
+ var runtime = this.connectRuntime(img.ruid);
5799
+ this.ruid = runtime.uid;
5800
+ runtime.exec.call(this, 'Image', 'loadFromImage', img, (Basic.typeOf(exact) === 'undefined' ? true : exact));
5801
+ }
5802
+
5803
+
5804
+ function _loadFromBlob(blob, options) {
5805
+ var self = this;
5806
+
5807
+ self.name = blob.name || '';
5808
+
5809
+ function exec(runtime) {
5810
+ self.ruid = runtime.uid;
5811
+ runtime.exec.call(self, 'Image', 'loadFromBlob', blob);
5812
+ }
5813
+
5814
+ if (blob.isDetached()) {
5815
+ this.bind('RuntimeInit', function(e, runtime) {
5816
+ exec(runtime);
5817
+ });
5818
+
5819
+ // convert to object representation
5820
+ if (options && typeof(options.required_caps) === 'string') {
5821
+ options.required_caps = Runtime.parseCaps(options.required_caps);
5822
+ }
5831
5823
 
5832
- abort: function(upload_complete_flag) {
5833
- var self = this.getRuntime();
5824
+ this.connectRuntime(Basic.extend({
5825
+ required_caps: {
5826
+ access_image_binary: true,
5827
+ resize_image: true
5828
+ }
5829
+ }, options));
5830
+ } else {
5831
+ exec(this.connectRuntime(blob.ruid));
5832
+ }
5833
+ }
5834
+
5835
+
5836
+ function _loadFromUrl(url, options) {
5837
+ var self = this, xhr;
5838
+
5839
+ xhr = new XMLHttpRequest();
5834
5840
 
5835
- self.shimExec.call(this, 'XMLHttpRequest', 'abort');
5841
+ xhr.open('get', url);
5842
+ xhr.responseType = 'blob';
5843
+
5844
+ xhr.onprogress = function(e) {
5845
+ self.trigger(e);
5846
+ };
5847
+
5848
+ xhr.onload = function() {
5849
+ _loadFromBlob.call(self, xhr.response, true);
5850
+ };
5851
+
5852
+ xhr.onerror = function(e) {
5853
+ self.trigger(e);
5854
+ };
5855
+
5856
+ xhr.onloadend = function() {
5857
+ xhr.destroy();
5858
+ };
5836
5859
 
5837
- this.dispatchEvent('readystatechange');
5838
- // this.dispatchEvent('progress');
5839
- this.dispatchEvent('abort');
5860
+ xhr.bind('RuntimeError', function(e, err) {
5861
+ self.trigger('RuntimeError', err);
5862
+ });
5840
5863
 
5841
- //if (!upload_complete_flag) {
5842
- // this.dispatchEvent('uploadprogress');
5843
- //}
5864
+ xhr.send(null, options);
5844
5865
  }
5845
- };
5866
+ }
5846
5867
 
5847
- return (extensions.XMLHttpRequest = XMLHttpRequest);
5868
+ // virtual world will crash on you if image has a resolution higher than this:
5869
+ Image.MAX_RESIZE_WIDTH = 6500;
5870
+ Image.MAX_RESIZE_HEIGHT = 6500;
5871
+
5872
+ Image.prototype = EventTarget.instance;
5873
+
5874
+ return Image;
5848
5875
  });
5849
5876
 
5850
5877
  // Included from: src/javascript/runtime/html4/Runtime.js
@@ -6836,10 +6863,10 @@ define("moxie/runtime/html4/xhr/XMLHttpRequest", [
6836
6863
  return (extensions.XMLHttpRequest = XMLHttpRequest);
6837
6864
  });
6838
6865
 
6839
- // Included from: src/javascript/runtime/silverlight/Runtime.js
6866
+ // Included from: src/javascript/runtime/html5/utils/BinaryReader.js
6840
6867
 
6841
6868
  /**
6842
- * RunTime.js
6869
+ * BinaryReader.js
6843
6870
  *
6844
6871
  * Copyright 2013, Moxiecode Systems AB
6845
6872
  * Released under GPL License.
@@ -6848,318 +6875,1630 @@ define("moxie/runtime/html4/xhr/XMLHttpRequest", [
6848
6875
  * Contributing: http://www.plupload.com/contributing
6849
6876
  */
6850
6877
 
6851
- /*global ActiveXObject:true */
6852
-
6853
6878
  /**
6854
- Defines constructor for Silverlight runtime.
6855
-
6856
- @class moxie/runtime/silverlight/Runtime
6879
+ @class moxie/runtime/html5/utils/BinaryReader
6857
6880
  @private
6858
6881
  */
6859
- define("moxie/runtime/silverlight/Runtime", [
6860
- "moxie/core/utils/Basic",
6861
- "moxie/core/utils/Env",
6862
- "moxie/core/utils/Dom",
6863
- "moxie/core/Exceptions",
6864
- "moxie/runtime/Runtime"
6865
- ], function(Basic, Env, Dom, x, Runtime) {
6866
-
6867
- var type = "silverlight", extensions = {};
6882
+ define("moxie/runtime/html5/utils/BinaryReader", [], function() {
6883
+ return function() {
6884
+ var II = false, bin;
6868
6885
 
6869
- function isInstalled(version) {
6870
- var isVersionSupported = false, control = null, actualVer,
6871
- actualVerArray, reqVerArray, requiredVersionPart, actualVersionPart, index = 0;
6886
+ // Private functions
6887
+ function read(idx, size) {
6888
+ var mv = II ? 0 : -8 * (size - 1), sum = 0, i;
6872
6889
 
6873
- try {
6874
- try {
6875
- control = new ActiveXObject('AgControl.AgControl');
6890
+ for (i = 0; i < size; i++) {
6891
+ sum |= (bin.charCodeAt(idx + i) << Math.abs(mv + i*8));
6892
+ }
6876
6893
 
6877
- if (control.IsVersionSupported(version)) {
6878
- isVersionSupported = true;
6894
+ return sum;
6895
+ }
6896
+
6897
+ function putstr(segment, idx, length) {
6898
+ length = arguments.length === 3 ? length : bin.length - idx - 1;
6899
+ bin = bin.substr(0, idx) + segment + bin.substr(length + idx);
6900
+ }
6901
+
6902
+ function write(idx, num, size) {
6903
+ var str = '', mv = II ? 0 : -8 * (size - 1), i;
6904
+
6905
+ for (i = 0; i < size; i++) {
6906
+ str += String.fromCharCode((num >> Math.abs(mv + i*8)) & 255);
6907
+ }
6908
+
6909
+ putstr(str, idx, size);
6910
+ }
6911
+
6912
+ // Public functions
6913
+ return {
6914
+ II: function(order) {
6915
+ if (order === undefined) {
6916
+ return II;
6917
+ } else {
6918
+ II = order;
6919
+ }
6920
+ },
6921
+
6922
+ init: function(binData) {
6923
+ II = false;
6924
+ bin = binData;
6925
+ },
6926
+
6927
+ SEGMENT: function(idx, length, segment) {
6928
+ switch (arguments.length) {
6929
+ case 1:
6930
+ return bin.substr(idx, bin.length - idx - 1);
6931
+ case 2:
6932
+ return bin.substr(idx, length);
6933
+ case 3:
6934
+ putstr(segment, idx, length);
6935
+ break;
6936
+ default: return bin;
6937
+ }
6938
+ },
6939
+
6940
+ BYTE: function(idx) {
6941
+ return read(idx, 1);
6942
+ },
6943
+
6944
+ SHORT: function(idx) {
6945
+ return read(idx, 2);
6946
+ },
6947
+
6948
+ LONG: function(idx, num) {
6949
+ if (num === undefined) {
6950
+ return read(idx, 4);
6951
+ } else {
6952
+ write(idx, num, 4);
6953
+ }
6954
+ },
6955
+
6956
+ SLONG: function(idx) { // 2's complement notation
6957
+ var num = read(idx, 4);
6958
+
6959
+ return (num > 2147483647 ? num - 4294967296 : num);
6960
+ },
6961
+
6962
+ STRING: function(idx, size) {
6963
+ var str = '';
6964
+
6965
+ for (size += idx; idx < size; idx++) {
6966
+ str += String.fromCharCode(read(idx, 1));
6967
+ }
6968
+
6969
+ return str;
6970
+ }
6971
+ };
6972
+ };
6973
+ });
6974
+
6975
+ // Included from: src/javascript/runtime/html5/image/JPEGHeaders.js
6976
+
6977
+ /**
6978
+ * JPEGHeaders.js
6979
+ *
6980
+ * Copyright 2013, Moxiecode Systems AB
6981
+ * Released under GPL License.
6982
+ *
6983
+ * License: http://www.plupload.com/license
6984
+ * Contributing: http://www.plupload.com/contributing
6985
+ */
6986
+
6987
+ /**
6988
+ @class moxie/runtime/html5/image/JPEGHeaders
6989
+ @private
6990
+ */
6991
+ define("moxie/runtime/html5/image/JPEGHeaders", [
6992
+ "moxie/runtime/html5/utils/BinaryReader"
6993
+ ], function(BinaryReader) {
6994
+
6995
+ return function JPEGHeaders(data) {
6996
+ var headers = [], read, idx, marker, length = 0;
6997
+
6998
+ read = new BinaryReader();
6999
+ read.init(data);
7000
+
7001
+ // Check if data is jpeg
7002
+ if (read.SHORT(0) !== 0xFFD8) {
7003
+ return;
7004
+ }
7005
+
7006
+ idx = 2;
7007
+
7008
+ while (idx <= data.length) {
7009
+ marker = read.SHORT(idx);
7010
+
7011
+ // omit RST (restart) markers
7012
+ if (marker >= 0xFFD0 && marker <= 0xFFD7) {
7013
+ idx += 2;
7014
+ continue;
7015
+ }
7016
+
7017
+ // no headers allowed after SOS marker
7018
+ if (marker === 0xFFDA || marker === 0xFFD9) {
7019
+ break;
7020
+ }
7021
+
7022
+ length = read.SHORT(idx + 2) + 2;
7023
+
7024
+ // APPn marker detected
7025
+ if (marker >= 0xFFE1 && marker <= 0xFFEF) {
7026
+ headers.push({
7027
+ hex: marker,
7028
+ name: 'APP' + (marker & 0x000F),
7029
+ start: idx,
7030
+ length: length,
7031
+ segment: read.SEGMENT(idx, length)
7032
+ });
7033
+ }
7034
+
7035
+ idx += length;
7036
+ }
7037
+
7038
+ read.init(null); // free memory
7039
+
7040
+ return {
7041
+ headers: headers,
7042
+
7043
+ restore: function(data) {
7044
+ var max, i;
7045
+
7046
+ read.init(data);
7047
+
7048
+ idx = read.SHORT(2) == 0xFFE0 ? 4 + read.SHORT(4) : 2;
7049
+
7050
+ for (i = 0, max = headers.length; i < max; i++) {
7051
+ read.SEGMENT(idx, 0, headers[i].segment);
7052
+ idx += headers[i].length;
7053
+ }
7054
+
7055
+ data = read.SEGMENT();
7056
+ read.init(null);
7057
+ return data;
7058
+ },
7059
+
7060
+ strip: function(data) {
7061
+ var headers, jpegHeaders, i;
7062
+
7063
+ jpegHeaders = new JPEGHeaders(data);
7064
+ headers = jpegHeaders.headers;
7065
+ jpegHeaders.purge();
7066
+
7067
+ read.init(data);
7068
+
7069
+ i = headers.length;
7070
+ while (i--) {
7071
+ read.SEGMENT(headers[i].start, headers[i].length, '');
7072
+ }
7073
+
7074
+ data = read.SEGMENT();
7075
+ read.init(null);
7076
+ return data;
7077
+ },
7078
+
7079
+ get: function(name) {
7080
+ var array = [];
7081
+
7082
+ for (var i = 0, max = headers.length; i < max; i++) {
7083
+ if (headers[i].name === name.toUpperCase()) {
7084
+ array.push(headers[i].segment);
7085
+ }
7086
+ }
7087
+ return array;
7088
+ },
7089
+
7090
+ set: function(name, segment) {
7091
+ var array = [], i, ii, max;
7092
+
7093
+ if (typeof(segment) === 'string') {
7094
+ array.push(segment);
7095
+ } else {
7096
+ array = segment;
7097
+ }
7098
+
7099
+ for (i = ii = 0, max = headers.length; i < max; i++) {
7100
+ if (headers[i].name === name.toUpperCase()) {
7101
+ headers[i].segment = array[ii];
7102
+ headers[i].length = array[ii].length;
7103
+ ii++;
7104
+ }
7105
+ if (ii >= array.length) {
7106
+ break;
7107
+ }
7108
+ }
7109
+ },
7110
+
7111
+ purge: function() {
7112
+ headers = [];
7113
+ read.init(null);
7114
+ read = null;
7115
+ }
7116
+ };
7117
+ };
7118
+ });
7119
+
7120
+ // Included from: src/javascript/runtime/html5/image/ExifParser.js
7121
+
7122
+ /**
7123
+ * ExifParser.js
7124
+ *
7125
+ * Copyright 2013, Moxiecode Systems AB
7126
+ * Released under GPL License.
7127
+ *
7128
+ * License: http://www.plupload.com/license
7129
+ * Contributing: http://www.plupload.com/contributing
7130
+ */
7131
+
7132
+ /**
7133
+ @class moxie/runtime/html5/image/ExifParser
7134
+ @private
7135
+ */
7136
+ define("moxie/runtime/html5/image/ExifParser", [
7137
+ "moxie/core/utils/Basic",
7138
+ "moxie/runtime/html5/utils/BinaryReader"
7139
+ ], function(Basic, BinaryReader) {
7140
+
7141
+ return function ExifParser() {
7142
+ // Private ExifParser fields
7143
+ var data, tags, Tiff, offsets = {}, tagDescs;
7144
+
7145
+ data = new BinaryReader();
7146
+
7147
+ tags = {
7148
+ tiff : {
7149
+ /*
7150
+ The image orientation viewed in terms of rows and columns.
7151
+
7152
+ 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
7153
+ 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
7154
+ 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
7155
+ 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
7156
+ 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
7157
+ 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
7158
+ 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
7159
+ 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
7160
+ */
7161
+ 0x0112: 'Orientation',
7162
+ 0x010E: 'ImageDescription',
7163
+ 0x010F: 'Make',
7164
+ 0x0110: 'Model',
7165
+ 0x0131: 'Software',
7166
+ 0x8769: 'ExifIFDPointer',
7167
+ 0x8825: 'GPSInfoIFDPointer'
7168
+ },
7169
+ exif : {
7170
+ 0x9000: 'ExifVersion',
7171
+ 0xA001: 'ColorSpace',
7172
+ 0xA002: 'PixelXDimension',
7173
+ 0xA003: 'PixelYDimension',
7174
+ 0x9003: 'DateTimeOriginal',
7175
+ 0x829A: 'ExposureTime',
7176
+ 0x829D: 'FNumber',
7177
+ 0x8827: 'ISOSpeedRatings',
7178
+ 0x9201: 'ShutterSpeedValue',
7179
+ 0x9202: 'ApertureValue' ,
7180
+ 0x9207: 'MeteringMode',
7181
+ 0x9208: 'LightSource',
7182
+ 0x9209: 'Flash',
7183
+ 0x920A: 'FocalLength',
7184
+ 0xA402: 'ExposureMode',
7185
+ 0xA403: 'WhiteBalance',
7186
+ 0xA406: 'SceneCaptureType',
7187
+ 0xA404: 'DigitalZoomRatio',
7188
+ 0xA408: 'Contrast',
7189
+ 0xA409: 'Saturation',
7190
+ 0xA40A: 'Sharpness'
7191
+ },
7192
+ gps : {
7193
+ 0x0000: 'GPSVersionID',
7194
+ 0x0001: 'GPSLatitudeRef',
7195
+ 0x0002: 'GPSLatitude',
7196
+ 0x0003: 'GPSLongitudeRef',
7197
+ 0x0004: 'GPSLongitude'
7198
+ }
7199
+ };
7200
+
7201
+ tagDescs = {
7202
+ 'ColorSpace': {
7203
+ 1: 'sRGB',
7204
+ 0: 'Uncalibrated'
7205
+ },
7206
+
7207
+ 'MeteringMode': {
7208
+ 0: 'Unknown',
7209
+ 1: 'Average',
7210
+ 2: 'CenterWeightedAverage',
7211
+ 3: 'Spot',
7212
+ 4: 'MultiSpot',
7213
+ 5: 'Pattern',
7214
+ 6: 'Partial',
7215
+ 255: 'Other'
7216
+ },
7217
+
7218
+ 'LightSource': {
7219
+ 1: 'Daylight',
7220
+ 2: 'Fliorescent',
7221
+ 3: 'Tungsten',
7222
+ 4: 'Flash',
7223
+ 9: 'Fine weather',
7224
+ 10: 'Cloudy weather',
7225
+ 11: 'Shade',
7226
+ 12: 'Daylight fluorescent (D 5700 - 7100K)',
7227
+ 13: 'Day white fluorescent (N 4600 -5400K)',
7228
+ 14: 'Cool white fluorescent (W 3900 - 4500K)',
7229
+ 15: 'White fluorescent (WW 3200 - 3700K)',
7230
+ 17: 'Standard light A',
7231
+ 18: 'Standard light B',
7232
+ 19: 'Standard light C',
7233
+ 20: 'D55',
7234
+ 21: 'D65',
7235
+ 22: 'D75',
7236
+ 23: 'D50',
7237
+ 24: 'ISO studio tungsten',
7238
+ 255: 'Other'
7239
+ },
7240
+
7241
+ 'Flash': {
7242
+ 0x0000: 'Flash did not fire.',
7243
+ 0x0001: 'Flash fired.',
7244
+ 0x0005: 'Strobe return light not detected.',
7245
+ 0x0007: 'Strobe return light detected.',
7246
+ 0x0009: 'Flash fired, compulsory flash mode',
7247
+ 0x000D: 'Flash fired, compulsory flash mode, return light not detected',
7248
+ 0x000F: 'Flash fired, compulsory flash mode, return light detected',
7249
+ 0x0010: 'Flash did not fire, compulsory flash mode',
7250
+ 0x0018: 'Flash did not fire, auto mode',
7251
+ 0x0019: 'Flash fired, auto mode',
7252
+ 0x001D: 'Flash fired, auto mode, return light not detected',
7253
+ 0x001F: 'Flash fired, auto mode, return light detected',
7254
+ 0x0020: 'No flash function',
7255
+ 0x0041: 'Flash fired, red-eye reduction mode',
7256
+ 0x0045: 'Flash fired, red-eye reduction mode, return light not detected',
7257
+ 0x0047: 'Flash fired, red-eye reduction mode, return light detected',
7258
+ 0x0049: 'Flash fired, compulsory flash mode, red-eye reduction mode',
7259
+ 0x004D: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light not detected',
7260
+ 0x004F: 'Flash fired, compulsory flash mode, red-eye reduction mode, return light detected',
7261
+ 0x0059: 'Flash fired, auto mode, red-eye reduction mode',
7262
+ 0x005D: 'Flash fired, auto mode, return light not detected, red-eye reduction mode',
7263
+ 0x005F: 'Flash fired, auto mode, return light detected, red-eye reduction mode'
7264
+ },
7265
+
7266
+ 'ExposureMode': {
7267
+ 0: 'Auto exposure',
7268
+ 1: 'Manual exposure',
7269
+ 2: 'Auto bracket'
7270
+ },
7271
+
7272
+ 'WhiteBalance': {
7273
+ 0: 'Auto white balance',
7274
+ 1: 'Manual white balance'
7275
+ },
7276
+
7277
+ 'SceneCaptureType': {
7278
+ 0: 'Standard',
7279
+ 1: 'Landscape',
7280
+ 2: 'Portrait',
7281
+ 3: 'Night scene'
7282
+ },
7283
+
7284
+ 'Contrast': {
7285
+ 0: 'Normal',
7286
+ 1: 'Soft',
7287
+ 2: 'Hard'
7288
+ },
7289
+
7290
+ 'Saturation': {
7291
+ 0: 'Normal',
7292
+ 1: 'Low saturation',
7293
+ 2: 'High saturation'
7294
+ },
7295
+
7296
+ 'Sharpness': {
7297
+ 0: 'Normal',
7298
+ 1: 'Soft',
7299
+ 2: 'Hard'
7300
+ },
7301
+
7302
+ // GPS related
7303
+ 'GPSLatitudeRef': {
7304
+ N: 'North latitude',
7305
+ S: 'South latitude'
7306
+ },
7307
+
7308
+ 'GPSLongitudeRef': {
7309
+ E: 'East longitude',
7310
+ W: 'West longitude'
7311
+ }
7312
+ };
7313
+
7314
+ function extractTags(IFD_offset, tags2extract) {
7315
+ var length = data.SHORT(IFD_offset), i, ii,
7316
+ tag, type, count, tagOffset, offset, value, values = [], hash = {};
7317
+
7318
+ for (i = 0; i < length; i++) {
7319
+ // Set binary reader pointer to beginning of the next tag
7320
+ offset = tagOffset = IFD_offset + 12 * i + 2;
7321
+
7322
+ tag = tags2extract[data.SHORT(offset)];
7323
+
7324
+ if (tag === undefined) {
7325
+ continue; // Not the tag we requested
7326
+ }
7327
+
7328
+ type = data.SHORT(offset+=2);
7329
+ count = data.LONG(offset+=2);
7330
+
7331
+ offset += 4;
7332
+ values = [];
7333
+
7334
+ switch (type) {
7335
+ case 1: // BYTE
7336
+ case 7: // UNDEFINED
7337
+ if (count > 4) {
7338
+ offset = data.LONG(offset) + offsets.tiffHeader;
7339
+ }
7340
+
7341
+ for (ii = 0; ii < count; ii++) {
7342
+ values[ii] = data.BYTE(offset + ii);
7343
+ }
7344
+
7345
+ break;
7346
+
7347
+ case 2: // STRING
7348
+ if (count > 4) {
7349
+ offset = data.LONG(offset) + offsets.tiffHeader;
7350
+ }
7351
+
7352
+ hash[tag] = data.STRING(offset, count - 1);
7353
+
7354
+ continue;
7355
+
7356
+ case 3: // SHORT
7357
+ if (count > 2) {
7358
+ offset = data.LONG(offset) + offsets.tiffHeader;
7359
+ }
7360
+
7361
+ for (ii = 0; ii < count; ii++) {
7362
+ values[ii] = data.SHORT(offset + ii*2);
7363
+ }
7364
+
7365
+ break;
7366
+
7367
+ case 4: // LONG
7368
+ if (count > 1) {
7369
+ offset = data.LONG(offset) + offsets.tiffHeader;
7370
+ }
7371
+
7372
+ for (ii = 0; ii < count; ii++) {
7373
+ values[ii] = data.LONG(offset + ii*4);
7374
+ }
7375
+
7376
+ break;
7377
+
7378
+ case 5: // RATIONAL
7379
+ offset = data.LONG(offset) + offsets.tiffHeader;
7380
+
7381
+ for (ii = 0; ii < count; ii++) {
7382
+ values[ii] = data.LONG(offset + ii*4) / data.LONG(offset + ii*4 + 4);
7383
+ }
7384
+
7385
+ break;
7386
+
7387
+ case 9: // SLONG
7388
+ offset = data.LONG(offset) + offsets.tiffHeader;
7389
+
7390
+ for (ii = 0; ii < count; ii++) {
7391
+ values[ii] = data.SLONG(offset + ii*4);
7392
+ }
7393
+
7394
+ break;
7395
+
7396
+ case 10: // SRATIONAL
7397
+ offset = data.LONG(offset) + offsets.tiffHeader;
7398
+
7399
+ for (ii = 0; ii < count; ii++) {
7400
+ values[ii] = data.SLONG(offset + ii*4) / data.SLONG(offset + ii*4 + 4);
7401
+ }
7402
+
7403
+ break;
7404
+
7405
+ default:
7406
+ continue;
7407
+ }
7408
+
7409
+ value = (count == 1 ? values[0] : values);
7410
+
7411
+ if (tagDescs.hasOwnProperty(tag) && typeof value != 'object') {
7412
+ hash[tag] = tagDescs[tag][value];
7413
+ } else {
7414
+ hash[tag] = value;
7415
+ }
7416
+ }
7417
+
7418
+ return hash;
7419
+ }
7420
+
7421
+ function getIFDOffsets() {
7422
+ var idx = offsets.tiffHeader;
7423
+
7424
+ // Set read order of multi-byte data
7425
+ data.II(data.SHORT(idx) == 0x4949);
7426
+
7427
+ // Check if always present bytes are indeed present
7428
+ if (data.SHORT(idx+=2) !== 0x002A) {
7429
+ return false;
7430
+ }
7431
+
7432
+ offsets.IFD0 = offsets.tiffHeader + data.LONG(idx += 2);
7433
+ Tiff = extractTags(offsets.IFD0, tags.tiff);
7434
+
7435
+ if ('ExifIFDPointer' in Tiff) {
7436
+ offsets.exifIFD = offsets.tiffHeader + Tiff.ExifIFDPointer;
7437
+ delete Tiff.ExifIFDPointer;
7438
+ }
7439
+
7440
+ if ('GPSInfoIFDPointer' in Tiff) {
7441
+ offsets.gpsIFD = offsets.tiffHeader + Tiff.GPSInfoIFDPointer;
7442
+ delete Tiff.GPSInfoIFDPointer;
7443
+ }
7444
+ return true;
7445
+ }
7446
+
7447
+ // At the moment only setting of simple (LONG) values, that do not require offset recalculation, is supported
7448
+ function setTag(ifd, tag, value) {
7449
+ var offset, length, tagOffset, valueOffset = 0;
7450
+
7451
+ // If tag name passed translate into hex key
7452
+ if (typeof(tag) === 'string') {
7453
+ var tmpTags = tags[ifd.toLowerCase()];
7454
+ for (var hex in tmpTags) {
7455
+ if (tmpTags[hex] === tag) {
7456
+ tag = hex;
7457
+ break;
7458
+ }
7459
+ }
7460
+ }
7461
+ offset = offsets[ifd.toLowerCase() + 'IFD'];
7462
+ length = data.SHORT(offset);
7463
+
7464
+ for (var i = 0; i < length; i++) {
7465
+ tagOffset = offset + 12 * i + 2;
7466
+
7467
+ if (data.SHORT(tagOffset) == tag) {
7468
+ valueOffset = tagOffset + 8;
7469
+ break;
7470
+ }
7471
+ }
7472
+
7473
+ if (!valueOffset) {
7474
+ return false;
7475
+ }
7476
+
7477
+ data.LONG(valueOffset, value);
7478
+ return true;
7479
+ }
7480
+
7481
+
7482
+ // Public functions
7483
+ return {
7484
+ init: function(segment) {
7485
+ // Reset internal data
7486
+ offsets = {
7487
+ tiffHeader: 10
7488
+ };
7489
+
7490
+ if (segment === undefined || !segment.length) {
7491
+ return false;
7492
+ }
7493
+
7494
+ data.init(segment);
7495
+
7496
+ // Check if that's APP1 and that it has EXIF
7497
+ if (data.SHORT(0) === 0xFFE1 && data.STRING(4, 5).toUpperCase() === "EXIF\0") {
7498
+ return getIFDOffsets();
7499
+ }
7500
+ return false;
7501
+ },
7502
+
7503
+ TIFF: function() {
7504
+ return Tiff;
7505
+ },
7506
+
7507
+ EXIF: function() {
7508
+ var Exif;
7509
+
7510
+ // Populate EXIF hash
7511
+ Exif = extractTags(offsets.exifIFD, tags.exif);
7512
+
7513
+ // Fix formatting of some tags
7514
+ if (Exif.ExifVersion && Basic.typeOf(Exif.ExifVersion) === 'array') {
7515
+ for (var i = 0, exifVersion = ''; i < Exif.ExifVersion.length; i++) {
7516
+ exifVersion += String.fromCharCode(Exif.ExifVersion[i]);
7517
+ }
7518
+ Exif.ExifVersion = exifVersion;
7519
+ }
7520
+
7521
+ return Exif;
7522
+ },
7523
+
7524
+ GPS: function() {
7525
+ var GPS;
7526
+
7527
+ GPS = extractTags(offsets.gpsIFD, tags.gps);
7528
+
7529
+ // iOS devices (and probably some others) do not put in GPSVersionID tag (why?..)
7530
+ if (GPS.GPSVersionID && Basic.typeOf(GPS.GPSVersionID) === 'array') {
7531
+ GPS.GPSVersionID = GPS.GPSVersionID.join('.');
7532
+ }
7533
+
7534
+ return GPS;
7535
+ },
7536
+
7537
+ setExif: function(tag, value) {
7538
+ // Right now only setting of width/height is possible
7539
+ if (tag !== 'PixelXDimension' && tag !== 'PixelYDimension') {return false;}
7540
+
7541
+ return setTag('exif', tag, value);
7542
+ },
7543
+
7544
+
7545
+ getBinary: function() {
7546
+ return data.SEGMENT();
7547
+ },
7548
+
7549
+ purge: function() {
7550
+ data.init(null);
7551
+ data = Tiff = null;
7552
+ offsets = {};
7553
+ }
7554
+ };
7555
+ };
7556
+ });
7557
+
7558
+ // Included from: src/javascript/runtime/html5/image/JPEG.js
7559
+
7560
+ /**
7561
+ * JPEG.js
7562
+ *
7563
+ * Copyright 2013, Moxiecode Systems AB
7564
+ * Released under GPL License.
7565
+ *
7566
+ * License: http://www.plupload.com/license
7567
+ * Contributing: http://www.plupload.com/contributing
7568
+ */
7569
+
7570
+ /**
7571
+ @class moxie/runtime/html5/image/JPEG
7572
+ @private
7573
+ */
7574
+ define("moxie/runtime/html5/image/JPEG", [
7575
+ "moxie/core/utils/Basic",
7576
+ "moxie/core/Exceptions",
7577
+ "moxie/runtime/html5/image/JPEGHeaders",
7578
+ "moxie/runtime/html5/utils/BinaryReader",
7579
+ "moxie/runtime/html5/image/ExifParser"
7580
+ ], function(Basic, x, JPEGHeaders, BinaryReader, ExifParser) {
7581
+
7582
+ function JPEG(binstr) {
7583
+ var _binstr, _br, _hm, _ep, _info, hasExif;
7584
+
7585
+ function _getDimensions() {
7586
+ var idx = 0, marker, length;
7587
+
7588
+ // examine all through the end, since some images might have very large APP segments
7589
+ while (idx <= _binstr.length) {
7590
+ marker = _br.SHORT(idx += 2);
7591
+
7592
+ if (marker >= 0xFFC0 && marker <= 0xFFC3) { // SOFn
7593
+ idx += 5; // marker (2 bytes) + length (2 bytes) + Sample precision (1 byte)
7594
+ return {
7595
+ height: _br.SHORT(idx),
7596
+ width: _br.SHORT(idx += 2)
7597
+ };
7598
+ }
7599
+ length = _br.SHORT(idx += 2);
7600
+ idx += length - 2;
7601
+ }
7602
+ return null;
7603
+ }
7604
+
7605
+ _binstr = binstr;
7606
+
7607
+ _br = new BinaryReader();
7608
+ _br.init(_binstr);
7609
+
7610
+ // check if it is jpeg
7611
+ if (_br.SHORT(0) !== 0xFFD8) {
7612
+ throw new x.ImageError(x.ImageError.WRONG_FORMAT);
7613
+ }
7614
+
7615
+ // backup headers
7616
+ _hm = new JPEGHeaders(binstr);
7617
+
7618
+ // extract exif info
7619
+ _ep = new ExifParser();
7620
+ hasExif = !!_ep.init(_hm.get('app1')[0]);
7621
+
7622
+ // get dimensions
7623
+ _info = _getDimensions.call(this);
7624
+
7625
+ Basic.extend(this, {
7626
+ type: 'image/jpeg',
7627
+
7628
+ size: _binstr.length,
7629
+
7630
+ width: _info && _info.width || 0,
7631
+
7632
+ height: _info && _info.height || 0,
7633
+
7634
+ setExif: function(tag, value) {
7635
+ if (!hasExif) {
7636
+ return false; // or throw an exception
7637
+ }
7638
+
7639
+ if (Basic.typeOf(tag) === 'object') {
7640
+ Basic.each(tag, function(value, tag) {
7641
+ _ep.setExif(tag, value);
7642
+ });
7643
+ } else {
7644
+ _ep.setExif(tag, value);
7645
+ }
7646
+
7647
+ // update internal headers
7648
+ _hm.set('app1', _ep.getBinary());
7649
+ },
7650
+
7651
+ writeHeaders: function() {
7652
+ if (!arguments.length) {
7653
+ // if no arguments passed, update headers internally
7654
+ return (_binstr = _hm.restore(_binstr));
7655
+ }
7656
+ return _hm.restore(arguments[0]);
7657
+ },
7658
+
7659
+ stripHeaders: function(binstr) {
7660
+ return _hm.strip(binstr);
7661
+ },
7662
+
7663
+ purge: function() {
7664
+ _purge.call(this);
7665
+ }
7666
+ });
7667
+
7668
+ if (hasExif) {
7669
+ this.meta = {
7670
+ tiff: _ep.TIFF(),
7671
+ exif: _ep.EXIF(),
7672
+ gps: _ep.GPS()
7673
+ };
7674
+ }
7675
+
7676
+ function _purge() {
7677
+ if (!_ep || !_hm || !_br) {
7678
+ return; // ignore any repeating purge requests
7679
+ }
7680
+ _ep.purge();
7681
+ _hm.purge();
7682
+ _br.init(null);
7683
+ _binstr = _info = _hm = _ep = _br = null;
7684
+ }
7685
+ }
7686
+
7687
+ return JPEG;
7688
+ });
7689
+
7690
+ // Included from: src/javascript/runtime/html5/image/PNG.js
7691
+
7692
+ /**
7693
+ * PNG.js
7694
+ *
7695
+ * Copyright 2013, Moxiecode Systems AB
7696
+ * Released under GPL License.
7697
+ *
7698
+ * License: http://www.plupload.com/license
7699
+ * Contributing: http://www.plupload.com/contributing
7700
+ */
7701
+
7702
+ /**
7703
+ @class moxie/runtime/html5/image/PNG
7704
+ @private
7705
+ */
7706
+ define("moxie/runtime/html5/image/PNG", [
7707
+ "moxie/core/Exceptions",
7708
+ "moxie/core/utils/Basic",
7709
+ "moxie/runtime/html5/utils/BinaryReader"
7710
+ ], function(x, Basic, BinaryReader) {
7711
+
7712
+ function PNG(binstr) {
7713
+ var _binstr, _br, _hm, _ep, _info;
7714
+
7715
+ _binstr = binstr;
7716
+
7717
+ _br = new BinaryReader();
7718
+ _br.init(_binstr);
7719
+
7720
+ // check if it's png
7721
+ (function() {
7722
+ var idx = 0, i = 0
7723
+ , signature = [0x8950, 0x4E47, 0x0D0A, 0x1A0A]
7724
+ ;
7725
+
7726
+ for (i = 0; i < signature.length; i++, idx += 2) {
7727
+ if (signature[i] != _br.SHORT(idx)) {
7728
+ throw new x.ImageError(x.ImageError.WRONG_FORMAT);
6879
7729
  }
7730
+ }
7731
+ }());
7732
+
7733
+ function _getDimensions() {
7734
+ var chunk, idx;
7735
+
7736
+ chunk = _getChunkAt.call(this, 8);
6880
7737
 
6881
- control = null;
6882
- } catch (e) {
6883
- var plugin = navigator.plugins["Silverlight Plug-In"];
7738
+ if (chunk.type == 'IHDR') {
7739
+ idx = chunk.start;
7740
+ return {
7741
+ width: _br.LONG(idx),
7742
+ height: _br.LONG(idx += 4)
7743
+ };
7744
+ }
7745
+ return null;
7746
+ }
6884
7747
 
6885
- if (plugin) {
6886
- actualVer = plugin.description;
7748
+ function _purge() {
7749
+ if (!_br) {
7750
+ return; // ignore any repeating purge requests
7751
+ }
7752
+ _br.init(null);
7753
+ _binstr = _info = _hm = _ep = _br = null;
7754
+ }
6887
7755
 
6888
- if (actualVer === "1.0.30226.2") {
6889
- actualVer = "2.0.30226.2";
6890
- }
7756
+ _info = _getDimensions.call(this);
6891
7757
 
6892
- actualVerArray = actualVer.split(".");
7758
+ Basic.extend(this, {
7759
+ type: 'image/png',
6893
7760
 
6894
- while (actualVerArray.length > 3) {
6895
- actualVerArray.pop();
6896
- }
7761
+ size: _binstr.length,
6897
7762
 
6898
- while ( actualVerArray.length < 4) {
6899
- actualVerArray.push(0);
6900
- }
7763
+ width: _info.width,
6901
7764
 
6902
- reqVerArray = version.split(".");
7765
+ height: _info.height,
6903
7766
 
6904
- while (reqVerArray.length > 4) {
6905
- reqVerArray.pop();
6906
- }
7767
+ purge: function() {
7768
+ _purge.call(this);
7769
+ }
7770
+ });
6907
7771
 
6908
- do {
6909
- requiredVersionPart = parseInt(reqVerArray[index], 10);
6910
- actualVersionPart = parseInt(actualVerArray[index], 10);
6911
- index++;
6912
- } while (index < reqVerArray.length && requiredVersionPart === actualVersionPart);
7772
+ // for PNG we can safely trigger purge automatically, as we do not keep any data for later
7773
+ _purge.call(this);
6913
7774
 
6914
- if (requiredVersionPart <= actualVersionPart && !isNaN(requiredVersionPart)) {
6915
- isVersionSupported = true;
6916
- }
7775
+ function _getChunkAt(idx) {
7776
+ var length, type, start, CRC;
7777
+
7778
+ length = _br.LONG(idx);
7779
+ type = _br.STRING(idx += 4, 4);
7780
+ start = idx += 4;
7781
+ CRC = _br.LONG(idx + length);
7782
+
7783
+ return {
7784
+ length: length,
7785
+ type: type,
7786
+ start: start,
7787
+ CRC: CRC
7788
+ };
7789
+ }
7790
+ }
7791
+
7792
+ return PNG;
7793
+ });
7794
+
7795
+ // Included from: src/javascript/runtime/html5/image/ImageInfo.js
7796
+
7797
+ /**
7798
+ * ImageInfo.js
7799
+ *
7800
+ * Copyright 2013, Moxiecode Systems AB
7801
+ * Released under GPL License.
7802
+ *
7803
+ * License: http://www.plupload.com/license
7804
+ * Contributing: http://www.plupload.com/contributing
7805
+ */
7806
+
7807
+ /**
7808
+ @class moxie/runtime/html5/image/ImageInfo
7809
+ @private
7810
+ */
7811
+ define("moxie/runtime/html5/image/ImageInfo", [
7812
+ "moxie/core/utils/Basic",
7813
+ "moxie/core/Exceptions",
7814
+ "moxie/runtime/html5/image/JPEG",
7815
+ "moxie/runtime/html5/image/PNG"
7816
+ ], function(Basic, x, JPEG, PNG) {
7817
+ /**
7818
+ Optional image investigation tool for HTML5 runtime. Provides the following features:
7819
+ - ability to distinguish image type (JPEG or PNG) by signature
7820
+ - ability to extract image width/height directly from it's internals, without preloading in memory (fast)
7821
+ - ability to extract APP headers from JPEGs (Exif, GPS, etc)
7822
+ - ability to replace width/height tags in extracted JPEG headers
7823
+ - ability to restore APP headers, that were for example stripped during image manipulation
7824
+
7825
+ @class ImageInfo
7826
+ @constructor
7827
+ @param {String} binstr Image source as binary string
7828
+ */
7829
+ return function(binstr) {
7830
+ var _cs = [JPEG, PNG], _img;
7831
+
7832
+ // figure out the format, throw: ImageError.WRONG_FORMAT if not supported
7833
+ _img = (function() {
7834
+ for (var i = 0; i < _cs.length; i++) {
7835
+ try {
7836
+ return new _cs[i](binstr);
7837
+ } catch (ex) {
7838
+ // console.info(ex);
6917
7839
  }
6918
7840
  }
6919
- } catch (e2) {
6920
- isVersionSupported = false;
7841
+ throw new x.ImageError(x.ImageError.WRONG_FORMAT);
7842
+ }());
7843
+
7844
+ Basic.extend(this, {
7845
+ /**
7846
+ Image Mime Type extracted from it's depths
7847
+
7848
+ @property type
7849
+ @type {String}
7850
+ @default ''
7851
+ */
7852
+ type: '',
7853
+
7854
+ /**
7855
+ Image size in bytes
7856
+
7857
+ @property size
7858
+ @type {Number}
7859
+ @default 0
7860
+ */
7861
+ size: 0,
7862
+
7863
+ /**
7864
+ Image width extracted from image source
7865
+
7866
+ @property width
7867
+ @type {Number}
7868
+ @default 0
7869
+ */
7870
+ width: 0,
7871
+
7872
+ /**
7873
+ Image height extracted from image source
7874
+
7875
+ @property height
7876
+ @type {Number}
7877
+ @default 0
7878
+ */
7879
+ height: 0,
7880
+
7881
+ /**
7882
+ Sets Exif tag. Currently applicable only for width and height tags. Obviously works only with JPEGs.
7883
+
7884
+ @method setExif
7885
+ @param {String} tag Tag to set
7886
+ @param {Mixed} value Value to assign to the tag
7887
+ */
7888
+ setExif: function() {},
7889
+
7890
+ /**
7891
+ Restores headers to the source.
7892
+
7893
+ @method writeHeaders
7894
+ @param {String} data Image source as binary string
7895
+ @return {String} Updated binary string
7896
+ */
7897
+ writeHeaders: function(data) {
7898
+ return data;
7899
+ },
7900
+
7901
+ /**
7902
+ Strip all headers from the source.
7903
+
7904
+ @method stripHeaders
7905
+ @param {String} data Image source as binary string
7906
+ @return {String} Updated binary string
7907
+ */
7908
+ stripHeaders: function(data) {
7909
+ return data;
7910
+ },
7911
+
7912
+ /**
7913
+ Dispose resources.
7914
+
7915
+ @method purge
7916
+ */
7917
+ purge: function() {}
7918
+ });
7919
+
7920
+ Basic.extend(this, _img);
7921
+
7922
+ this.purge = function() {
7923
+ _img.purge();
7924
+ _img = null;
7925
+ };
7926
+ };
7927
+ });
7928
+
7929
+ // Included from: src/javascript/runtime/html5/image/MegaPixel.js
7930
+
7931
+ /**
7932
+ (The MIT License)
7933
+
7934
+ Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com>;
7935
+
7936
+ Permission is hereby granted, free of charge, to any person obtaining
7937
+ a copy of this software and associated documentation files (the
7938
+ 'Software'), to deal in the Software without restriction, including
7939
+ without limitation the rights to use, copy, modify, merge, publish,
7940
+ distribute, sublicense, and/or sell copies of the Software, and to
7941
+ permit persons to whom the Software is furnished to do so, subject to
7942
+ the following conditions:
7943
+
7944
+ The above copyright notice and this permission notice shall be
7945
+ included in all copies or substantial portions of the Software.
7946
+
7947
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
7948
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
7949
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
7950
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
7951
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
7952
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
7953
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
7954
+ */
7955
+
7956
+ /**
7957
+ * Mega pixel image rendering library for iOS6 Safari
7958
+ *
7959
+ * Fixes iOS6 Safari's image file rendering issue for large size image (over mega-pixel),
7960
+ * which causes unexpected subsampling when drawing it in canvas.
7961
+ * By using this library, you can safely render the image with proper stretching.
7962
+ *
7963
+ * Copyright (c) 2012 Shinichi Tomita <shinichi.tomita@gmail.com>
7964
+ * Released under the MIT license
7965
+ */
7966
+
7967
+ /**
7968
+ @class moxie/runtime/html5/image/MegaPixel
7969
+ @private
7970
+ */
7971
+ define("moxie/runtime/html5/image/MegaPixel", [], function() {
7972
+
7973
+ /**
7974
+ * Rendering image element (with resizing) into the canvas element
7975
+ */
7976
+ function renderImageToCanvas(img, canvas, options) {
7977
+ var iw = img.naturalWidth, ih = img.naturalHeight;
7978
+ var width = options.width, height = options.height;
7979
+ var x = options.x || 0, y = options.y || 0;
7980
+ var ctx = canvas.getContext('2d');
7981
+ if (detectSubsampling(img)) {
7982
+ iw /= 2;
7983
+ ih /= 2;
7984
+ }
7985
+ var d = 1024; // size of tiling canvas
7986
+ var tmpCanvas = document.createElement('canvas');
7987
+ tmpCanvas.width = tmpCanvas.height = d;
7988
+ var tmpCtx = tmpCanvas.getContext('2d');
7989
+ var vertSquashRatio = detectVerticalSquash(img, iw, ih);
7990
+ var sy = 0;
7991
+ while (sy < ih) {
7992
+ var sh = sy + d > ih ? ih - sy : d;
7993
+ var sx = 0;
7994
+ while (sx < iw) {
7995
+ var sw = sx + d > iw ? iw - sx : d;
7996
+ tmpCtx.clearRect(0, 0, d, d);
7997
+ tmpCtx.drawImage(img, -sx, -sy);
7998
+ var dx = (sx * width / iw + x) << 0;
7999
+ var dw = Math.ceil(sw * width / iw);
8000
+ var dy = (sy * height / ih / vertSquashRatio + y) << 0;
8001
+ var dh = Math.ceil(sh * height / ih / vertSquashRatio);
8002
+ ctx.drawImage(tmpCanvas, 0, 0, sw, sh, dx, dy, dw, dh);
8003
+ sx += d;
8004
+ }
8005
+ sy += d;
6921
8006
  }
8007
+ tmpCanvas = tmpCtx = null;
8008
+ }
6922
8009
 
6923
- return isVersionSupported;
8010
+ /**
8011
+ * Detect subsampling in loaded image.
8012
+ * In iOS, larger images than 2M pixels may be subsampled in rendering.
8013
+ */
8014
+ function detectSubsampling(img) {
8015
+ var iw = img.naturalWidth, ih = img.naturalHeight;
8016
+ if (iw * ih > 1024 * 1024) { // subsampling may happen over megapixel image
8017
+ var canvas = document.createElement('canvas');
8018
+ canvas.width = canvas.height = 1;
8019
+ var ctx = canvas.getContext('2d');
8020
+ ctx.drawImage(img, -iw + 1, 0);
8021
+ // subsampled image becomes half smaller in rendering size.
8022
+ // check alpha channel value to confirm image is covering edge pixel or not.
8023
+ // if alpha value is 0 image is not covering, hence subsampled.
8024
+ return ctx.getImageData(0, 0, 1, 1).data[3] === 0;
8025
+ } else {
8026
+ return false;
8027
+ }
6924
8028
  }
6925
8029
 
8030
+
6926
8031
  /**
6927
- Constructor for the Silverlight Runtime
8032
+ * Detecting vertical squash in loaded image.
8033
+ * Fixes a bug which squash image vertically while drawing into canvas for some images.
8034
+ */
8035
+ function detectVerticalSquash(img, iw, ih) {
8036
+ var canvas = document.createElement('canvas');
8037
+ canvas.width = 1;
8038
+ canvas.height = ih;
8039
+ var ctx = canvas.getContext('2d');
8040
+ ctx.drawImage(img, 0, 0);
8041
+ var data = ctx.getImageData(0, 0, 1, ih).data;
8042
+ // search image edge pixel position in case it is squashed vertically.
8043
+ var sy = 0;
8044
+ var ey = ih;
8045
+ var py = ih;
8046
+ while (py > sy) {
8047
+ var alpha = data[(py - 1) * 4 + 3];
8048
+ if (alpha === 0) {
8049
+ ey = py;
8050
+ } else {
8051
+ sy = py;
8052
+ }
8053
+ py = (ey + sy) >> 1;
8054
+ }
8055
+ canvas = null;
8056
+ var ratio = (py / ih);
8057
+ return (ratio === 0) ? 1 : ratio;
8058
+ }
6928
8059
 
6929
- @class SilverlightRuntime
6930
- @extends Runtime
6931
- */
6932
- function SilverlightRuntime(options) {
6933
- var I = this, initTimer;
8060
+ return {
8061
+ isSubsampled: detectSubsampling,
8062
+ renderTo: renderImageToCanvas
8063
+ };
8064
+ });
6934
8065
 
6935
- options = Basic.extend({ xap_url: Env.xap_url }, options);
8066
+ // Included from: src/javascript/runtime/html5/image/Image.js
6936
8067
 
6937
- Runtime.call(this, options, type, {
6938
- access_binary: Runtime.capTrue,
6939
- access_image_binary: Runtime.capTrue,
6940
- display_media: Runtime.capTrue,
6941
- do_cors: Runtime.capTrue,
6942
- drag_and_drop: false,
6943
- report_upload_progress: Runtime.capTrue,
6944
- resize_image: Runtime.capTrue,
6945
- return_response_headers: function(value) {
6946
- return value && I.mode === 'client';
6947
- },
6948
- return_response_type: function(responseType) {
6949
- if (responseType !== 'json') {
6950
- return true;
8068
+ /**
8069
+ * Image.js
8070
+ *
8071
+ * Copyright 2013, Moxiecode Systems AB
8072
+ * Released under GPL License.
8073
+ *
8074
+ * License: http://www.plupload.com/license
8075
+ * Contributing: http://www.plupload.com/contributing
8076
+ */
8077
+
8078
+ /**
8079
+ @class moxie/runtime/html5/image/Image
8080
+ @private
8081
+ */
8082
+ define("moxie/runtime/html5/image/Image", [
8083
+ "moxie/runtime/html5/Runtime",
8084
+ "moxie/core/utils/Basic",
8085
+ "moxie/core/Exceptions",
8086
+ "moxie/core/utils/Encode",
8087
+ "moxie/file/File",
8088
+ "moxie/runtime/html5/image/ImageInfo",
8089
+ "moxie/runtime/html5/image/MegaPixel",
8090
+ "moxie/core/utils/Mime",
8091
+ "moxie/core/utils/Env"
8092
+ ], function(extensions, Basic, x, Encode, File, ImageInfo, MegaPixel, Mime, Env) {
8093
+
8094
+ function HTML5Image() {
8095
+ var me = this
8096
+ , _img, _imgInfo, _canvas, _binStr, _blob
8097
+ , _modified = false // is set true whenever image is modified
8098
+ , _preserveHeaders = true
8099
+ ;
8100
+
8101
+ Basic.extend(this, {
8102
+ loadFromBlob: function(blob) {
8103
+ var comp = this, I = comp.getRuntime()
8104
+ , asBinary = arguments.length > 1 ? arguments[1] : true
8105
+ ;
8106
+
8107
+ if (!I.can('access_binary')) {
8108
+ throw new x.RuntimeError(x.RuntimeError.NOT_SUPPORTED_ERR);
8109
+ }
8110
+
8111
+ _blob = blob;
8112
+
8113
+ if (blob.isDetached()) {
8114
+ _binStr = blob.getSource();
8115
+ _preload.call(this, _binStr);
8116
+ return;
6951
8117
  } else {
6952
- return !!window.JSON;
8118
+ _readAsDataUrl.call(this, blob.getSource(), function(dataUrl) {
8119
+ if (asBinary) {
8120
+ _binStr = _toBinary(dataUrl);
8121
+ }
8122
+ _preload.call(comp, dataUrl);
8123
+ });
6953
8124
  }
6954
8125
  },
6955
- return_status_code: function(code) {
6956
- return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]);
8126
+
8127
+ loadFromImage: function(img, exact) {
8128
+ this.meta = img.meta;
8129
+
8130
+ _blob = new File(null, {
8131
+ name: img.name,
8132
+ size: img.size,
8133
+ type: img.type
8134
+ });
8135
+
8136
+ _preload.call(this, exact ? (_binStr = img.getAsBinaryString()) : img.getAsDataURL());
6957
8137
  },
6958
- select_file: Runtime.capTrue,
6959
- select_multiple: Runtime.capTrue,
6960
- send_binary_string: Runtime.capTrue,
6961
- send_browser_cookies: function(value) {
6962
- return value && I.mode === 'browser';
8138
+
8139
+ getInfo: function() {
8140
+ var I = this.getRuntime(), info;
8141
+
8142
+ if (!_imgInfo && _binStr && I.can('access_image_binary')) {
8143
+ _imgInfo = new ImageInfo(_binStr);
8144
+ }
8145
+
8146
+ info = {
8147
+ width: _getImg().width || 0,
8148
+ height: _getImg().height || 0,
8149
+ type: _blob.type || Mime.getFileMime(_blob.name),
8150
+ size: _binStr && _binStr.length || _blob.size || 0,
8151
+ name: _blob.name || '',
8152
+ meta: _imgInfo && _imgInfo.meta || this.meta || {}
8153
+ };
8154
+
8155
+ return info;
6963
8156
  },
6964
- send_custom_headers: function(value) {
6965
- return value && I.mode === 'client';
8157
+
8158
+ downsize: function() {
8159
+ _downsize.apply(this, arguments);
6966
8160
  },
6967
- send_multipart: Runtime.capTrue,
6968
- slice_blob: Runtime.capTrue,
6969
- stream_upload: true,
6970
- summon_file_dialog: false,
6971
- upload_filesize: Runtime.capTrue,
6972
- use_http_method: function(methods) {
6973
- return I.mode === 'client' || !Basic.arrayDiff(methods, ['GET', 'POST']);
6974
- }
6975
- }, {
6976
- // capabilities that require specific mode
6977
- return_response_headers: function(value) {
6978
- return value ? 'client' : 'browser';
8161
+
8162
+ getAsCanvas: function() {
8163
+ if (_canvas) {
8164
+ _canvas.id = this.uid + '_canvas';
8165
+ }
8166
+ return _canvas;
6979
8167
  },
6980
- return_status_code: function(code) {
6981
- return Basic.arrayDiff(code, [200, 404]) ? 'client' : ['client', 'browser'];
8168
+
8169
+ getAsBlob: function(type, quality) {
8170
+ if (type !== this.type) {
8171
+ // if different mime type requested prepare image for conversion
8172
+ _downsize.call(this, this.width, this.height, false);
8173
+ }
8174
+ return new File(null, {
8175
+ name: _blob.name || '',
8176
+ type: type,
8177
+ data: me.getAsBinaryString.call(this, type, quality)
8178
+ });
6982
8179
  },
6983
- send_browser_cookies: function(value) {
6984
- return value ? 'browser' : 'client';
8180
+
8181
+ getAsDataURL: function(type) {
8182
+ var quality = arguments[1] || 90;
8183
+
8184
+ // if image has not been modified, return the source right away
8185
+ if (!_modified) {
8186
+ return _img.src;
8187
+ }
8188
+
8189
+ if ('image/jpeg' !== type) {
8190
+ return _canvas.toDataURL('image/png');
8191
+ } else {
8192
+ try {
8193
+ // older Geckos used to result in an exception on quality argument
8194
+ return _canvas.toDataURL('image/jpeg', quality/100);
8195
+ } catch (ex) {
8196
+ return _canvas.toDataURL('image/jpeg');
8197
+ }
8198
+ }
6985
8199
  },
6986
- send_custom_headers: function(value) {
6987
- return value ? 'client' : 'browser';
8200
+
8201
+ getAsBinaryString: function(type, quality) {
8202
+ // if image has not been modified, return the source right away
8203
+ if (!_modified) {
8204
+ // if image was not loaded from binary string
8205
+ if (!_binStr) {
8206
+ _binStr = _toBinary(me.getAsDataURL(type, quality));
8207
+ }
8208
+ return _binStr;
8209
+ }
8210
+
8211
+ if ('image/jpeg' !== type) {
8212
+ _binStr = _toBinary(me.getAsDataURL(type, quality));
8213
+ } else {
8214
+ var dataUrl;
8215
+
8216
+ // if jpeg
8217
+ if (!quality) {
8218
+ quality = 90;
8219
+ }
8220
+
8221
+ try {
8222
+ // older Geckos used to result in an exception on quality argument
8223
+ dataUrl = _canvas.toDataURL('image/jpeg', quality/100);
8224
+ } catch (ex) {
8225
+ dataUrl = _canvas.toDataURL('image/jpeg');
8226
+ }
8227
+
8228
+ _binStr = _toBinary(dataUrl);
8229
+
8230
+ if (_imgInfo) {
8231
+ _binStr = _imgInfo.stripHeaders(_binStr);
8232
+
8233
+ if (_preserveHeaders) {
8234
+ // update dimensions info in exif
8235
+ if (_imgInfo.meta && _imgInfo.meta.exif) {
8236
+ _imgInfo.setExif({
8237
+ PixelXDimension: this.width,
8238
+ PixelYDimension: this.height
8239
+ });
8240
+ }
8241
+
8242
+ // re-inject the headers
8243
+ _binStr = _imgInfo.writeHeaders(_binStr);
8244
+ }
8245
+
8246
+ // will be re-created from fresh on next getInfo call
8247
+ _imgInfo.purge();
8248
+ _imgInfo = null;
8249
+ }
8250
+ }
8251
+
8252
+ _modified = false;
8253
+
8254
+ return _binStr;
6988
8255
  },
6989
- use_http_method: function(methods) {
6990
- return Basic.arrayDiff(methods, ['GET', 'POST']) ? 'client' : ['client', 'browser'];
8256
+
8257
+ destroy: function() {
8258
+ me = null;
8259
+ _purge.call(this);
8260
+ this.getRuntime().getShim().removeInstance(this.uid);
6991
8261
  }
6992
8262
  });
6993
8263
 
6994
8264
 
6995
- // minimal requirement
6996
- if (!isInstalled('2.0.31005.0') || Env.browser === 'Opera') {
6997
- this.mode = false;
8265
+ function _getImg() {
8266
+ if (!_canvas && !_img) {
8267
+ throw new x.ImageError(x.DOMException.INVALID_STATE_ERR);
8268
+ }
8269
+ return _canvas || _img;
6998
8270
  }
6999
8271
 
7000
8272
 
7001
- Basic.extend(this, {
7002
- getShim: function() {
7003
- return Dom.get(this.uid).content.Moxie;
7004
- },
8273
+ function _toBinary(str) {
8274
+ return Encode.atob(str.substring(str.indexOf('base64,') + 7));
8275
+ }
7005
8276
 
7006
- shimExec: function(component, action) {
7007
- var args = [].slice.call(arguments, 2);
7008
- return I.getShim().exec(this.uid, component, action, args);
7009
- },
7010
8277
 
7011
- init : function() {
7012
- var container;
7013
-
7014
- container = this.getShimContainer();
7015
-
7016
- container.innerHTML = '<object id="' + this.uid + '" data="data:application/x-silverlight," type="application/x-silverlight-2" width="100%" height="100%" style="outline:none;">' +
7017
- '<param name="source" value="' + options.xap_url + '"/>' +
7018
- '<param name="background" value="Transparent"/>' +
7019
- '<param name="windowless" value="true"/>' +
7020
- '<param name="enablehtmlaccess" value="true"/>' +
7021
- '<param name="initParams" value="uid=' + this.uid + ',target=' + Env.global_event_dispatcher + '"/>' +
7022
- '</object>';
7023
-
7024
- // Init is dispatched by the shim
7025
- initTimer = setTimeout(function() {
7026
- if (I && !I.initialized) { // runtime might be already destroyed by this moment
7027
- I.trigger("Error", new x.RuntimeError(x.RuntimeError.NOT_INIT_ERR));
7028
- }
7029
- }, Env.OS !== 'Windows'? 10000 : 5000); // give it more time to initialize in non Windows OS (like Mac)
7030
- },
8278
+ function _toDataUrl(str, type) {
8279
+ return 'data:' + (type || '') + ';base64,' + Encode.btoa(str);
8280
+ }
8281
+
8282
+
8283
+ function _preload(str) {
8284
+ var comp = this;
8285
+
8286
+ _img = new Image();
8287
+ _img.onerror = function() {
8288
+ _purge.call(this);
8289
+ comp.trigger('error', x.ImageError.WRONG_FORMAT);
8290
+ };
8291
+ _img.onload = function() {
8292
+ comp.trigger('load');
8293
+ };
8294
+
8295
+ _img.src = /^data:[^;]*;base64,/.test(str) ? str : _toDataUrl(str, _blob.type);
8296
+ }
8297
+
8298
+
8299
+ function _readAsDataUrl(file, callback) {
8300
+ var comp = this, fr;
8301
+
8302
+ // use FileReader if it's available
8303
+ if (window.FileReader) {
8304
+ fr = new FileReader();
8305
+ fr.onload = function() {
8306
+ callback(this.result);
8307
+ };
8308
+ fr.onerror = function() {
8309
+ comp.trigger('error', x.ImageError.WRONG_FORMAT);
8310
+ };
8311
+ fr.readAsDataURL(file);
8312
+ } else {
8313
+ return callback(file.getAsDataURL());
8314
+ }
8315
+ }
8316
+
8317
+ function _downsize(width, height, crop, preserveHeaders) {
8318
+ var self = this
8319
+ , scale
8320
+ , mathFn
8321
+ , x = 0
8322
+ , y = 0
8323
+ , img
8324
+ , destWidth
8325
+ , destHeight
8326
+ , orientation
8327
+ ;
8328
+
8329
+ _preserveHeaders = preserveHeaders; // we will need to check this on export (see getAsBinaryString())
8330
+
8331
+ // take into account orientation tag
8332
+ orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
8333
+
8334
+ if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation
8335
+ // swap dimensions
8336
+ var tmp = width;
8337
+ width = height;
8338
+ height = tmp;
8339
+ }
8340
+
8341
+ img = _getImg();
8342
+
8343
+ // unify dimensions
8344
+ if (!crop) {
8345
+ scale = Math.min(width/img.width, height/img.height);
8346
+ } else {
8347
+ // one of the dimensions may exceed the actual image dimensions - we need to take the smallest value
8348
+ width = Math.min(width, img.width);
8349
+ height = Math.min(height, img.height);
7031
8350
 
7032
- destroy: (function(destroy) { // extend default destroy method
7033
- return function() {
7034
- destroy.call(I);
7035
- clearTimeout(initTimer); // initialization check might be still onwait
7036
- options = initTimer = destroy = I = null;
7037
- };
7038
- }(this.destroy))
8351
+ scale = Math.max(width/img.width, height/img.height);
8352
+ }
8353
+
8354
+ // we only downsize here
8355
+ if (scale > 1 && !crop && preserveHeaders) {
8356
+ this.trigger('Resize');
8357
+ return;
8358
+ }
7039
8359
 
7040
- }, extensions);
7041
- }
8360
+ // prepare canvas if necessary
8361
+ if (!_canvas) {
8362
+ _canvas = document.createElement("canvas");
8363
+ }
7042
8364
 
7043
- Runtime.addConstructor(type, SilverlightRuntime);
8365
+ // calculate dimensions of proportionally resized image
8366
+ destWidth = Math.round(img.width * scale);
8367
+ destHeight = Math.round(img.height * scale);
7044
8368
 
7045
- return extensions;
7046
- });
8369
+ // scale image and canvas
8370
+ if (crop) {
8371
+ _canvas.width = width;
8372
+ _canvas.height = height;
7047
8373
 
7048
- // Included from: src/javascript/runtime/silverlight/file/Blob.js
8374
+ // if dimensions of the resulting image still larger than canvas, center it
8375
+ if (destWidth > width) {
8376
+ x = Math.round((destWidth - width) / 2);
8377
+ }
7049
8378
 
7050
- /**
7051
- * Blob.js
7052
- *
7053
- * Copyright 2013, Moxiecode Systems AB
7054
- * Released under GPL License.
7055
- *
7056
- * License: http://www.plupload.com/license
7057
- * Contributing: http://www.plupload.com/contributing
7058
- */
8379
+ if (destHeight > height) {
8380
+ y = Math.round((destHeight - height) / 2);
8381
+ }
8382
+ } else {
8383
+ _canvas.width = destWidth;
8384
+ _canvas.height = destHeight;
8385
+ }
7059
8386
 
7060
- /**
7061
- @class moxie/runtime/silverlight/file/Blob
7062
- @private
7063
- */
7064
- define("moxie/runtime/silverlight/file/Blob", [
7065
- "moxie/runtime/silverlight/Runtime",
7066
- "moxie/core/utils/Basic",
7067
- "moxie/runtime/flash/file/Blob"
7068
- ], function(extensions, Basic, Blob) {
7069
- return (extensions.Blob = Basic.extend({}, Blob));
7070
- });
8387
+ // rotate if required, according to orientation tag
8388
+ if (!_preserveHeaders) {
8389
+ _rotateToOrientaion(_canvas.width, _canvas.height, orientation);
8390
+ }
7071
8391
 
7072
- // Included from: src/javascript/runtime/silverlight/file/FileInput.js
8392
+ _drawToCanvas.call(this, img, _canvas, -x, -y, destWidth, destHeight);
7073
8393
 
7074
- /**
7075
- * FileInput.js
7076
- *
7077
- * Copyright 2013, Moxiecode Systems AB
7078
- * Released under GPL License.
7079
- *
7080
- * License: http://www.plupload.com/license
7081
- * Contributing: http://www.plupload.com/contributing
7082
- */
8394
+ this.width = _canvas.width;
8395
+ this.height = _canvas.height;
7083
8396
 
7084
- /**
7085
- @class moxie/runtime/silverlight/file/FileInput
7086
- @private
7087
- */
7088
- define("moxie/runtime/silverlight/file/FileInput", [
7089
- "moxie/runtime/silverlight/Runtime"
7090
- ], function(extensions) {
7091
-
7092
- var FileInput = {
7093
- init: function(options) {
8397
+ _modified = true;
8398
+ self.trigger('Resize');
8399
+ }
7094
8400
 
7095
- function toFilters(accept) {
7096
- var filter = '';
7097
- for (var i = 0; i < accept.length; i++) {
7098
- filter += (filter !== '' ? '|' : '') + accept[i].title + " | *." + accept[i].extensions.replace(/,/g, ';*.');
7099
- }
7100
- return filter;
8401
+
8402
+ function _drawToCanvas(img, canvas, x, y, w, h) {
8403
+ if (Env.OS === 'iOS') {
8404
+ // avoid squish bug in iOS6
8405
+ MegaPixel.renderTo(img, canvas, { width: w, height: h, x: x, y: y });
8406
+ } else {
8407
+ var ctx = canvas.getContext('2d');
8408
+ ctx.drawImage(img, x, y, w, h);
7101
8409
  }
7102
-
7103
- this.getRuntime().shimExec.call(this, 'FileInput', 'init', toFilters(options.accept), options.name, options.multiple);
7104
- this.trigger('ready');
7105
8410
  }
7106
- };
7107
8411
 
7108
- return (extensions.FileInput = FileInput);
7109
- });
7110
8412
 
7111
- // Included from: src/javascript/runtime/silverlight/file/FileReader.js
8413
+ /**
8414
+ * Transform canvas coordination according to specified frame size and orientation
8415
+ * Orientation value is from EXIF tag
8416
+ * @author Shinichi Tomita <shinichi.tomita@gmail.com>
8417
+ */
8418
+ function _rotateToOrientaion(width, height, orientation) {
8419
+ switch (orientation) {
8420
+ case 5:
8421
+ case 6:
8422
+ case 7:
8423
+ case 8:
8424
+ _canvas.width = height;
8425
+ _canvas.height = width;
8426
+ break;
8427
+ default:
8428
+ _canvas.width = width;
8429
+ _canvas.height = height;
8430
+ }
7112
8431
 
7113
- /**
7114
- * FileReader.js
7115
- *
7116
- * Copyright 2013, Moxiecode Systems AB
7117
- * Released under GPL License.
7118
- *
7119
- * License: http://www.plupload.com/license
7120
- * Contributing: http://www.plupload.com/contributing
7121
- */
8432
+ /**
8433
+ 1 = The 0th row is at the visual top of the image, and the 0th column is the visual left-hand side.
8434
+ 2 = The 0th row is at the visual top of the image, and the 0th column is the visual right-hand side.
8435
+ 3 = The 0th row is at the visual bottom of the image, and the 0th column is the visual right-hand side.
8436
+ 4 = The 0th row is at the visual bottom of the image, and the 0th column is the visual left-hand side.
8437
+ 5 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual top.
8438
+ 6 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual top.
8439
+ 7 = The 0th row is the visual right-hand side of the image, and the 0th column is the visual bottom.
8440
+ 8 = The 0th row is the visual left-hand side of the image, and the 0th column is the visual bottom.
8441
+ */
7122
8442
 
7123
- /**
7124
- @class moxie/runtime/silverlight/file/FileReader
7125
- @private
7126
- */
7127
- define("moxie/runtime/silverlight/file/FileReader", [
7128
- "moxie/runtime/silverlight/Runtime",
7129
- "moxie/core/utils/Basic",
7130
- "moxie/runtime/flash/file/FileReader"
7131
- ], function(extensions, Basic, FileReader) {
7132
- return (extensions.FileReader = Basic.extend({}, FileReader));
7133
- });
8443
+ var ctx = _canvas.getContext('2d');
8444
+ switch (orientation) {
8445
+ case 2:
8446
+ // horizontal flip
8447
+ ctx.translate(width, 0);
8448
+ ctx.scale(-1, 1);
8449
+ break;
8450
+ case 3:
8451
+ // 180 rotate left
8452
+ ctx.translate(width, height);
8453
+ ctx.rotate(Math.PI);
8454
+ break;
8455
+ case 4:
8456
+ // vertical flip
8457
+ ctx.translate(0, height);
8458
+ ctx.scale(1, -1);
8459
+ break;
8460
+ case 5:
8461
+ // vertical flip + 90 rotate right
8462
+ ctx.rotate(0.5 * Math.PI);
8463
+ ctx.scale(1, -1);
8464
+ break;
8465
+ case 6:
8466
+ // 90 rotate right
8467
+ ctx.rotate(0.5 * Math.PI);
8468
+ ctx.translate(0, -height);
8469
+ break;
8470
+ case 7:
8471
+ // horizontal flip + 90 rotate right
8472
+ ctx.rotate(0.5 * Math.PI);
8473
+ ctx.translate(width, -height);
8474
+ ctx.scale(-1, 1);
8475
+ break;
8476
+ case 8:
8477
+ // 90 rotate left
8478
+ ctx.rotate(-0.5 * Math.PI);
8479
+ ctx.translate(-width, 0);
8480
+ break;
8481
+ }
8482
+ }
7134
8483
 
7135
- // Included from: src/javascript/runtime/silverlight/file/FileReaderSync.js
7136
8484
 
7137
- /**
7138
- * FileReaderSync.js
7139
- *
7140
- * Copyright 2013, Moxiecode Systems AB
7141
- * Released under GPL License.
7142
- *
7143
- * License: http://www.plupload.com/license
7144
- * Contributing: http://www.plupload.com/contributing
7145
- */
8485
+ function _purge() {
8486
+ if (_imgInfo) {
8487
+ _imgInfo.purge();
8488
+ _imgInfo = null;
8489
+ }
8490
+ _binStr = _img = _canvas = _blob = null;
8491
+ _modified = false;
8492
+ }
8493
+ }
7146
8494
 
7147
- /**
7148
- @class moxie/runtime/silverlight/file/FileReaderSync
7149
- @private
7150
- */
7151
- define("moxie/runtime/silverlight/file/FileReaderSync", [
7152
- "moxie/runtime/silverlight/Runtime",
7153
- "moxie/core/utils/Basic",
7154
- "moxie/runtime/flash/file/FileReaderSync"
7155
- ], function(extensions, Basic, FileReaderSync) {
7156
- return (extensions.FileReaderSync = Basic.extend({}, FileReaderSync));
8495
+ return (extensions.Image = HTML5Image);
7157
8496
  });
7158
8497
 
7159
- // Included from: src/javascript/runtime/silverlight/xhr/XMLHttpRequest.js
8498
+ // Included from: src/javascript/runtime/html4/image/Image.js
7160
8499
 
7161
8500
  /**
7162
- * XMLHttpRequest.js
8501
+ * Image.js
7163
8502
  *
7164
8503
  * Copyright 2013, Moxiecode Systems AB
7165
8504
  * Released under GPL License.
@@ -7169,18 +8508,17 @@ define("moxie/runtime/silverlight/file/FileReaderSync", [
7169
8508
  */
7170
8509
 
7171
8510
  /**
7172
- @class moxie/runtime/silverlight/xhr/XMLHttpRequest
8511
+ @class moxie/runtime/html4/image/Image
7173
8512
  @private
7174
8513
  */
7175
- define("moxie/runtime/silverlight/xhr/XMLHttpRequest", [
7176
- "moxie/runtime/silverlight/Runtime",
7177
- "moxie/core/utils/Basic",
7178
- "moxie/runtime/flash/xhr/XMLHttpRequest"
7179
- ], function(extensions, Basic, XMLHttpRequest) {
7180
- return (extensions.XMLHttpRequest = Basic.extend({}, XMLHttpRequest));
8514
+ define("moxie/runtime/html4/image/Image", [
8515
+ "moxie/runtime/html4/Runtime",
8516
+ "moxie/runtime/html5/image/Image"
8517
+ ], function(extensions, Image) {
8518
+ return (extensions.Image = Image);
7181
8519
  });
7182
8520
 
7183
- 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/runtime/RuntimeTarget","moxie/file/FileReader","moxie/core/utils/Url","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/core/utils/Events"]);
8521
+ 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/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"]);
7184
8522
  })(this);/**
7185
8523
  * o.js
7186
8524
  *
@@ -7231,477 +8569,3 @@ Globally exposed namespace with the most frequently used public classes and hand
7231
8569
  }
7232
8570
  return o;
7233
8571
  })(this);
7234
- ;webshim.register('filereader', function($, webshim, window, document, undefined, featureOptions){
7235
- "use strict";
7236
- var mOxie, moxie, hasXDomain;
7237
- var FormData = $.noop;
7238
- var sel = 'input[type="file"].ws-filereader';
7239
- var loadMoxie = function (){
7240
- webshim.loader.loadList(['moxie']);
7241
- };
7242
- var _createFilePicker = function(){
7243
- var $input, picker, $parent, onReset;
7244
- var input = this;
7245
-
7246
- if(webshim.implement(input, 'filepicker')){
7247
-
7248
- input = this;
7249
- $input = $(this);
7250
- $parent = $input.parent();
7251
- onReset = function(){
7252
- if(!input.value){
7253
- $input.prop('value', '');
7254
- }
7255
- };
7256
-
7257
- $input.attr('tabindex', '-1').on('mousedown.filereaderwaiting click.filereaderwaiting', false);
7258
- $parent.addClass('ws-loading');
7259
- picker = new mOxie.FileInput({
7260
- browse_button: this,
7261
- accept: $.prop(this, 'accept'),
7262
- multiple: $.prop(this, 'multiple')
7263
- });
7264
-
7265
- $input.jProp('form').on('reset', function(){
7266
- setTimeout(onReset);
7267
- });
7268
- picker.onready = function(){
7269
- $input.off('.fileraderwaiting');
7270
- $parent.removeClass('ws-waiting');
7271
- };
7272
-
7273
- picker.onchange = function(e){
7274
- webshim.data(input, 'fileList', e.target.files);
7275
- $input.trigger('change');
7276
- };
7277
- picker.onmouseenter = function(){
7278
- $input.trigger('mouseover');
7279
- $parent.addClass('ws-mouseenter');
7280
- };
7281
- picker.onmouseleave = function(){
7282
- $input.trigger('mouseout');
7283
- $parent.removeClass('ws-mouseenter');
7284
- };
7285
- picker.onmousedown = function(){
7286
- $input.trigger('mousedown');
7287
- $parent.addClass('ws-active');
7288
- };
7289
- picker.onmouseup = function(){
7290
- $input.trigger('mouseup');
7291
- $parent.removeClass('ws-active');
7292
- };
7293
-
7294
- webshim.data(input, 'filePicker', picker);
7295
-
7296
- webshim.ready('WINDOWLOAD', function(){
7297
- var lastWidth;
7298
- $input.onWSOff('updateshadowdom', function(){
7299
- var curWitdth = input.offsetWidth;
7300
- if(curWitdth && lastWidth != curWitdth){
7301
- lastWidth = curWitdth;
7302
- picker.refresh();
7303
- }
7304
- });
7305
- });
7306
-
7307
- webshim.addShadowDom();
7308
-
7309
- picker.init();
7310
- if(input.disabled){
7311
- picker.disable(true);
7312
- }
7313
- }
7314
- };
7315
- var getFileNames = function(file){
7316
- return file.name;
7317
- };
7318
- var createFilePicker = function(){
7319
- var elem = this;
7320
- loadMoxie();
7321
- $(elem)
7322
- .on('mousedown.filereaderwaiting click.filereaderwaiting', false)
7323
- .parent()
7324
- .addClass('ws-loading')
7325
- ;
7326
- webshim.ready('moxie', function(){
7327
- createFilePicker.call(elem);
7328
- });
7329
- };
7330
- var noxhr = /^(?:script|jsonp)$/i;
7331
- var notReadyYet = function(){
7332
- loadMoxie();
7333
- webshim.error('filereader/formdata not ready yet. please wait for moxie to load `webshim.ready("moxie", callbackFn);`` or wait for the first change event on input[type="file"].ws-filereader.')
7334
- };
7335
- var inputValueDesc = webshim.defineNodeNameProperty('input', 'value', {
7336
- prop: {
7337
- get: function(){
7338
- var fileList = webshim.data(this, 'fileList');
7339
-
7340
- if(fileList && fileList.map){
7341
- return fileList.map(getFileNames).join(', ');
7342
- }
7343
-
7344
- return inputValueDesc.prop._supget.call(this);
7345
- }
7346
- }
7347
- }
7348
- );
7349
- var shimMoxiePath = webshim.cfg.basePath+'moxie/';
7350
- var crossXMLMessage = 'You nedd a crossdomain.xml to get all "filereader" / "XHR2" / "CORS" features to work. Or host moxie.swf/moxie.xap on your server an configure filereader options: "swfpath"/"xappath"';
7351
- var testMoxie = function(options){
7352
- return (options.wsType == 'moxie' || (options.data && options.data instanceof mOxie.FormData) || (options.crossDomain && $.support.cors !== false && hasXDomain != 'no' && !noxhr.test(options.dataType || '')));
7353
- };
7354
- var createMoxieTransport = function (options){
7355
-
7356
- if(testMoxie(options)){
7357
- var ajax;
7358
- webshim.info('moxie transfer used for $.ajax');
7359
- if(hasXDomain == 'no'){
7360
- webshim.error(crossXMLMessage);
7361
- }
7362
- return {
7363
- send: function( headers, completeCallback ) {
7364
-
7365
- var proressEvent = function(obj, name){
7366
- if(options[name]){
7367
- var called = false;
7368
- ajax.addEventListener('load', function(e){
7369
- if(!called){
7370
- options[name]({type: 'progress', lengthComputable: true, total: 1, loaded: 1});
7371
- } else if(called.lengthComputable && called.total > called.loaded){
7372
- options[name]({type: 'progress', lengthComputable: true, total: called.total, loaded: called.total});
7373
- }
7374
- });
7375
- obj.addEventListener('progress', function(e){
7376
- called = e;
7377
- options[name](e);
7378
- });
7379
- }
7380
- };
7381
- ajax = new moxie.xhr.XMLHttpRequest();
7382
-
7383
- ajax.open(options.type, options.url, options.async, options.username, options.password);
7384
-
7385
- proressEvent(ajax.upload, featureOptions.uploadprogress);
7386
- proressEvent(ajax.upload, featureOptions.progress);
7387
-
7388
- ajax.addEventListener('load', function(e){
7389
- var responses = {
7390
- text: ajax.responseText,
7391
- xml: ajax.responseXML
7392
- };
7393
- completeCallback(ajax.status, ajax.statusText, responses, ajax.getAllResponseHeaders());
7394
- });
7395
-
7396
- if(options.xhrFields && options.xhrFields.withCredentials){
7397
- ajax.withCredentials = true;
7398
- }
7399
-
7400
- if(options.timeout){
7401
- ajax.timeout = options.timeout;
7402
- }
7403
-
7404
- $.each(headers, function(name, value){
7405
- ajax.setRequestHeader(name, value);
7406
- });
7407
-
7408
-
7409
- ajax.send(options.data);
7410
-
7411
- },
7412
- abort: function() {
7413
- if(ajax){
7414
- ajax.abort();
7415
- }
7416
- }
7417
- };
7418
- }
7419
- };
7420
- var transports = {
7421
- //based on script: https://github.com/MoonScript/jQuery-ajaxTransport-XDomainRequest
7422
- xdomain: (function(){
7423
- var httpRegEx = /^https?:\/\//i;
7424
- var getOrPostRegEx = /^get|post$/i;
7425
- var sameSchemeRegEx = new RegExp('^'+location.protocol, 'i');
7426
- return function(options, userOptions, jqXHR) {
7427
-
7428
- // Only continue if the request is: asynchronous, uses GET or POST method, has HTTP or HTTPS protocol, and has the same scheme as the calling page
7429
- if (!options.crossDomain || options.username || (options.xhrFields && options.xhrFields.withCredentials) || !options.async || !getOrPostRegEx.test(options.type) || !httpRegEx.test(options.url) || !sameSchemeRegEx.test(options.url) || (options.data && options.data instanceof mOxie.FormData) || noxhr.test(options.dataType || '')) {
7430
- return;
7431
- }
7432
-
7433
- var xdr = null;
7434
- webshim.info('xdomain transport used.');
7435
-
7436
- return {
7437
- send: function(headers, complete) {
7438
- var postData = '';
7439
- var userType = (userOptions.dataType || '').toLowerCase();
7440
-
7441
- xdr = new XDomainRequest();
7442
- if (/^\d+$/.test(userOptions.timeout)) {
7443
- xdr.timeout = userOptions.timeout;
7444
- }
7445
-
7446
- xdr.ontimeout = function() {
7447
- complete(500, 'timeout');
7448
- };
7449
-
7450
- xdr.onload = function() {
7451
- var allResponseHeaders = 'Content-Length: ' + xdr.responseText.length + '\r\nContent-Type: ' + xdr.contentType;
7452
- var status = {
7453
- code: xdr.status || 200,
7454
- message: xdr.statusText || 'OK'
7455
- };
7456
- var responses = {
7457
- text: xdr.responseText,
7458
- xml: xdr.responseXML
7459
- };
7460
- try {
7461
- if (userType === 'html' || /text\/html/i.test(xdr.contentType)) {
7462
- responses.html = xdr.responseText;
7463
- } else if (userType === 'json' || (userType !== 'text' && /\/json/i.test(xdr.contentType))) {
7464
- try {
7465
- responses.json = $.parseJSON(xdr.responseText);
7466
- } catch(e) {
7467
-
7468
- }
7469
- } else if (userType === 'xml' && !xdr.responseXML) {
7470
- var doc;
7471
- try {
7472
- doc = new ActiveXObject('Microsoft.XMLDOM');
7473
- doc.async = false;
7474
- doc.loadXML(xdr.responseText);
7475
- } catch(e) {
7476
-
7477
- }
7478
-
7479
- responses.xml = doc;
7480
- }
7481
- } catch(parseMessage) {}
7482
- complete(status.code, status.message, responses, allResponseHeaders);
7483
- };
7484
-
7485
- // set an empty handler for 'onprogress' so requests don't get aborted
7486
- xdr.onprogress = function(){};
7487
- xdr.onerror = function() {
7488
- complete(500, 'error', {
7489
- text: xdr.responseText
7490
- });
7491
- };
7492
-
7493
- if (userOptions.data) {
7494
- postData = ($.type(userOptions.data) === 'string') ? userOptions.data : $.param(userOptions.data);
7495
- }
7496
- xdr.open(options.type, options.url);
7497
- xdr.send(postData);
7498
- },
7499
- abort: function() {
7500
- if (xdr) {
7501
- xdr.abort();
7502
- }
7503
- }
7504
- };
7505
- };
7506
- })(),
7507
- moxie: function (options, originalOptions, jqXHR){
7508
- if(testMoxie(options)){
7509
- loadMoxie(options);
7510
- var ajax;
7511
-
7512
- var tmpTransport = {
7513
- send: function( headers, completeCallback ) {
7514
- ajax = true;
7515
- webshim.ready('moxie', function(){
7516
- if(ajax){
7517
- ajax = createMoxieTransport(options, originalOptions, jqXHR);
7518
- tmpTransport.send = ajax.send;
7519
- tmpTransport.abort = ajax.abort;
7520
- ajax.send(headers, completeCallback);
7521
- }
7522
- });
7523
- },
7524
- abort: function() {
7525
- ajax = false;
7526
- }
7527
- };
7528
- return tmpTransport;
7529
- }
7530
- }
7531
- };
7532
-
7533
- if(!featureOptions.progress){
7534
- featureOptions.progress = 'onprogress';
7535
- }
7536
-
7537
- if(!featureOptions.uploadprogress){
7538
- featureOptions.uploadprogress = 'onuploadprogress';
7539
- }
7540
-
7541
- if(!featureOptions.swfpath){
7542
- featureOptions.swfpath = shimMoxiePath+'flash/Moxie.min.swf';
7543
- }
7544
- if(!featureOptions.xappath){
7545
- featureOptions.xappath = shimMoxiePath+'silverlight/Moxie.min.xap';
7546
- }
7547
-
7548
- if($.support.cors !== false || !window.XDomainRequest){
7549
- delete transports.xdomain;
7550
- }
7551
-
7552
-
7553
- $.ajaxTransport("+*", function( options, originalOptions, jqXHR ) {
7554
- var ajax, type;
7555
-
7556
- if(options.wsType || transports[transports]){
7557
- ajax = transports[transports](options, originalOptions, jqXHR);
7558
- }
7559
- if(!ajax){
7560
- for(type in transports){
7561
- ajax = transports[type](options, originalOptions, jqXHR);
7562
- if(ajax){break;}
7563
- }
7564
- }
7565
- return ajax;
7566
- });
7567
-
7568
- webshim.defineNodeNameProperty('input', 'files', {
7569
- prop: {
7570
- writeable: false,
7571
- get: function(){
7572
- if(this.type != 'file'){return null;}
7573
- if(!$(this).hasClass('ws-filereader')){
7574
- webshim.info("please add the 'ws-filereader' class to your input[type='file'] to implement files-property");
7575
- }
7576
- return webshim.data(this, 'fileList') || [];
7577
- }
7578
- }
7579
- }
7580
- );
7581
-
7582
- webshim.reflectProperties(['input'], ['accept']);
7583
-
7584
- if($('<input />').prop('multiple') == null){
7585
- webshim.defineNodeNamesBooleanProperty(['input'], ['multiple']);
7586
- }
7587
-
7588
- webshim.onNodeNamesPropertyModify('input', 'disabled', function(value, boolVal, type){
7589
- var picker = webshim.data(this, 'filePicker');
7590
- if(picker){
7591
- picker.disable(boolVal);
7592
- }
7593
- });
7594
-
7595
- webshim.onNodeNamesPropertyModify('input', 'value', function(value, boolVal, type){
7596
- if(value === '' && this.type == 'file' && $(this).hasClass('ws-filereader')){
7597
- webshim.data(this, 'fileList', []);
7598
- }
7599
- });
7600
-
7601
-
7602
- window.FileReader = notReadyYet;
7603
- window.FormData = notReadyYet;
7604
- webshim.ready('moxie', function(){
7605
- var wsMimes = 'application/xml,xml';
7606
- moxie = window.moxie;
7607
- mOxie = window.mOxie;
7608
-
7609
- mOxie.Env.swf_url = featureOptions.swfpath;
7610
- mOxie.Env.xap_url = featureOptions.xappath;
7611
-
7612
- window.FileReader = mOxie.FileReader;
7613
-
7614
- window.FormData = function(form){
7615
- var appendData, i, len, files, fileI, fileLen, inputName;
7616
- var moxieData = new mOxie.FormData();
7617
- if(form && $.nodeName(form, 'form')){
7618
- appendData = $(form).serializeArray();
7619
- for(i = 0; i < appendData.length; i++){
7620
- if(Array.isArray(appendData[i].value)){
7621
- appendData[i].value.forEach(function(val){
7622
- moxieData.append(appendData[i].name, val);
7623
- });
7624
- } else {
7625
- moxieData.append(appendData[i].name, appendData[i].value);
7626
- }
7627
- }
7628
-
7629
- appendData = form.querySelectorAll('input[type="file"][name]');
7630
-
7631
- for(i = 0, len = appendData.length; i < appendData.length; i++){
7632
- inputName = appendData[i].name;
7633
- if(inputName && !$(appendData[i]).is(':disabled')){
7634
- files = $.prop(appendData[i], 'files') || [];
7635
- if(files.length){
7636
- if(files.length > 1 || (moxieData.hasBlob && moxieData.hasBlob())){
7637
- webshim.error('FormData shim can only handle one file per ajax. Use multiple ajax request. One per file.');
7638
- }
7639
- for(fileI = 0, fileLen = files.length; fileI < fileLen; fileI++){
7640
- moxieData.append(inputName, files[fileI]);
7641
- }
7642
- }
7643
- }
7644
- }
7645
- }
7646
-
7647
- return moxieData;
7648
- };
7649
- FormData = window.FormData;
7650
-
7651
- createFilePicker = _createFilePicker;
7652
- transports.moxie = createMoxieTransport;
7653
-
7654
- featureOptions.mimeTypes = (featureOptions.mimeTypes) ? wsMimes+','+featureOptions.mimeTypes : wsMimes;
7655
- try {
7656
- mOxie.Mime.addMimeType(featureOptions.mimeTypes);
7657
- } catch(e){
7658
- webshim.warn('mimetype to moxie error: '+e);
7659
- }
7660
-
7661
- });
7662
-
7663
- webshim.addReady(function(context, contextElem){
7664
- $(context.querySelectorAll(sel)).add(contextElem.filter(sel)).each(createFilePicker);
7665
- });
7666
- webshim.ready('WINDOWLOAD', loadMoxie);
7667
-
7668
- if(webshim.cfg.debug !== false && featureOptions.swfpath.indexOf((location.protocol+'//'+location.hostname)) && featureOptions.swfpath.indexOf(('https://'+location.hostname))){
7669
- webshim.ready('WINDOWLOAD', function(){
7670
-
7671
- var printMessage = function(){
7672
- if(hasXDomain == 'no'){
7673
- webshim.error(crossXMLMessage);
7674
- }
7675
- };
7676
-
7677
- try {
7678
- hasXDomain = sessionStorage.getItem('wsXdomain.xml');
7679
- } catch(e){}
7680
- printMessage();
7681
- if(hasXDomain == null){
7682
- try {
7683
- $.ajax({
7684
- url: 'crossdomain.xml',
7685
- type: 'HEAD',
7686
- dataType: 'xml',
7687
- success: function(){
7688
- hasXDomain = 'yes';
7689
- },
7690
- error: function(){
7691
- hasXDomain = 'no';
7692
- },
7693
- complete: function(){
7694
- try {
7695
- sessionStorage.setItem('wsXdomain.xml', hasXDomain);
7696
- } catch(e){}
7697
- printMessage();
7698
- }
7699
- });
7700
- } catch(e){}
7701
- }
7702
- });
7703
- }
7704
- if(document.readyState == 'complete'){
7705
- webshims.isReady('WINDOWLOAD', true);
7706
- }
7707
- });