plupload-rails 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (61) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +34 -35
  3. data/lib/plupload/rails/version.rb +2 -2
  4. data/vendor/assets/images/jquery.plupload.queue/backgrounds.gif +0 -0
  5. data/vendor/assets/images/jquery.plupload.queue/buttons-disabled.png +0 -0
  6. data/vendor/assets/images/jquery.plupload.queue/buttons.png +0 -0
  7. data/vendor/assets/images/jquery.plupload.queue/delete.gif +0 -0
  8. data/vendor/assets/images/jquery.plupload.queue/done.gif +0 -0
  9. data/vendor/assets/images/jquery.plupload.queue/error.gif +0 -0
  10. data/vendor/assets/images/jquery.plupload.queue/throbber.gif +0 -0
  11. data/vendor/assets/images/jquery.plupload.queue/transp50.png +0 -0
  12. data/vendor/assets/images/jquery.ui.plupload/loading.gif +0 -0
  13. data/vendor/assets/images/jquery.ui.plupload/plupload.png +0 -0
  14. data/vendor/assets/javascripts/jquery.plupload.queue.js +27 -17
  15. data/vendor/assets/javascripts/jquery.ui.plupload.js +308 -217
  16. data/vendor/assets/javascripts/moxie.js +906 -661
  17. data/vendor/assets/javascripts/plupload.dev.js +727 -537
  18. data/vendor/assets/javascripts/plupload/i18n/ar.js +2 -0
  19. data/vendor/assets/javascripts/plupload/i18n/bs.js +1 -0
  20. data/vendor/assets/javascripts/plupload/i18n/ca.js +2 -0
  21. data/vendor/assets/javascripts/plupload/i18n/cs.js +1 -0
  22. data/vendor/assets/javascripts/plupload/i18n/cy.js +1 -0
  23. data/vendor/assets/javascripts/plupload/i18n/da.js +1 -0
  24. data/vendor/assets/javascripts/plupload/i18n/de.js +2 -1
  25. data/vendor/assets/javascripts/plupload/i18n/el.js +1 -0
  26. data/vendor/assets/javascripts/plupload/i18n/en.js +1 -0
  27. data/vendor/assets/javascripts/plupload/i18n/es.js +2 -1
  28. data/vendor/assets/javascripts/plupload/i18n/et.js +1 -0
  29. data/vendor/assets/javascripts/plupload/i18n/fa.js +1 -0
  30. data/vendor/assets/javascripts/plupload/i18n/fi.js +1 -0
  31. data/vendor/assets/javascripts/plupload/i18n/fr.js +2 -1
  32. data/vendor/assets/javascripts/plupload/i18n/he.js +2 -0
  33. data/vendor/assets/javascripts/plupload/i18n/hr.js +1 -0
  34. data/vendor/assets/javascripts/plupload/i18n/hu.js +2 -1
  35. data/vendor/assets/javascripts/plupload/i18n/hy.js +1 -0
  36. data/vendor/assets/javascripts/plupload/i18n/id.js +2 -0
  37. data/vendor/assets/javascripts/plupload/i18n/it.js +1 -0
  38. data/vendor/assets/javascripts/plupload/i18n/ja.js +1 -0
  39. data/vendor/assets/javascripts/plupload/i18n/ka.js +1 -0
  40. data/vendor/assets/javascripts/plupload/i18n/kk.js +2 -0
  41. data/vendor/assets/javascripts/plupload/i18n/ko.js +1 -0
  42. data/vendor/assets/javascripts/plupload/i18n/lt.js +1 -0
  43. data/vendor/assets/javascripts/plupload/i18n/lv.js +2 -1
  44. data/vendor/assets/javascripts/plupload/i18n/nl.js +1 -0
  45. data/vendor/assets/javascripts/plupload/i18n/pl.js +1 -0
  46. data/vendor/assets/javascripts/plupload/i18n/pt_BR.js +1 -0
  47. data/vendor/assets/javascripts/plupload/i18n/ro.js +2 -1
  48. data/vendor/assets/javascripts/plupload/i18n/ru.js +2 -1
  49. data/vendor/assets/javascripts/plupload/i18n/sk.js +1 -0
  50. data/vendor/assets/javascripts/plupload/i18n/sr.js +1 -0
  51. data/vendor/assets/javascripts/plupload/i18n/sv.js +1 -0
  52. data/vendor/assets/javascripts/plupload/i18n/th_TH.js +1 -0
  53. data/vendor/assets/javascripts/plupload/i18n/tr.js +1 -0
  54. data/vendor/assets/javascripts/plupload/i18n/uk_UA.js +1 -0
  55. data/vendor/assets/javascripts/plupload/i18n/zh_CN.js +1 -0
  56. data/vendor/assets/javascripts/plupload/i18n/zh_TW.js +2 -0
  57. data/vendor/assets/misc/Moxie.swf +0 -0
  58. data/vendor/assets/misc/Moxie.xap +0 -0
  59. data/vendor/assets/stylesheets/{jquery.plupload.queue.scss → jquery.plupload.queue.css.erb} +15 -11
  60. data/vendor/assets/stylesheets/{jquery.ui.plupload.scss → jquery.ui.plupload.css.erb} +3 -3
  61. metadata +18 -12
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * mOxie - multi-runtime File API & XMLHttpRequest L2 Polyfill
3
- * v1.0.0
3
+ * v1.2.0
4
4
  *
5
5
  * Copyright 2013, Moxiecode Systems AB
6
6
  * Released under GPL License.
@@ -8,7 +8,7 @@
8
8
  * License: http://www.plupload.com/license
9
9
  * Contributing: http://www.plupload.com/contributing
10
10
  *
11
- * Date: 2013-09-23
11
+ * Date: 2014-01-16
12
12
  */
13
13
  /**
14
14
  * Compiled inline version. (Library mode)
@@ -252,6 +252,42 @@ define('moxie/core/utils/Basic', [], function() {
252
252
  }
253
253
  callNext(i);
254
254
  };
255
+
256
+
257
+ /**
258
+ Recieve an array of functions (usually async) to call in parallel, each function
259
+ receives a callback as first argument that it should call, when it completes. After
260
+ everything is complete, main callback is called. Passing truthy value to the
261
+ callback as a first argument will interrupt the process and invoke main callback
262
+ immediately.
263
+
264
+ @method inParallel
265
+ @static
266
+ @param {Array} queue Array of functions to call in sequence
267
+ @param {Function} cb Main callback that is called in the end, or in case of erro
268
+ */
269
+ var inParallel = function(queue, cb) {
270
+ var count = 0, num = queue.length, cbArgs = new Array(num);
271
+
272
+ each(queue, function(fn, i) {
273
+ fn(function(error) {
274
+ if (error) {
275
+ return cb(error);
276
+ }
277
+
278
+ var args = [].slice.call(arguments);
279
+ args.shift(); // strip error - undefined or not
280
+
281
+ cbArgs[i] = args;
282
+ count++;
283
+
284
+ if (count === num) {
285
+ cbArgs.unshift(null);
286
+ cb.apply(this, cbArgs);
287
+ }
288
+ });
289
+ });
290
+ };
255
291
 
256
292
 
257
293
  /**
@@ -429,6 +465,7 @@ define('moxie/core/utils/Basic', [], function() {
429
465
  each: each,
430
466
  isEmptyObj: isEmptyObj,
431
467
  inSeries: inSeries,
468
+ inParallel: inParallel,
432
469
  inArray: inArray,
433
470
  arrayDiff: arrayDiff,
434
471
  arrayIntersect: arrayIntersect,
@@ -493,15 +530,12 @@ define("moxie/core/I18n", [
493
530
  * @return {String} String with replaced tokens
494
531
  */
495
532
  sprintf: function(str) {
496
- var args = [].slice.call(arguments, 1), reStr = '';
533
+ var args = [].slice.call(arguments, 1);
497
534
 
498
- Basic.each(str.split(/%[a-z]/), function(part) {
499
- reStr += part;
500
- if (args.length) {
501
- reStr += args.shift();
502
- }
535
+ return str.replace(/%[a-z]/g, function() {
536
+ var value = args.shift();
537
+ return Basic.typeOf(value) !== 'undefined' ? value : '';
503
538
  });
504
- return reStr;
505
539
  }
506
540
  };
507
541
  });
@@ -543,7 +577,7 @@ define("moxie/core/utils/Mime", [
543
577
  "application/json,json," +
544
578
  "audio/mpeg,mp3 mpga mpega mp2," +
545
579
  "audio/x-wav,wav," +
546
- "audio/mp4,m4a," +
580
+ "audio/x-m4a,m4a," +
547
581
  "audio/ogg,oga ogg," +
548
582
  "audio/aiff,aiff aif," +
549
583
  "audio/flac,flac," +
@@ -715,109 +749,518 @@ define("moxie/core/utils/Env", [
715
749
  "moxie/core/utils/Basic"
716
750
  ], function(Basic) {
717
751
 
718
- var browser = [{
719
- s1: navigator.userAgent,
720
- s2: "Android",
721
- id: "Android Browser", // default or Dolphin
722
- sv: "Version"
723
- },{
724
- s1: navigator.userAgent, // string
725
- s2: "Chrome", // substring
726
- id: "Chrome" // identity
727
- },{
728
- s1: navigator.vendor,
729
- s2: "Apple",
730
- id: "Safari",
731
- sv: "Version" // version
732
- },{
733
- prop: window.opera && window.opera.buildNumber,
734
- id: "Opera",
735
- sv: "Version"
736
- },{
737
- s1: navigator.vendor,
738
- s2: "KDE",
739
- id: "Konqueror"
740
- },{
741
- s1: navigator.userAgent,
742
- s2: "Firefox",
743
- id: "Firefox"
744
- },{
745
- s1: navigator.vendor,
746
- s2: "Camino",
747
- id: "Camino"
748
- },{
749
- // for newer Netscapes (6+)
750
- s1: navigator.userAgent,
751
- s2: "Netscape",
752
- id: "Netscape"
753
- },{
754
- s1: navigator.userAgent,
755
- s2: "MSIE",
756
- id: "IE",
757
- sv: "MSIE"
758
- },{
759
- s1: navigator.userAgent,
760
- s2: "Gecko",
761
- id: "Mozilla",
762
- sv: "rv"
763
- }],
764
-
765
- os = [{
766
- s1: navigator.platform,
767
- s2: "Win",
768
- id: "Windows"
769
- },{
770
- s1: navigator.platform,
771
- s2: "Mac",
772
- id: "Mac"
773
- },{
774
- s1: navigator.userAgent,
775
- s2: "iPhone",
776
- id: "iOS"
777
- },{
778
- s1: navigator.userAgent,
779
- s2: "iPad",
780
- id: "iOS"
781
- },{
782
- s1: navigator.userAgent,
783
- s2: "Android",
784
- id: "Android"
785
- },{
786
- s1: navigator.platform,
787
- s2: "Linux",
788
- id: "Linux"
789
- }]
790
- , version;
791
-
792
- function getStr(data) {
793
- var str, prop;
794
-
795
- for (var i = 0; i < data.length; i++) {
796
- str = data[i].s1;
797
- prop = data[i].prop;
798
- version = data[i].sv || data[i].id;
799
-
800
- if (str) {
801
- if (str.indexOf(data[i].s2) != -1) {
802
- return data[i].id;
803
- }
804
- } else if (prop) {
805
- return data[i].id;
806
- }
807
- }
808
- }
809
-
810
-
811
- function getVer(str) {
812
- var index = str.indexOf(version);
752
+ // UAParser.js v0.6.2
753
+ // Lightweight JavaScript-based User-Agent string parser
754
+ // https://github.com/faisalman/ua-parser-js
755
+ //
756
+ // Copyright © 2012-2013 Faisalman <fyzlman@gmail.com>
757
+ // Dual licensed under GPLv2 & MIT
758
+
759
+ var UAParser = (function (undefined) {
760
+
761
+ //////////////
762
+ // Constants
763
+ /////////////
764
+
765
+
766
+ var EMPTY = '',
767
+ UNKNOWN = '?',
768
+ FUNC_TYPE = 'function',
769
+ UNDEF_TYPE = 'undefined',
770
+ OBJ_TYPE = 'object',
771
+ MAJOR = 'major',
772
+ MODEL = 'model',
773
+ NAME = 'name',
774
+ TYPE = 'type',
775
+ VENDOR = 'vendor',
776
+ VERSION = 'version',
777
+ ARCHITECTURE= 'architecture',
778
+ CONSOLE = 'console',
779
+ MOBILE = 'mobile',
780
+ TABLET = 'tablet';
781
+
782
+
783
+ ///////////
784
+ // Helper
785
+ //////////
786
+
787
+
788
+ var util = {
789
+ has : function (str1, str2) {
790
+ return str2.toLowerCase().indexOf(str1.toLowerCase()) !== -1;
791
+ },
792
+ lowerize : function (str) {
793
+ return str.toLowerCase();
794
+ }
795
+ };
813
796
 
814
- if (index == -1) {
815
- return;
816
- }
817
797
 
818
- return parseFloat(str.substring(index + version.length + 1));
798
+ ///////////////
799
+ // Map helper
800
+ //////////////
801
+
802
+
803
+ var mapper = {
804
+
805
+ rgx : function () {
806
+
807
+ // loop through all regexes maps
808
+ for (var result, i = 0, j, k, p, q, matches, match, args = arguments; i < args.length; i += 2) {
809
+
810
+ var regex = args[i], // even sequence (0,2,4,..)
811
+ props = args[i + 1]; // odd sequence (1,3,5,..)
812
+
813
+ // construct object barebones
814
+ if (typeof(result) === UNDEF_TYPE) {
815
+ result = {};
816
+ for (p in props) {
817
+ q = props[p];
818
+ if (typeof(q) === OBJ_TYPE) {
819
+ result[q[0]] = undefined;
820
+ } else {
821
+ result[q] = undefined;
822
+ }
823
+ }
824
+ }
825
+
826
+ // try matching uastring with regexes
827
+ for (j = k = 0; j < regex.length; j++) {
828
+ matches = regex[j].exec(this.getUA());
829
+ if (!!matches) {
830
+ for (p = 0; p < props.length; p++) {
831
+ match = matches[++k];
832
+ q = props[p];
833
+ // check if given property is actually array
834
+ if (typeof(q) === OBJ_TYPE && q.length > 0) {
835
+ if (q.length == 2) {
836
+ if (typeof(q[1]) == FUNC_TYPE) {
837
+ // assign modified match
838
+ result[q[0]] = q[1].call(this, match);
839
+ } else {
840
+ // assign given value, ignore regex match
841
+ result[q[0]] = q[1];
842
+ }
843
+ } else if (q.length == 3) {
844
+ // check whether function or regex
845
+ if (typeof(q[1]) === FUNC_TYPE && !(q[1].exec && q[1].test)) {
846
+ // call function (usually string mapper)
847
+ result[q[0]] = match ? q[1].call(this, match, q[2]) : undefined;
848
+ } else {
849
+ // sanitize match using given regex
850
+ result[q[0]] = match ? match.replace(q[1], q[2]) : undefined;
851
+ }
852
+ } else if (q.length == 4) {
853
+ result[q[0]] = match ? q[3].call(this, match.replace(q[1], q[2])) : undefined;
854
+ }
855
+ } else {
856
+ result[q] = match ? match : undefined;
857
+ }
858
+ }
859
+ break;
860
+ }
861
+ }
862
+
863
+ if(!!matches) break; // break the loop immediately if match found
864
+ }
865
+ return result;
866
+ },
867
+
868
+ str : function (str, map) {
869
+
870
+ for (var i in map) {
871
+ // check if array
872
+ if (typeof(map[i]) === OBJ_TYPE && map[i].length > 0) {
873
+ for (var j = 0; j < map[i].length; j++) {
874
+ if (util.has(map[i][j], str)) {
875
+ return (i === UNKNOWN) ? undefined : i;
876
+ }
877
+ }
878
+ } else if (util.has(map[i], str)) {
879
+ return (i === UNKNOWN) ? undefined : i;
880
+ }
881
+ }
882
+ return str;
883
+ }
884
+ };
885
+
886
+
887
+ ///////////////
888
+ // String map
889
+ //////////////
890
+
891
+
892
+ var maps = {
893
+
894
+ browser : {
895
+ oldsafari : {
896
+ major : {
897
+ '1' : ['/8', '/1', '/3'],
898
+ '2' : '/4',
899
+ '?' : '/'
900
+ },
901
+ version : {
902
+ '1.0' : '/8',
903
+ '1.2' : '/1',
904
+ '1.3' : '/3',
905
+ '2.0' : '/412',
906
+ '2.0.2' : '/416',
907
+ '2.0.3' : '/417',
908
+ '2.0.4' : '/419',
909
+ '?' : '/'
910
+ }
911
+ }
912
+ },
913
+
914
+ device : {
915
+ sprint : {
916
+ model : {
917
+ 'Evo Shift 4G' : '7373KT'
918
+ },
919
+ vendor : {
920
+ 'HTC' : 'APA',
921
+ 'Sprint' : 'Sprint'
922
+ }
923
+ }
924
+ },
925
+
926
+ os : {
927
+ windows : {
928
+ version : {
929
+ 'ME' : '4.90',
930
+ 'NT 3.11' : 'NT3.51',
931
+ 'NT 4.0' : 'NT4.0',
932
+ '2000' : 'NT 5.0',
933
+ 'XP' : ['NT 5.1', 'NT 5.2'],
934
+ 'Vista' : 'NT 6.0',
935
+ '7' : 'NT 6.1',
936
+ '8' : 'NT 6.2',
937
+ '8.1' : 'NT 6.3',
938
+ 'RT' : 'ARM'
939
+ }
940
+ }
941
+ }
942
+ };
943
+
944
+
945
+ //////////////
946
+ // Regex map
947
+ /////////////
948
+
949
+
950
+ var regexes = {
951
+
952
+ browser : [[
953
+
954
+ // Presto based
955
+ /(opera\smini)\/((\d+)?[\w\.-]+)/i, // Opera Mini
956
+ /(opera\s[mobiletab]+).+version\/((\d+)?[\w\.-]+)/i, // Opera Mobi/Tablet
957
+ /(opera).+version\/((\d+)?[\w\.]+)/i, // Opera > 9.80
958
+ /(opera)[\/\s]+((\d+)?[\w\.]+)/i // Opera < 9.80
959
+
960
+ ], [NAME, VERSION, MAJOR], [
961
+
962
+ /\s(opr)\/((\d+)?[\w\.]+)/i // Opera Webkit
963
+ ], [[NAME, 'Opera'], VERSION, MAJOR], [
964
+
965
+ // Mixed
966
+ /(kindle)\/((\d+)?[\w\.]+)/i, // Kindle
967
+ /(lunascape|maxthon|netfront|jasmine|blazer)[\/\s]?((\d+)?[\w\.]+)*/i,
968
+ // Lunascape/Maxthon/Netfront/Jasmine/Blazer
969
+
970
+ // Trident based
971
+ /(avant\s|iemobile|slim|baidu)(?:browser)?[\/\s]?((\d+)?[\w\.]*)/i,
972
+ // Avant/IEMobile/SlimBrowser/Baidu
973
+ /(?:ms|\()(ie)\s((\d+)?[\w\.]+)/i, // Internet Explorer
974
+
975
+ // Webkit/KHTML based
976
+ /(rekonq)((?:\/)[\w\.]+)*/i, // Rekonq
977
+ /(chromium|flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron)\/((\d+)?[\w\.-]+)/i
978
+ // Chromium/Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron
979
+ ], [NAME, VERSION, MAJOR], [
980
+
981
+ /(trident).+rv[:\s]((\d+)?[\w\.]+).+like\sgecko/i // IE11
982
+ ], [[NAME, 'IE'], VERSION, MAJOR], [
983
+
984
+ /(yabrowser)\/((\d+)?[\w\.]+)/i // Yandex
985
+ ], [[NAME, 'Yandex'], VERSION, MAJOR], [
986
+
987
+ /(comodo_dragon)\/((\d+)?[\w\.]+)/i // Comodo Dragon
988
+ ], [[NAME, /_/g, ' '], VERSION, MAJOR], [
989
+
990
+ /(chrome|omniweb|arora|[tizenoka]{5}\s?browser)\/v?((\d+)?[\w\.]+)/i
991
+ // Chrome/OmniWeb/Arora/Tizen/Nokia
992
+ ], [NAME, VERSION, MAJOR], [
993
+
994
+ /(dolfin)\/((\d+)?[\w\.]+)/i // Dolphin
995
+ ], [[NAME, 'Dolphin'], VERSION, MAJOR], [
996
+
997
+ /((?:android.+)crmo|crios)\/((\d+)?[\w\.]+)/i // Chrome for Android/iOS
998
+ ], [[NAME, 'Chrome'], VERSION, MAJOR], [
999
+
1000
+ /((?:android.+))version\/((\d+)?[\w\.]+)\smobile\ssafari/i // Android Browser
1001
+ ], [[NAME, 'Android Browser'], VERSION, MAJOR], [
1002
+
1003
+ /version\/((\d+)?[\w\.]+).+?mobile\/\w+\s(safari)/i // Mobile Safari
1004
+ ], [VERSION, MAJOR, [NAME, 'Mobile Safari']], [
1005
+
1006
+ /version\/((\d+)?[\w\.]+).+?(mobile\s?safari|safari)/i // Safari & Safari Mobile
1007
+ ], [VERSION, MAJOR, NAME], [
1008
+
1009
+ /webkit.+?(mobile\s?safari|safari)((\/[\w\.]+))/i // Safari < 3.0
1010
+ ], [NAME, [MAJOR, mapper.str, maps.browser.oldsafari.major], [VERSION, mapper.str, maps.browser.oldsafari.version]], [
1011
+
1012
+ /(konqueror)\/((\d+)?[\w\.]+)/i, // Konqueror
1013
+ /(webkit|khtml)\/((\d+)?[\w\.]+)/i
1014
+ ], [NAME, VERSION, MAJOR], [
1015
+
1016
+ // Gecko based
1017
+ /(navigator|netscape)\/((\d+)?[\w\.-]+)/i // Netscape
1018
+ ], [[NAME, 'Netscape'], VERSION, MAJOR], [
1019
+ /(swiftfox)/i, // Swiftfox
1020
+ /(icedragon|iceweasel|camino|chimera|fennec|maemo\sbrowser|minimo|conkeror)[\/\s]?((\d+)?[\w\.\+]+)/i,
1021
+ // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror
1022
+ /(firefox|seamonkey|k-meleon|icecat|iceape|firebird|phoenix)\/((\d+)?[\w\.-]+)/i,
1023
+ // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix
1024
+ /(mozilla)\/((\d+)?[\w\.]+).+rv\:.+gecko\/\d+/i, // Mozilla
1025
+
1026
+ // Other
1027
+ /(uc\s?browser|polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|qqbrowser)[\/\s]?((\d+)?[\w\.]+)/i,
1028
+ // UCBrowser/Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/QQBrowser
1029
+ /(links)\s\(((\d+)?[\w\.]+)/i, // Links
1030
+ /(gobrowser)\/?((\d+)?[\w\.]+)*/i, // GoBrowser
1031
+ /(ice\s?browser)\/v?((\d+)?[\w\._]+)/i, // ICE Browser
1032
+ /(mosaic)[\/\s]((\d+)?[\w\.]+)/i // Mosaic
1033
+ ], [NAME, VERSION, MAJOR]
1034
+ ],
1035
+
1036
+ engine : [[
1037
+
1038
+ /(presto)\/([\w\.]+)/i, // Presto
1039
+ /(webkit|trident|netfront|netsurf|amaya|lynx|w3m)\/([\w\.]+)/i, // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m
1040
+ /(khtml|tasman|links)[\/\s]\(?([\w\.]+)/i, // KHTML/Tasman/Links
1041
+ /(icab)[\/\s]([23]\.[\d\.]+)/i // iCab
1042
+ ], [NAME, VERSION], [
1043
+
1044
+ /rv\:([\w\.]+).*(gecko)/i // Gecko
1045
+ ], [VERSION, NAME]
1046
+ ],
1047
+
1048
+ os : [[
1049
+
1050
+ // Windows based
1051
+ /(windows)\snt\s6\.2;\s(arm)/i, // Windows RT
1052
+ /(windows\sphone(?:\sos)*|windows\smobile|windows)[\s\/]?([ntce\d\.\s]+\w)/i
1053
+ ], [NAME, [VERSION, mapper.str, maps.os.windows.version]], [
1054
+ /(win(?=3|9|n)|win\s9x\s)([nt\d\.]+)/i
1055
+ ], [[NAME, 'Windows'], [VERSION, mapper.str, maps.os.windows.version]], [
1056
+
1057
+ // Mobile/Embedded OS
1058
+ /\((bb)(10);/i // BlackBerry 10
1059
+ ], [[NAME, 'BlackBerry'], VERSION], [
1060
+ /(blackberry)\w*\/?([\w\.]+)*/i, // Blackberry
1061
+ /(tizen)\/([\w\.]+)/i, // Tizen
1062
+ /(android|webos|palm\os|qnx|bada|rim\stablet\sos|meego)[\/\s-]?([\w\.]+)*/i
1063
+ // Android/WebOS/Palm/QNX/Bada/RIM/MeeGo
1064
+ ], [NAME, VERSION], [
1065
+ /(symbian\s?os|symbos|s60(?=;))[\/\s-]?([\w\.]+)*/i // Symbian
1066
+ ], [[NAME, 'Symbian'], VERSION],[
1067
+ /mozilla.+\(mobile;.+gecko.+firefox/i // Firefox OS
1068
+ ], [[NAME, 'Firefox OS'], VERSION], [
1069
+
1070
+ // Console
1071
+ /(nintendo|playstation)\s([wids3portablevu]+)/i, // Nintendo/Playstation
1072
+
1073
+ // GNU/Linux based
1074
+ /(mint)[\/\s\(]?(\w+)*/i, // Mint
1075
+ /(joli|[kxln]?ubuntu|debian|[open]*suse|gentoo|arch|slackware|fedora|mandriva|centos|pclinuxos|redhat|zenwalk)[\/\s-]?([\w\.-]+)*/i,
1076
+ // Joli/Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware
1077
+ // Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk
1078
+ /(hurd|linux)\s?([\w\.]+)*/i, // Hurd/Linux
1079
+ /(gnu)\s?([\w\.]+)*/i // GNU
1080
+ ], [NAME, VERSION], [
1081
+
1082
+ /(cros)\s[\w]+\s([\w\.]+\w)/i // Chromium OS
1083
+ ], [[NAME, 'Chromium OS'], VERSION],[
1084
+
1085
+ // Solaris
1086
+ /(sunos)\s?([\w\.]+\d)*/i // Solaris
1087
+ ], [[NAME, 'Solaris'], VERSION], [
1088
+
1089
+ // BSD based
1090
+ /\s([frentopc-]{0,4}bsd|dragonfly)\s?([\w\.]+)*/i // FreeBSD/NetBSD/OpenBSD/PC-BSD/DragonFly
1091
+ ], [NAME, VERSION],[
1092
+
1093
+ /(ip[honead]+)(?:.*os\s*([\w]+)*\slike\smac|;\sopera)/i // iOS
1094
+ ], [[NAME, 'iOS'], [VERSION, /_/g, '.']], [
1095
+
1096
+ /(mac\sos\sx)\s?([\w\s\.]+\w)*/i // Mac OS
1097
+ ], [NAME, [VERSION, /_/g, '.']], [
1098
+
1099
+ // Other
1100
+ /(haiku)\s(\w+)/i, // Haiku
1101
+ /(aix)\s((\d)(?=\.|\)|\s)[\w\.]*)*/i, // AIX
1102
+ /(macintosh|mac(?=_powerpc)|plan\s9|minix|beos|os\/2|amigaos|morphos|risc\sos)/i,
1103
+ // Plan9/Minix/BeOS/OS2/AmigaOS/MorphOS/RISCOS
1104
+ /(unix)\s?([\w\.]+)*/i // UNIX
1105
+ ], [NAME, VERSION]
1106
+ ]
1107
+ };
1108
+
1109
+
1110
+ /////////////////
1111
+ // Constructor
1112
+ ////////////////
1113
+
1114
+
1115
+ var UAParser = function (uastring) {
1116
+
1117
+ var ua = uastring || ((window && window.navigator && window.navigator.userAgent) ? window.navigator.userAgent : EMPTY);
1118
+
1119
+ this.getBrowser = function () {
1120
+ return mapper.rgx.apply(this, regexes.browser);
1121
+ };
1122
+ this.getEngine = function () {
1123
+ return mapper.rgx.apply(this, regexes.engine);
1124
+ };
1125
+ this.getOS = function () {
1126
+ return mapper.rgx.apply(this, regexes.os);
1127
+ };
1128
+ this.getResult = function() {
1129
+ return {
1130
+ ua : this.getUA(),
1131
+ browser : this.getBrowser(),
1132
+ engine : this.getEngine(),
1133
+ os : this.getOS()
1134
+ };
1135
+ };
1136
+ this.getUA = function () {
1137
+ return ua;
1138
+ };
1139
+ this.setUA = function (uastring) {
1140
+ ua = uastring;
1141
+ return this;
1142
+ };
1143
+ this.setUA(ua);
1144
+ };
1145
+
1146
+ return new UAParser().getResult();
1147
+ })();
1148
+
1149
+
1150
+ function version_compare(v1, v2, operator) {
1151
+ // From: http://phpjs.org/functions
1152
+ // + original by: Philippe Jausions (http://pear.php.net/user/jausions)
1153
+ // + original by: Aidan Lister (http://aidanlister.com/)
1154
+ // + reimplemented by: Kankrelune (http://www.webfaktory.info/)
1155
+ // + improved by: Brett Zamir (http://brett-zamir.me)
1156
+ // + improved by: Scott Baker
1157
+ // + improved by: Theriault
1158
+ // * example 1: version_compare('8.2.5rc', '8.2.5a');
1159
+ // * returns 1: 1
1160
+ // * example 2: version_compare('8.2.50', '8.2.52', '<');
1161
+ // * returns 2: true
1162
+ // * example 3: version_compare('5.3.0-dev', '5.3.0');
1163
+ // * returns 3: -1
1164
+ // * example 4: version_compare('4.1.0.52','4.01.0.51');
1165
+ // * returns 4: 1
1166
+
1167
+ // Important: compare must be initialized at 0.
1168
+ var i = 0,
1169
+ x = 0,
1170
+ compare = 0,
1171
+ // vm maps textual PHP versions to negatives so they're less than 0.
1172
+ // PHP currently defines these as CASE-SENSITIVE. It is important to
1173
+ // leave these as negatives so that they can come before numerical versions
1174
+ // and as if no letters were there to begin with.
1175
+ // (1alpha is < 1 and < 1.1 but > 1dev1)
1176
+ // If a non-numerical value can't be mapped to this table, it receives
1177
+ // -7 as its value.
1178
+ vm = {
1179
+ 'dev': -6,
1180
+ 'alpha': -5,
1181
+ 'a': -5,
1182
+ 'beta': -4,
1183
+ 'b': -4,
1184
+ 'RC': -3,
1185
+ 'rc': -3,
1186
+ '#': -2,
1187
+ 'p': 1,
1188
+ 'pl': 1
1189
+ },
1190
+ // This function will be called to prepare each version argument.
1191
+ // It replaces every _, -, and + with a dot.
1192
+ // It surrounds any nonsequence of numbers/dots with dots.
1193
+ // It replaces sequences of dots with a single dot.
1194
+ // version_compare('4..0', '4.0') == 0
1195
+ // Important: A string of 0 length needs to be converted into a value
1196
+ // even less than an unexisting value in vm (-7), hence [-8].
1197
+ // It's also important to not strip spaces because of this.
1198
+ // version_compare('', ' ') == 1
1199
+ prepVersion = function (v) {
1200
+ v = ('' + v).replace(/[_\-+]/g, '.');
1201
+ v = v.replace(/([^.\d]+)/g, '.$1.').replace(/\.{2,}/g, '.');
1202
+ return (!v.length ? [-8] : v.split('.'));
1203
+ },
1204
+ // This converts a version component to a number.
1205
+ // Empty component becomes 0.
1206
+ // Non-numerical component becomes a negative number.
1207
+ // Numerical component becomes itself as an integer.
1208
+ numVersion = function (v) {
1209
+ return !v ? 0 : (isNaN(v) ? vm[v] || -7 : parseInt(v, 10));
1210
+ };
1211
+
1212
+ v1 = prepVersion(v1);
1213
+ v2 = prepVersion(v2);
1214
+ x = Math.max(v1.length, v2.length);
1215
+ for (i = 0; i < x; i++) {
1216
+ if (v1[i] == v2[i]) {
1217
+ continue;
1218
+ }
1219
+ v1[i] = numVersion(v1[i]);
1220
+ v2[i] = numVersion(v2[i]);
1221
+ if (v1[i] < v2[i]) {
1222
+ compare = -1;
1223
+ break;
1224
+ } else if (v1[i] > v2[i]) {
1225
+ compare = 1;
1226
+ break;
1227
+ }
1228
+ }
1229
+ if (!operator) {
1230
+ return compare;
1231
+ }
1232
+
1233
+ // Important: operator is CASE-SENSITIVE.
1234
+ // "No operator" seems to be treated as "<."
1235
+ // Any other values seem to make the function return null.
1236
+ switch (operator) {
1237
+ case '>':
1238
+ case 'gt':
1239
+ return (compare > 0);
1240
+ case '>=':
1241
+ case 'ge':
1242
+ return (compare >= 0);
1243
+ case '<=':
1244
+ case 'le':
1245
+ return (compare <= 0);
1246
+ case '==':
1247
+ case '=':
1248
+ case 'eq':
1249
+ return (compare === 0);
1250
+ case '<>':
1251
+ case '!=':
1252
+ case 'ne':
1253
+ return (compare !== 0);
1254
+ case '':
1255
+ case '<':
1256
+ case 'lt':
1257
+ return (compare < 0);
1258
+ default:
1259
+ return null;
1260
+ }
819
1261
  }
820
1262
 
1263
+
821
1264
  var can = (function() {
822
1265
  var caps = {
823
1266
  define_property: (function() {
@@ -851,7 +1294,7 @@ define("moxie/core/utils/Env", [
851
1294
  try {
852
1295
  if (Basic.inArray(responseType, ['', 'text', 'document']) !== -1) {
853
1296
  return true;
854
- } else if (window.XMLHttpRequest){
1297
+ } else if (window.XMLHttpRequest) {
855
1298
  var xhr = new XMLHttpRequest();
856
1299
  xhr.open('get', '/'); // otherwise Gecko throws an exception
857
1300
  if ('responseType' in xhr) {
@@ -903,16 +1346,26 @@ define("moxie/core/utils/Env", [
903
1346
  };
904
1347
  }());
905
1348
 
1349
+
906
1350
  var Env = {
907
1351
  can: can,
908
- browser: getStr(browser),
909
- version: getVer(navigator.userAgent) || getVer(navigator.appVersion),
910
- OS: getStr(os),
1352
+
1353
+ browser: UAParser.browser.name,
1354
+ version: parseFloat(UAParser.browser.major),
1355
+ os: UAParser.os.name, // everybody intuitively types it in a lowercase for some reason
1356
+ osVersion: UAParser.os.version,
1357
+
1358
+ verComp: version_compare,
1359
+
911
1360
  swf_url: "../flash/Moxie.swf",
912
1361
  xap_url: "../silverlight/Moxie.xap",
913
1362
  global_event_dispatcher: "moxie.core.EventTarget.instance.dispatchEvent"
914
1363
  };
915
1364
 
1365
+ // for backward compatibility
1366
+ // @deprecated Use `Env.os` instead
1367
+ Env.OS = Env.os;
1368
+
916
1369
  return Env;
917
1370
  });
918
1371
 
@@ -942,7 +1395,6 @@ define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
942
1395
  if (typeof id !== 'string') {
943
1396
  return id;
944
1397
  }
945
-
946
1398
  return document.getElementById(id);
947
1399
  };
948
1400
 
@@ -955,14 +1407,11 @@ define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
955
1407
  @param {String} name Class name
956
1408
  */
957
1409
  var hasClass = function(obj, name) {
958
- var regExp;
959
-
960
- if (obj.className === '') {
1410
+ if (!obj.className) {
961
1411
  return false;
962
1412
  }
963
1413
 
964
- regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
965
-
1414
+ var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
966
1415
  return regExp.test(obj.className);
967
1416
  };
968
1417
 
@@ -976,7 +1425,7 @@ define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
976
1425
  */
977
1426
  var addClass = function(obj, name) {
978
1427
  if (!hasClass(obj, name)) {
979
- obj.className = obj.className === '' ? name : obj.className.replace(/\s+$/, '') + ' ' + name;
1428
+ obj.className = !obj.className ? name : obj.className.replace(/\s+$/, '') + ' ' + name;
980
1429
  }
981
1430
  };
982
1431
 
@@ -989,11 +1438,12 @@ define('moxie/core/utils/Dom', ['moxie/core/utils/Env'], function(Env) {
989
1438
  @param {String} name Class name
990
1439
  */
991
1440
  var removeClass = function(obj, name) {
992
- var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
993
-
994
- obj.className = obj.className.replace(regExp, function($0, $1, $2) {
995
- return $1 === ' ' && $2 === ' ' ? ' ' : '';
996
- });
1441
+ if (obj.className) {
1442
+ var regExp = new RegExp("(^|\\s+)"+name+"(\\s+|$)");
1443
+ obj.className = obj.className.replace(regExp, function($0, $1, $2) {
1444
+ return $1 === ' ' && $2 === ' ' ? ' ' : '';
1445
+ });
1446
+ }
997
1447
  };
998
1448
 
999
1449
  /**
@@ -1408,7 +1858,7 @@ define('moxie/core/EventTarget', [
1408
1858
  @return {Boolean} true by default and false if any handler returned false
1409
1859
  */
1410
1860
  dispatchEvent: function(type) {
1411
- var uid, list, args, tmpEvt, evt = {};
1861
+ var uid, list, args, tmpEvt, evt = {}, result = true, undef;
1412
1862
 
1413
1863
  if (Basic.typeOf(type) !== 'string') {
1414
1864
  // we can't use original object directly (because of Silverlight)
@@ -1417,7 +1867,7 @@ define('moxie/core/EventTarget', [
1417
1867
  if (Basic.typeOf(tmpEvt.type) === 'string') {
1418
1868
  type = tmpEvt.type;
1419
1869
 
1420
- if (tmpEvt.total && tmpEvt.loaded) { // progress event
1870
+ if (tmpEvt.total !== undef && tmpEvt.loaded !== undef) { // progress event
1421
1871
  evt.total = tmpEvt.total;
1422
1872
  evt.loaded = tmpEvt.loaded;
1423
1873
  }
@@ -1471,10 +1921,12 @@ define('moxie/core/EventTarget', [
1471
1921
  }
1472
1922
  });
1473
1923
  if (queue.length) {
1474
- Basic.inSeries(queue);
1924
+ Basic.inSeries(queue, function(err) {
1925
+ result = !err;
1926
+ });
1475
1927
  }
1476
1928
  }
1477
- return true;
1929
+ return result;
1478
1930
  },
1479
1931
 
1480
1932
  /**
@@ -1514,7 +1966,7 @@ define('moxie/core/EventTarget', [
1514
1966
  @protected
1515
1967
  */
1516
1968
  trigger: function() {
1517
- this.dispatchEvent.apply(this, arguments);
1969
+ return this.dispatchEvent.apply(this, arguments);
1518
1970
  },
1519
1971
 
1520
1972
 
@@ -1759,9 +2211,9 @@ define('moxie/runtime/Runtime', [
1759
2211
  @param {String} type Sanitized name of the runtime
1760
2212
  @param {Object} [caps] Set of capabilities that differentiate specified runtime
1761
2213
  @param {Object} [modeCaps] Set of capabilities that do require specific operational mode
1762
- @param {String} [defaultMode='browser'] Default operational mode to choose if no required capabilities were requested
2214
+ @param {String} [preferredMode='browser'] Preferred operational mode to choose if no required capabilities were requested
1763
2215
  */
1764
- function Runtime(options, type, caps, modeCaps, defaultMode) {
2216
+ function Runtime(options, type, caps, modeCaps, preferredMode) {
1765
2217
  /**
1766
2218
  Dispatched when runtime is initialized and ready.
1767
2219
  Results in RuntimeInit on a connected component.
@@ -1779,67 +2231,10 @@ define('moxie/runtime/Runtime', [
1779
2231
  var self = this
1780
2232
  , _shim
1781
2233
  , _uid = Basic.guid(type + '_')
2234
+ , defaultMode = preferredMode || 'browser'
1782
2235
  ;
1783
2236
 
1784
-
1785
- /**
1786
- Runtime (not native one) may operate in browser or client mode.
1787
-
1788
- @method _setMode
1789
- @private
1790
- @param {Object} [modeCaps] Set of capabilities that do require specific operational mode
1791
- @param {Object} [defaultMode] The mode to switch to if modeCaps or requiredCaps are empty
1792
- */
1793
- function _setMode(modeCaps, defaultMode) {
1794
- var mode = null
1795
- , rc = options && options.required_caps
1796
- ;
1797
-
1798
- defaultMode = defaultMode || 'browser';
1799
-
1800
- // mode can be effectively set only once
1801
- if (this.mode !== null) {
1802
- return this.mode;
1803
- }
1804
-
1805
- if (rc && !Basic.isEmptyObj(modeCaps)) {
1806
- // loop over required caps and check if they do require the same mode
1807
- Basic.each(rc, function(value, cap) {
1808
- if (modeCaps.hasOwnProperty(cap)) {
1809
- var capMode = modeCaps[cap](value);
1810
-
1811
- // make sure we always have an array
1812
- if (typeof(capMode) === 'string') {
1813
- capMode = [capMode];
1814
- }
1815
-
1816
- if (!mode) {
1817
- mode = capMode;
1818
- } else if (!(mode = Basic.arrayIntersect(mode, capMode))) {
1819
- // if cap requires conflicting mode - runtime cannot fulfill required caps
1820
- return (mode = false);
1821
- }
1822
- }
1823
- });
1824
-
1825
- if (mode) {
1826
- this.mode = Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0];
1827
- } else if (mode === false) {
1828
- this.mode = false;
1829
- }
1830
- }
1831
-
1832
- // if mode still not defined
1833
- if (this.mode === null) {
1834
- this.mode = defaultMode;
1835
- }
1836
-
1837
- // once we got the mode, test against all caps
1838
- if (this.mode && rc && !this.can(rc)) {
1839
- this.mode = false;
1840
- }
1841
- }
1842
-
2237
+ options = options || {};
1843
2238
 
1844
2239
  // register runtime in private hash
1845
2240
  runtimes[_uid] = this;
@@ -1903,7 +2298,12 @@ define('moxie/runtime/Runtime', [
1903
2298
  // e.g. runtime.can('use_http_method', 'put')
1904
2299
  use_http_method: true
1905
2300
  }, caps);
1906
-
2301
+
2302
+
2303
+ // default to the mode that is compatible with preferred caps
2304
+ if (options.preferred_caps) {
2305
+ defaultMode = Runtime.getMode(modeCaps, options.preferred_caps, defaultMode);
2306
+ }
1907
2307
 
1908
2308
  // small extension factory here (is meant to be extended with actual extensions constructors)
1909
2309
  _shim = (function() {
@@ -1974,7 +2374,7 @@ define('moxie/runtime/Runtime', [
1974
2374
  @private
1975
2375
  @type {String|Boolean} current mode or false, if none possible
1976
2376
  */
1977
- mode: null,
2377
+ mode: Runtime.getMode(modeCaps, (options.required_caps), defaultMode),
1978
2378
 
1979
2379
  /**
1980
2380
  id of the DOM container for the runtime (if available)
@@ -2135,7 +2535,10 @@ define('moxie/runtime/Runtime', [
2135
2535
  }
2136
2536
  });
2137
2537
 
2138
- _setMode.call(this, modeCaps, defaultMode);
2538
+ // once we got the mode, test against all caps
2539
+ if (this.mode && options.required_caps && !this.can(options.required_caps)) {
2540
+ this.mode = false;
2541
+ }
2139
2542
  }
2140
2543
 
2141
2544
 
@@ -2205,6 +2608,7 @@ define('moxie/runtime/Runtime', [
2205
2608
  return {
2206
2609
  uid: runtime.uid,
2207
2610
  type: runtime.type,
2611
+ mode: runtime.mode,
2208
2612
  can: function() {
2209
2613
  return runtime.can.apply(runtime, arguments);
2210
2614
  }
@@ -2282,6 +2686,53 @@ define('moxie/runtime/Runtime', [
2282
2686
  };
2283
2687
 
2284
2688
 
2689
+ /**
2690
+ Figure out an operational mode for the specified set of capabilities.
2691
+
2692
+ @method getMode
2693
+ @static
2694
+ @param {Object} modeCaps Set of capabilities that depend on particular runtime mode
2695
+ @param {Object} [requiredCaps] Supplied set of capabilities to find operational mode for
2696
+ @param {String|Boolean} [defaultMode='browser'] Default mode to use
2697
+ @return {String|Boolean} Compatible operational mode
2698
+ */
2699
+ Runtime.getMode = function(modeCaps, requiredCaps, defaultMode) {
2700
+ var mode = null;
2701
+
2702
+ if (Basic.typeOf(defaultMode) === 'undefined') { // only if not specified
2703
+ defaultMode = 'browser';
2704
+ }
2705
+
2706
+ if (requiredCaps && !Basic.isEmptyObj(modeCaps)) {
2707
+ // loop over required caps and check if they do require the same mode
2708
+ Basic.each(requiredCaps, function(value, cap) {
2709
+ if (modeCaps.hasOwnProperty(cap)) {
2710
+ var capMode = modeCaps[cap](value);
2711
+
2712
+ // make sure we always have an array
2713
+ if (typeof(capMode) === 'string') {
2714
+ capMode = [capMode];
2715
+ }
2716
+
2717
+ if (!mode) {
2718
+ mode = capMode;
2719
+ } else if (!(mode = Basic.arrayIntersect(mode, capMode))) {
2720
+ // if cap requires conflicting mode - runtime cannot fulfill required caps
2721
+ return (mode = false);
2722
+ }
2723
+ }
2724
+ });
2725
+
2726
+ if (mode) {
2727
+ return Basic.inArray(defaultMode, mode) !== -1 ? defaultMode : mode[0];
2728
+ } else if (mode === false) {
2729
+ return false;
2730
+ }
2731
+ }
2732
+ return defaultMode;
2733
+ };
2734
+
2735
+
2285
2736
  /**
2286
2737
  Capability check that always returns true
2287
2738
 
@@ -2927,6 +3378,15 @@ define('moxie/file/FileInput', [
2927
3378
  @type {String}
2928
3379
  */
2929
3380
  ruid: null,
3381
+
3382
+ /**
3383
+ Unique id of the runtime container. Useful to get hold of it for various manipulations.
3384
+
3385
+ @property shimid
3386
+ @protected
3387
+ @type {String}
3388
+ */
3389
+ shimid: null,
2930
3390
 
2931
3391
  /**
2932
3392
  Array of selected mOxie.File objects
@@ -2947,6 +3407,7 @@ define('moxie/file/FileInput', [
2947
3407
 
2948
3408
  self.bind('RuntimeInit', function(e, runtime) {
2949
3409
  self.ruid = runtime.uid;
3410
+ self.shimid = runtime.shimid;
2950
3411
 
2951
3412
  self.bind("Ready", function() {
2952
3413
  self.trigger("Refresh");
@@ -3593,10 +4054,10 @@ define('moxie/core/utils/Url', [], function() {
3593
4054
  @method parseUrl
3594
4055
  @for Utils
3595
4056
  @static
3596
- @param {String} str Url to parse (defaults to empty string if undefined)
4057
+ @param {String} url Url to parse (defaults to empty string if undefined)
3597
4058
  @return {Object} Hash containing extracted uri components
3598
4059
  */
3599
- var parseUrl = function(str) {
4060
+ var parseUrl = function(url, currentUrl) {
3600
4061
  var key = ['source', 'scheme', 'authority', 'userInfo', 'user', 'pass', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment']
3601
4062
  , i = key.length
3602
4063
  , ports = {
@@ -3605,7 +4066,7 @@ define('moxie/core/utils/Url', [], function() {
3605
4066
  }
3606
4067
  , uri = {}
3607
4068
  , regex = /^(?:([^:\/?#]+):)?(?:\/\/()(?:(?:()(?:([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?()(?:(()(?:(?:[^?#\/]*\/)*)()(?:[^?#]*))(?:\\?([^#]*))?(?:#(.*))?)/
3608
- , m = regex.exec(str || '') // default to empty string if undefined
4069
+ , m = regex.exec(url || '')
3609
4070
  ;
3610
4071
 
3611
4072
  while (i--) {
@@ -3614,34 +4075,43 @@ define('moxie/core/utils/Url', [], function() {
3614
4075
  }
3615
4076
  }
3616
4077
 
3617
- if (/^[^\/]/.test(uri.path) && !uri.scheme) { // when url is relative, we need to figure out the path ourselves
3618
- var path = document.location.pathname;
3619
- // if path ends with a filename, strip it
3620
- if (!/(\/|\/[^\.]+)$/.test(path)) {
3621
- path = path.replace(/[^\/]+$/, '');
4078
+ // when url is relative, we set the origin and the path ourselves
4079
+ if (!uri.scheme) {
4080
+ // come up with defaults
4081
+ if (!currentUrl || typeof(currentUrl) === 'string') {
4082
+ currentUrl = parseUrl(currentUrl || document.location.href);
4083
+ }
4084
+
4085
+ uri.scheme = currentUrl.scheme;
4086
+ uri.host = currentUrl.host;
4087
+ uri.port = currentUrl.port;
4088
+
4089
+ var path = '';
4090
+ // for urls without trailing slash we need to figure out the path
4091
+ if (/^[^\/]/.test(uri.path)) {
4092
+ path = currentUrl.path;
4093
+ // if path ends with a filename, strip it
4094
+ if (!/(\/|\/[^\.]+)$/.test(path)) {
4095
+ path = path.replace(/\/[^\/]+$/, '/');
4096
+ } else {
4097
+ path += '/';
4098
+ }
3622
4099
  }
3623
- uri.host = document.location.hostname;
3624
4100
  uri.path = path + (uri.path || ''); // site may reside at domain.com or domain.com/subdir
3625
4101
  }
3626
4102
 
3627
- if (!uri.scheme) {
3628
- uri.scheme = document.location.protocol.replace(/:$/, '');
3629
- }
3630
-
3631
- if (!uri.host) {
3632
- uri.host = document.location.hostname;
3633
- }
3634
-
3635
4103
  if (!uri.port) {
3636
- uri.port = document.location.port || ports[uri.scheme] || 80;
4104
+ uri.port = ports[uri.scheme] || 80;
3637
4105
  }
4106
+
3638
4107
  uri.port = parseInt(uri.port, 10);
3639
4108
 
3640
4109
  if (!uri.path) {
3641
4110
  uri.path = "/";
3642
4111
  }
3643
-
4112
+
3644
4113
  delete uri.source;
4114
+
3645
4115
  return uri;
3646
4116
  };
3647
4117
 
@@ -3787,7 +4257,7 @@ define("moxie/xhr/FormData", [
3787
4257
  @constructor
3788
4258
  */
3789
4259
  function FormData() {
3790
- var _blobField, _fields = {}, _name = "";
4260
+ var _blob, _fields = [];
3791
4261
 
3792
4262
  Basic.extend(this, {
3793
4263
  /**
@@ -3800,29 +4270,29 @@ define("moxie/xhr/FormData", [
3800
4270
  append: function(name, value) {
3801
4271
  var self = this, valueType = Basic.typeOf(value);
3802
4272
 
4273
+ // according to specs value might be either Blob or String
3803
4274
  if (value instanceof Blob) {
3804
- if (_blobField) {
3805
- delete _fields[_blobField];
3806
- }
3807
- _blobField = name;
3808
- _fields[name] = [value]; // unfortunately we can only send single Blob in one FormData
4275
+ _blob = {
4276
+ name: name,
4277
+ value: value // unfortunately we can only send single Blob in one FormData
4278
+ };
3809
4279
  } else if ('array' === valueType) {
3810
4280
  name += '[]';
3811
4281
 
3812
4282
  Basic.each(value, function(value) {
3813
- self.append.call(self, name, value);
4283
+ self.append(name, value);
3814
4284
  });
3815
4285
  } else if ('object' === valueType) {
3816
4286
  Basic.each(value, function(value, key) {
3817
- self.append.call(self, name + '[' + key + ']', value);
4287
+ self.append(name + '[' + key + ']', value);
3818
4288
  });
4289
+ } else if ('null' === valueType || 'undefined' === valueType || 'number' === valueType && isNaN(value)) {
4290
+ self.append(name, "false");
3819
4291
  } else {
3820
- value = value.toString(); // according to specs value might be either Blob or String
3821
-
3822
- if (!_fields[name]) {
3823
- _fields[name] = [];
3824
- }
3825
- _fields[name].push(value);
4292
+ _fields.push({
4293
+ name: name,
4294
+ value: value.toString()
4295
+ });
3826
4296
  }
3827
4297
  },
3828
4298
 
@@ -3833,7 +4303,7 @@ define("moxie/xhr/FormData", [
3833
4303
  @return {Boolean}
3834
4304
  */
3835
4305
  hasBlob: function() {
3836
- return !!_blobField;
4306
+ return !!this.getBlob();
3837
4307
  },
3838
4308
 
3839
4309
  /**
@@ -3843,7 +4313,7 @@ define("moxie/xhr/FormData", [
3843
4313
  @return {Object} Either Blob if found or null
3844
4314
  */
3845
4315
  getBlob: function() {
3846
- return _fields[_blobField] && _fields[_blobField][0] || null;
4316
+ return _blob && _blob.value || null;
3847
4317
  },
3848
4318
 
3849
4319
  /**
@@ -3853,7 +4323,7 @@ define("moxie/xhr/FormData", [
3853
4323
  @return {String} Either Blob field name or null
3854
4324
  */
3855
4325
  getBlobName: function() {
3856
- return _blobField || null;
4326
+ return _blob && _blob.name || null;
3857
4327
  },
3858
4328
 
3859
4329
  /**
@@ -3863,17 +4333,18 @@ define("moxie/xhr/FormData", [
3863
4333
  @param {Function} cb Callback to call for each field
3864
4334
  */
3865
4335
  each: function(cb) {
3866
- Basic.each(_fields, function(value, name) {
3867
- Basic.each(value, function(value) {
3868
- cb(value, name);
3869
- });
4336
+ Basic.each(_fields, function(field) {
4337
+ cb(field.value, field.name);
3870
4338
  });
4339
+
4340
+ if (_blob) {
4341
+ cb(_blob.value, _blob.name);
4342
+ }
3871
4343
  },
3872
4344
 
3873
4345
  destroy: function() {
3874
- _blobField = null;
3875
- _name = "";
3876
- _fields = {};
4346
+ _blob = null;
4347
+ _fields = [];
3877
4348
  }
3878
4349
  });
3879
4350
  }
@@ -4452,9 +4923,9 @@ define("moxie/xhr/XMLHttpRequest", [
4452
4923
  // 8.2
4453
4924
  // this.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr
4454
4925
  // 8.3
4455
- if (!_upload_complete_flag) {
4926
+ //if (!_upload_complete_flag) {
4456
4927
  // this.upload.dispatchEvent('loadstart'); // will be dispatched either by native or runtime xhr
4457
- }
4928
+ //}
4458
4929
  }
4459
4930
  // 8.5 - Return the send() method call, but continue running the steps in this algorithm.
4460
4931
  _doXHR.call(this, data);
@@ -4968,329 +5439,6 @@ define("moxie/runtime/Transporter", [
4968
5439
  return Transporter;
4969
5440
  });
4970
5441
 
4971
- // Included from: src/javascript/core/JSON.js
4972
-
4973
- /**
4974
- * JSON.js
4975
- *
4976
- * Copyright 2013, Moxiecode Systems AB
4977
- * Released under GPL License.
4978
- *
4979
- * License: http://www.plupload.com/license
4980
- * Contributing: http://www.plupload.com/contributing
4981
- */
4982
-
4983
- /*jshint smarttabs:true */
4984
-
4985
- define("moxie/core/JSON", [], function() {
4986
- /**
4987
- Parse string into the JSON object in a safe way
4988
- @credits Douglas Crockford: https://github.com/douglascrockford/JSON-js/blob/master/json_parse.js
4989
-
4990
- @method parse
4991
- @static
4992
- @protected
4993
- @param {Object} obj Object to add property to
4994
- @param {String} prop Property name
4995
- @param {Object} desc Set of key-value pairs defining descriptor for the property
4996
- */
4997
- return !!window.JSON && JSON.parse || (function() {
4998
- "use strict";
4999
-
5000
- // This is a function that can parse a JSON text, producing a JavaScript
5001
- // data structure. It is a simple, recursive descent parser. It does not use
5002
- // eval or regular expressions, so it can be used as a model for implementing
5003
- // a JSON parser in other languages.
5004
-
5005
- // We are defining the function inside of another function to avoid
5006
- // creating global variables.
5007
-
5008
- var at, // The index of the current character
5009
- ch, // The current character
5010
- escapee = {
5011
- '"': '"',
5012
- '\\': '\\',
5013
- '/': '/',
5014
- b: '\b',
5015
- f: '\f',
5016
- n: '\n',
5017
- r: '\r',
5018
- t: '\t'
5019
- },
5020
- text,
5021
-
5022
- error = function (m) {
5023
-
5024
- // Call error when something is wrong.
5025
-
5026
- throw {
5027
- name: 'SyntaxError',
5028
- message: m,
5029
- at: at,
5030
- text: text
5031
- };
5032
- },
5033
-
5034
- next = function (c) {
5035
-
5036
- // If a c parameter is provided, verify that it matches the current character.
5037
-
5038
- if (c && c !== ch) {
5039
- error("Expected '" + c + "' instead of '" + ch + "'");
5040
- }
5041
-
5042
- // Get the next character. When there are no more characters,
5043
- // return the empty string.
5044
-
5045
- ch = text.charAt(at);
5046
- at += 1;
5047
- return ch;
5048
- },
5049
-
5050
- number = function () {
5051
-
5052
- // Parse a number value.
5053
-
5054
- var number,
5055
- string = '';
5056
-
5057
- if (ch === '-') {
5058
- string = '-';
5059
- next('-');
5060
- }
5061
- while (ch >= '0' && ch <= '9') {
5062
- string += ch;
5063
- next();
5064
- }
5065
- if (ch === '.') {
5066
- string += '.';
5067
- while (next() && ch >= '0' && ch <= '9') {
5068
- string += ch;
5069
- }
5070
- }
5071
- if (ch === 'e' || ch === 'E') {
5072
- string += ch;
5073
- next();
5074
- if (ch === '-' || ch === '+') {
5075
- string += ch;
5076
- next();
5077
- }
5078
- while (ch >= '0' && ch <= '9') {
5079
- string += ch;
5080
- next();
5081
- }
5082
- }
5083
- number = +string;
5084
- if (!isFinite(number)) {
5085
- error("Bad number");
5086
- } else {
5087
- return number;
5088
- }
5089
- },
5090
-
5091
- string = function () {
5092
-
5093
- // Parse a string value.
5094
-
5095
- var hex,
5096
- i,
5097
- string = '',
5098
- uffff;
5099
-
5100
- // When parsing for string values, we must look for " and \ characters.
5101
-
5102
- if (ch === '"') {
5103
- while (next()) {
5104
- if (ch === '"') {
5105
- next();
5106
- return string;
5107
- } else if (ch === '\\') {
5108
- next();
5109
- if (ch === 'u') {
5110
- uffff = 0;
5111
- for (i = 0; i < 4; i += 1) {
5112
- hex = parseInt(next(), 16);
5113
- if (!isFinite(hex)) {
5114
- break;
5115
- }
5116
- uffff = uffff * 16 + hex;
5117
- }
5118
- string += String.fromCharCode(uffff);
5119
- } else if (typeof escapee[ch] === 'string') {
5120
- string += escapee[ch];
5121
- } else {
5122
- break;
5123
- }
5124
- } else {
5125
- string += ch;
5126
- }
5127
- }
5128
- }
5129
- error("Bad string");
5130
- },
5131
-
5132
- white = function () {
5133
-
5134
- // Skip whitespace.
5135
-
5136
- while (ch && ch <= ' ') {
5137
- next();
5138
- }
5139
- },
5140
-
5141
- word = function () {
5142
-
5143
- // true, false, or null.
5144
-
5145
- switch (ch) {
5146
- case 't':
5147
- next('t');
5148
- next('r');
5149
- next('u');
5150
- next('e');
5151
- return true;
5152
- case 'f':
5153
- next('f');
5154
- next('a');
5155
- next('l');
5156
- next('s');
5157
- next('e');
5158
- return false;
5159
- case 'n':
5160
- next('n');
5161
- next('u');
5162
- next('l');
5163
- next('l');
5164
- return null;
5165
- }
5166
- error("Unexpected '" + ch + "'");
5167
- },
5168
-
5169
- value, // Place holder for the value function.
5170
-
5171
- array = function () {
5172
-
5173
- // Parse an array value.
5174
-
5175
- var array = [];
5176
-
5177
- if (ch === '[') {
5178
- next('[');
5179
- white();
5180
- if (ch === ']') {
5181
- next(']');
5182
- return array; // empty array
5183
- }
5184
- while (ch) {
5185
- array.push(value());
5186
- white();
5187
- if (ch === ']') {
5188
- next(']');
5189
- return array;
5190
- }
5191
- next(',');
5192
- white();
5193
- }
5194
- }
5195
- error("Bad array");
5196
- },
5197
-
5198
- object = function () {
5199
-
5200
- // Parse an object value.
5201
-
5202
- var key,
5203
- object = {};
5204
-
5205
- if (ch === '{') {
5206
- next('{');
5207
- white();
5208
- if (ch === '}') {
5209
- next('}');
5210
- return object; // empty object
5211
- }
5212
- while (ch) {
5213
- key = string();
5214
- white();
5215
- next(':');
5216
- if (Object.hasOwnProperty.call(object, key)) {
5217
- error('Duplicate key "' + key + '"');
5218
- }
5219
- object[key] = value();
5220
- white();
5221
- if (ch === '}') {
5222
- next('}');
5223
- return object;
5224
- }
5225
- next(',');
5226
- white();
5227
- }
5228
- }
5229
- error("Bad object");
5230
- };
5231
-
5232
- value = function () {
5233
-
5234
- // Parse a JSON value. It could be an object, an array, a string, a number,
5235
- // or a word.
5236
-
5237
- white();
5238
- switch (ch) {
5239
- case '{':
5240
- return object();
5241
- case '[':
5242
- return array();
5243
- case '"':
5244
- return string();
5245
- case '-':
5246
- return number();
5247
- default:
5248
- return ch >= '0' && ch <= '9' ? number() : word();
5249
- }
5250
- };
5251
-
5252
- // Return the json_parse function. It will have access to all of the above
5253
- // functions and variables.
5254
-
5255
- return function (source, reviver) {
5256
- var result;
5257
-
5258
- text = source;
5259
- at = 0;
5260
- ch = ' ';
5261
- result = value();
5262
- white();
5263
- if (ch) {
5264
- error("Syntax error");
5265
- }
5266
-
5267
- // If there is a reviver function, we recursively walk the new structure,
5268
- // passing each name/value pair to the reviver function for possible
5269
- // transformation, starting with a temporary root object that holds the result
5270
- // in an empty key. If there is not a reviver function, we simply return the
5271
- // result.
5272
-
5273
- return typeof reviver === 'function' ? (function walk(holder, key) {
5274
- var k, v, value = holder[key];
5275
- if (value && typeof value === 'object') {
5276
- for (k in value) {
5277
- if (Object.prototype.hasOwnProperty.call(value, k)) {
5278
- v = walk(value, k);
5279
- if (v !== undefined) {
5280
- value[k] = v;
5281
- } else {
5282
- delete value[k];
5283
- }
5284
- }
5285
- }
5286
- }
5287
- return reviver.call(holder, key, value);
5288
- }({'': result}, '')) : result;
5289
- };
5290
- }());
5291
-
5292
- });
5293
-
5294
5442
  // Included from: src/javascript/image/Image.js
5295
5443
 
5296
5444
  /**
@@ -5316,9 +5464,8 @@ define("moxie/image/Image", [
5316
5464
  "moxie/core/EventTarget",
5317
5465
  "moxie/file/Blob",
5318
5466
  "moxie/file/File",
5319
- "moxie/core/utils/Encode",
5320
- "moxie/core/JSON"
5321
- ], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode, parseJSON) {
5467
+ "moxie/core/utils/Encode"
5468
+ ], function(Basic, Dom, x, FileReaderSync, XMLHttpRequest, Runtime, RuntimeClient, Transporter, Env, EventTarget, Blob, File, Encode) {
5322
5469
  /**
5323
5470
  Image preloading and manipulation utility. Additionally it provides access to image meta info (Exif, GPS) and raw binary data.
5324
5471
 
@@ -5745,28 +5892,18 @@ define("moxie/image/Image", [
5745
5892
  info = this.getRuntime().exec.call(this, 'Image', 'getInfo');
5746
5893
  }
5747
5894
 
5748
- if (info) {
5749
- if (Basic.typeOf(info.meta) === 'string') { // might be a JSON string
5750
- try {
5751
- this.meta = parseJSON(info.meta);
5752
- } catch(ex) {}
5753
- } else {
5754
- this.meta = info.meta;
5755
- }
5756
- }
5757
-
5758
- Basic.extend(this, { // info object might be non-enumerable (as returned from SilverLight for example)
5759
- size: parseInt(info.size, 10),
5760
- width: parseInt(info.width, 10),
5761
- height: parseInt(info.height, 10),
5762
- type: info.type
5763
- });
5895
+ this.size = info.size;
5896
+ this.width = info.width;
5897
+ this.height = info.height;
5898
+ this.type = info.type;
5899
+ this.meta = info.meta;
5764
5900
 
5765
5901
  // update file name, only if empty
5766
5902
  if (this.name === '') {
5767
5903
  this.name = info.name;
5768
5904
  }
5769
5905
  }
5906
+
5770
5907
 
5771
5908
  function _load(src) {
5772
5909
  var srcType = Basic.typeOf(src);
@@ -5948,11 +6085,10 @@ define("moxie/runtime/html5/Runtime", [
5948
6085
  }()),
5949
6086
  return_response_headers: True,
5950
6087
  return_response_type: function(responseType) {
5951
- if (responseType === 'json') {
5952
- return true; // we can fake this one even if it's not supported
5953
- } else {
5954
- return Env.can('return_response_type', responseType);
5955
- }
6088
+ if (responseType === 'json' && !!window.JSON) { // we can fake this one even if it's not supported
6089
+ return true;
6090
+ }
6091
+ return Env.can('return_response_type', responseType);
5956
6092
  },
5957
6093
  return_status_code: True,
5958
6094
  report_upload_progress: Test(window.XMLHttpRequest && new XMLHttpRequest().upload),
@@ -5966,7 +6102,10 @@ define("moxie/runtime/html5/Runtime", [
5966
6102
  return I.can('select_file') && Env.browser === 'Chrome' && Env.version >= 21;
5967
6103
  },
5968
6104
  select_multiple: function() {
5969
- return I.can('select_file') && !(Env.browser === 'Safari' && Env.OS === 'Windows');
6105
+ // it is buggy on Safari Windows and iOS
6106
+ return I.can('select_file') &&
6107
+ !(Env.browser === 'Safari' && Env.os === 'Windows') &&
6108
+ !(Env.os === 'iOS' && Env.verComp(Env.osVersion, "7.0.4", '<'));
5970
6109
  },
5971
6110
  send_binary_string: Test(window.XMLHttpRequest && (new XMLHttpRequest().sendAsBinary || (window.Uint8Array && window.ArrayBuffer))),
5972
6111
  send_custom_headers: Test(window.XMLHttpRequest),
@@ -6383,7 +6522,10 @@ define("moxie/runtime/html5/file/FileInput", [
6383
6522
  },
6384
6523
 
6385
6524
  destroy: function() {
6386
- var I = this.getRuntime(), shimContainer = I.getShimContainer();
6525
+ var I = this.getRuntime()
6526
+ , shim = I.getShim()
6527
+ , shimContainer = I.getShimContainer()
6528
+ ;
6387
6529
 
6388
6530
  Events.removeAllEvents(shimContainer, this.uid);
6389
6531
  Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
@@ -6392,7 +6534,10 @@ define("moxie/runtime/html5/file/FileInput", [
6392
6534
  if (shimContainer) {
6393
6535
  shimContainer.innerHTML = '';
6394
6536
  }
6395
- _files = _options = null;
6537
+
6538
+ shim.removeInstance(this.uid);
6539
+
6540
+ _files = _options = shimContainer = shim = null;
6396
6541
  }
6397
6542
  });
6398
6543
  }
@@ -6449,11 +6594,7 @@ define("moxie/runtime/html5/file/FileDrop", [
6449
6594
 
6450
6595
  // Chrome 21+ accepts folders via Drag'n'Drop
6451
6596
  if (e.dataTransfer.items && e.dataTransfer.items[0].webkitGetAsEntry) {
6452
- var entries = [];
6453
- Basic.each(e.dataTransfer.items, function(item) {
6454
- entries.push(item.webkitGetAsEntry());
6455
- });
6456
- _readEntries(entries, function() {
6597
+ _readItems(e.dataTransfer.items, function() {
6457
6598
  comp.trigger("drop");
6458
6599
  });
6459
6600
  } else {
@@ -6505,6 +6646,32 @@ define("moxie/runtime/html5/file/FileDrop", [
6505
6646
  }
6506
6647
 
6507
6648
 
6649
+ function _readItems(items, cb) {
6650
+ var entries = [];
6651
+ Basic.each(items, function(item) {
6652
+ var entry = item.webkitGetAsEntry();
6653
+ // Address #998 (https://code.google.com/p/chromium/issues/detail?id=332579)
6654
+ if (entry) {
6655
+ // file() fails on OSX when the filename contains a special character (e.g. umlaut): see #61
6656
+ if (entry.isFile) {
6657
+ var file = item.getAsFile();
6658
+ if (_isAcceptable(file)) {
6659
+ _files.push(file);
6660
+ }
6661
+ } else {
6662
+ entries.push(entry);
6663
+ }
6664
+ }
6665
+ });
6666
+
6667
+ if (entries.length) {
6668
+ _readEntries(entries, cb);
6669
+ } else {
6670
+ cb();
6671
+ }
6672
+ }
6673
+
6674
+
6508
6675
  function _readEntries(entries, cb) {
6509
6676
  var queue = [];
6510
6677
  Basic.each(entries, function(entry) {
@@ -6667,12 +6834,12 @@ define("moxie/runtime/html5/xhr/XMLHttpRequest", [
6667
6834
  "moxie/file/Blob",
6668
6835
  "moxie/xhr/FormData",
6669
6836
  "moxie/core/Exceptions",
6670
- "moxie/core/utils/Env",
6671
- "moxie/core/JSON"
6672
- ], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env, parseJSON) {
6837
+ "moxie/core/utils/Env"
6838
+ ], function(extensions, Basic, Mime, Url, File, Blob, FormData, x, Env) {
6673
6839
 
6674
6840
  function XMLHttpRequest() {
6675
- var _xhr
6841
+ var self = this
6842
+ , _xhr
6676
6843
  , _filename
6677
6844
  ;
6678
6845
 
@@ -6881,7 +7048,7 @@ define("moxie/runtime/html5/xhr/XMLHttpRequest", [
6881
7048
 
6882
7049
  case 'json':
6883
7050
  if (!Env.can('return_response_type', 'json')) {
6884
- return _xhr.status === 200 ? parseJSON(_xhr.responseText) : null;
7051
+ return _xhr.status === 200 && !!window.JSON ? JSON.parse(_xhr.responseText) : null;
6885
7052
  }
6886
7053
  return _xhr.response;
6887
7054
 
@@ -6997,7 +7164,7 @@ define("moxie/runtime/html5/xhr/XMLHttpRequest", [
6997
7164
  // Build RFC2388 blob
6998
7165
  multipart += dashdash + boundary + crlf +
6999
7166
  'Content-Disposition: form-data; name="' + name + '"; filename="' + unescape(encodeURIComponent(value.name || 'blob')) + '"' + crlf +
7000
- 'Content-Type: ' + value.type + crlf + crlf +
7167
+ 'Content-Type: ' + (value.type || 'application/octet-stream') + crlf + crlf +
7001
7168
  value.getSource() + crlf;
7002
7169
  } else {
7003
7170
  multipart += dashdash + boundary + crlf +
@@ -8236,12 +8403,12 @@ define("moxie/runtime/html5/image/Image", [
8236
8403
  "moxie/core/utils/Basic",
8237
8404
  "moxie/core/Exceptions",
8238
8405
  "moxie/core/utils/Encode",
8239
- "moxie/file/Blob",
8406
+ "moxie/file/File",
8240
8407
  "moxie/runtime/html5/image/ImageInfo",
8241
8408
  "moxie/runtime/html5/image/MegaPixel",
8242
8409
  "moxie/core/utils/Mime",
8243
8410
  "moxie/core/utils/Env"
8244
- ], function(extensions, Basic, x, Encode, Blob, ImageInfo, MegaPixel, Mime, Env) {
8411
+ ], function(extensions, Basic, x, Encode, File, ImageInfo, MegaPixel, Mime, Env) {
8245
8412
 
8246
8413
  function HTML5Image() {
8247
8414
  var me = this
@@ -8279,7 +8446,7 @@ define("moxie/runtime/html5/image/Image", [
8279
8446
  loadFromImage: function(img, exact) {
8280
8447
  this.meta = img.meta;
8281
8448
 
8282
- _blob = new Blob(null, {
8449
+ _blob = new File(null, {
8283
8450
  name: img.name,
8284
8451
  size: img.size,
8285
8452
  type: img.type
@@ -8323,7 +8490,8 @@ define("moxie/runtime/html5/image/Image", [
8323
8490
  // if different mime type requested prepare image for conversion
8324
8491
  _downsize.call(this, this.width, this.height, false);
8325
8492
  }
8326
- return new Blob(null, {
8493
+ return new File(null, {
8494
+ name: _blob.name || '',
8327
8495
  type: type,
8328
8496
  data: me.getAsBinaryString.call(this, type, quality)
8329
8497
  });
@@ -8466,18 +8634,27 @@ define("moxie/runtime/html5/image/Image", [
8466
8634
  }
8467
8635
 
8468
8636
  function _downsize(width, height, crop, preserveHeaders) {
8469
- var self = this, ctx, scale, mathFn, x, y, img, imgWidth, imgHeight, orientation;
8637
+ var self = this
8638
+ , scale
8639
+ , mathFn
8640
+ , x = 0
8641
+ , y = 0
8642
+ , img
8643
+ , destWidth
8644
+ , destHeight
8645
+ , orientation
8646
+ ;
8470
8647
 
8471
- _preserveHeaders = preserveHeaders; // we will need to check this on export
8648
+ _preserveHeaders = preserveHeaders; // we will need to check this on export (see getAsBinaryString())
8472
8649
 
8473
8650
  // take into account orientation tag
8474
8651
  orientation = (this.meta && this.meta.tiff && this.meta.tiff.Orientation) || 1;
8475
8652
 
8476
8653
  if (Basic.inArray(orientation, [5,6,7,8]) !== -1) { // values that require 90 degree rotation
8477
8654
  // swap dimensions
8478
- var mem = width;
8655
+ var tmp = width;
8479
8656
  width = height;
8480
- height = mem;
8657
+ height = tmp;
8481
8658
  }
8482
8659
 
8483
8660
  img = _getImg();
@@ -8492,34 +8669,40 @@ define("moxie/runtime/html5/image/Image", [
8492
8669
  return;
8493
8670
  }
8494
8671
 
8495
- imgWidth = Math.round(img.width * scale);
8496
- imgHeight = Math.round(img.height * scale);
8497
-
8498
8672
  // prepare canvas if necessary
8499
8673
  if (!_canvas) {
8500
8674
  _canvas = document.createElement("canvas");
8501
8675
  }
8502
8676
 
8503
- ctx = _canvas.getContext('2d');
8677
+ // calculate dimensions of proportionally resized image
8678
+ destWidth = Math.round(img.width * scale);
8679
+ destHeight = Math.round(img.height * scale);
8680
+
8504
8681
 
8505
8682
  // scale image and canvas
8506
8683
  if (crop) {
8507
8684
  _canvas.width = width;
8508
8685
  _canvas.height = height;
8686
+
8687
+ // if dimensions of the resulting image still larger than canvas, center it
8688
+ if (destWidth > width) {
8689
+ x = Math.round((destWidth - width) / 2);
8690
+ }
8691
+
8692
+ if (destHeight > height) {
8693
+ y = Math.round((destHeight - height) / 2);
8694
+ }
8509
8695
  } else {
8510
- _canvas.width = imgWidth;
8511
- _canvas.height = imgHeight;
8696
+ _canvas.width = destWidth;
8697
+ _canvas.height = destHeight;
8512
8698
  }
8513
8699
 
8514
- // if dimensions of the resulting image still larger than canvas, center it
8515
- x = imgWidth > _canvas.width ? Math.round((imgWidth - _canvas.width) / 2) : 0;
8516
- y = imgHeight > _canvas.height ? Math.round((imgHeight - _canvas.height) / 2) : 0;
8517
-
8700
+ // rotate if required, according to orientation tag
8518
8701
  if (!_preserveHeaders) {
8519
8702
  _rotateToOrientaion(_canvas.width, _canvas.height, orientation);
8520
8703
  }
8521
8704
 
8522
- _drawToCanvas.call(this, img, _canvas, -x, -y, imgWidth, imgHeight);
8705
+ _drawToCanvas.call(this, img, _canvas, -x, -y, destWidth, destHeight);
8523
8706
 
8524
8707
  this.width = _canvas.width;
8525
8708
  this.height = _canvas.height;
@@ -8706,7 +8889,10 @@ define("moxie/runtime/flash/Runtime", [
8706
8889
  resize_image: Runtime.capTrue,
8707
8890
  return_response_headers: false,
8708
8891
  return_response_type: function(responseType) {
8709
- return !Basic.arrayDiff(responseType, ['', 'text', 'json', 'document']) || I.mode === 'browser';
8892
+ if (responseType === 'json' && !!window.JSON) {
8893
+ return true;
8894
+ }
8895
+ return !Basic.arrayDiff(responseType, ['', 'text', 'document']) || I.mode === 'browser';
8710
8896
  },
8711
8897
  return_status_code: function(code) {
8712
8898
  return I.mode === 'browser' || !Basic.arrayDiff(code, [200, 404]);
@@ -8769,7 +8955,7 @@ define("moxie/runtime/flash/Runtime", [
8769
8955
  }, 'client');
8770
8956
 
8771
8957
 
8772
- // minimal requirement Flash Player 10
8958
+ // minimal requirement for Flash Player version
8773
8959
  if (getShimVersion() < 10) {
8774
8960
  this.mode = false; // with falsy mode, runtime won't operable, no matter what the mode was before
8775
8961
  }
@@ -9073,9 +9259,8 @@ define("moxie/runtime/flash/xhr/XMLHttpRequest", [
9073
9259
  "moxie/file/File",
9074
9260
  "moxie/file/FileReaderSync",
9075
9261
  "moxie/xhr/FormData",
9076
- "moxie/runtime/Transporter",
9077
- "moxie/core/JSON"
9078
- ], function(extensions, Basic, Blob, File, FileReaderSync, FormData, Transporter, parseJSON) {
9262
+ "moxie/runtime/Transporter"
9263
+ ], function(extensions, Basic, Blob, File, FileReaderSync, FormData, Transporter) {
9079
9264
 
9080
9265
  var XMLHttpRequest = {
9081
9266
 
@@ -9165,24 +9350,20 @@ define("moxie/runtime/flash/xhr/XMLHttpRequest", [
9165
9350
 
9166
9351
  if ('blob' === responseType) {
9167
9352
  return blob;
9168
- } else if (!!~Basic.inArray(responseType, ["", "text"])) {
9169
- frs = new FileReaderSync();
9170
- return frs.readAsText(blob);
9171
- } else if ('arraybuffer' === responseType) {
9172
-
9173
- // do something
9353
+ }
9174
9354
 
9175
- } else if ('json' === responseType) {
9355
+ try {
9176
9356
  frs = new FileReaderSync();
9177
-
9178
- try {
9179
- return parseJSON(frs.readAsText(blob));
9180
- } catch (ex) {
9181
- return null;
9357
+
9358
+ if (!!~Basic.inArray(responseType, ["", "text"])) {
9359
+ return frs.readAsText(blob);
9360
+ } else if ('json' === responseType && !!window.JSON) {
9361
+ return JSON.parse(frs.readAsText(blob));
9182
9362
  }
9363
+ } finally {
9364
+ blob.destroy();
9183
9365
  }
9184
9366
  }
9185
-
9186
9367
  return null;
9187
9368
  },
9188
9369
 
@@ -9195,9 +9376,9 @@ define("moxie/runtime/flash/xhr/XMLHttpRequest", [
9195
9376
  // this.dispatchEvent('progress');
9196
9377
  this.dispatchEvent('abort');
9197
9378
 
9198
- if (!upload_complete_flag) {
9379
+ //if (!upload_complete_flag) {
9199
9380
  // this.dispatchEvent('uploadprogress');
9200
- }
9381
+ //}
9201
9382
  }
9202
9383
  };
9203
9384
 
@@ -9424,7 +9605,13 @@ define("moxie/runtime/silverlight/Runtime", [
9424
9605
  return_response_headers: function(value) {
9425
9606
  return value && I.mode === 'client';
9426
9607
  },
9427
- return_response_type: Runtime.capTrue,
9608
+ return_response_type: function(responseType) {
9609
+ if (responseType !== 'json') {
9610
+ return true;
9611
+ } else {
9612
+ return !!window.JSON;
9613
+ }
9614
+ },
9428
9615
  return_status_code: function(code) {
9429
9616
  return I.mode === 'client' || !Basic.arrayDiff(code, [200, 404]);
9430
9617
  },
@@ -9758,7 +9945,51 @@ define("moxie/runtime/silverlight/image/Image", [
9758
9945
  "moxie/core/utils/Basic",
9759
9946
  "moxie/runtime/flash/image/Image"
9760
9947
  ], function(extensions, Basic, Image) {
9761
- return (extensions.Image = Basic.extend({}, Image));
9948
+ return (extensions.Image = Basic.extend({}, Image, {
9949
+
9950
+ getInfo: function() {
9951
+ var self = this.getRuntime()
9952
+ , grps = ['tiff', 'exif', 'gps']
9953
+ , info = { meta: {} }
9954
+ , rawInfo = self.shimExec.call(this, 'Image', 'getInfo')
9955
+ ;
9956
+
9957
+ if (rawInfo.meta) {
9958
+ Basic.each(grps, function(grp) {
9959
+ var meta = rawInfo.meta[grp]
9960
+ , tag
9961
+ , i
9962
+ , length
9963
+ , value
9964
+ ;
9965
+ if (meta && meta.keys) {
9966
+ info.meta[grp] = {};
9967
+ for (i = 0, length = meta.keys.length; i < length; i++) {
9968
+ tag = meta.keys[i];
9969
+ value = meta[tag];
9970
+ if (value) {
9971
+ // convert numbers
9972
+ if (/^(\d|[1-9]\d+)$/.test(value)) { // integer (make sure doesn't start with zero)
9973
+ value = parseInt(value, 10);
9974
+ } else if (/^\d*\.\d+$/.test(value)) { // double
9975
+ value = parseFloat(value);
9976
+ }
9977
+ info.meta[grp][tag] = value;
9978
+ }
9979
+ }
9980
+ }
9981
+ });
9982
+ }
9983
+
9984
+ info.width = parseInt(rawInfo.width, 10);
9985
+ info.height = parseInt(rawInfo.height, 10);
9986
+ info.size = parseInt(rawInfo.size, 10);
9987
+ info.type = rawInfo.type;
9988
+ info.name = rawInfo.name;
9989
+
9990
+ return info;
9991
+ }
9992
+ }));
9762
9993
  });
9763
9994
 
9764
9995
  // Included from: src/javascript/runtime/html4/Runtime.js
@@ -9811,7 +10042,10 @@ define("moxie/runtime/html4/Runtime", [
9811
10042
  report_upload_progress: false,
9812
10043
  return_response_headers: false,
9813
10044
  return_response_type: function(responseType) {
9814
- return !!~Basic.inArray(responseType, ['json', 'text', 'document', '']);
10045
+ if (responseType === 'json' && !!window.JSON) {
10046
+ return true;
10047
+ }
10048
+ return !!~Basic.inArray(responseType, ['text', 'document', '']);
9815
10049
  },
9816
10050
  return_status_code: function(code) {
9817
10051
  return !Basic.arrayDiff(code, [200, 404]);
@@ -9830,7 +10064,6 @@ define("moxie/runtime/html4/Runtime", [
9830
10064
  summon_file_dialog: Test(function() { // yeah... some dirty sniffing here...
9831
10065
  return (Env.browser === 'Firefox' && Env.version >= 4) ||
9832
10066
  (Env.browser === 'Opera' && Env.version >= 12) ||
9833
- (Env.browser === 'IE' && Env.version >= 10) ||
9834
10067
  !!~Basic.inArray(Env.browser, ['Chrome', 'Safari']);
9835
10068
  }()),
9836
10069
  upload_filesize: True,
@@ -9922,7 +10155,7 @@ define("moxie/runtime/html4/file/FileInput", [
9922
10155
  input = document.createElement('input');
9923
10156
  input.setAttribute('id', uid);
9924
10157
  input.setAttribute('type', 'file');
9925
- input.setAttribute('name', 'Filedata');
10158
+ input.setAttribute('name', _options.name || 'Filedata');
9926
10159
  input.setAttribute('accept', _mimes.join(','));
9927
10160
 
9928
10161
  Basic.extend(input.style, {
@@ -9969,9 +10202,11 @@ define("moxie/runtime/html4/file/FileInput", [
9969
10202
  addInput.call(comp);
9970
10203
 
9971
10204
  // after file is initialized as o.File, we need to update form and input ids
9972
- comp.bind('change', function() {
10205
+ comp.bind('change', function onChange() {
9973
10206
  var input = Dom.get(uid), form = Dom.get(uid + '_form'), file;
9974
10207
 
10208
+ comp.unbind('change', onChange);
10209
+
9975
10210
  if (comp.files.length && input && form) {
9976
10211
  file = comp.files[0];
9977
10212
 
@@ -10004,12 +10239,6 @@ define("moxie/runtime/html4/file/FileInput", [
10004
10239
  _uid = uid;
10005
10240
 
10006
10241
  shimContainer = currForm = browseButton = null;
10007
-
10008
- // trigger ready event asynchronously
10009
- comp.trigger({
10010
- type: 'ready',
10011
- async: true
10012
- });
10013
10242
  }
10014
10243
 
10015
10244
  Basic.extend(this, {
@@ -10065,6 +10294,12 @@ define("moxie/runtime/html4/file/FileInput", [
10065
10294
  addInput.call(this);
10066
10295
 
10067
10296
  shimContainer = null;
10297
+
10298
+ // trigger ready event asynchronously
10299
+ comp.trigger({
10300
+ type: 'ready',
10301
+ async: true
10302
+ });
10068
10303
  },
10069
10304
 
10070
10305
  getFiles: function() {
@@ -10080,7 +10315,10 @@ define("moxie/runtime/html4/file/FileInput", [
10080
10315
  },
10081
10316
 
10082
10317
  destroy: function() {
10083
- var I = this.getRuntime(), shimContainer = I.getShimContainer();
10318
+ var I = this.getRuntime()
10319
+ , shim = I.getShim()
10320
+ , shimContainer = I.getShimContainer()
10321
+ ;
10084
10322
 
10085
10323
  Events.removeAllEvents(shimContainer, this.uid);
10086
10324
  Events.removeAllEvents(_options && Dom.get(_options.container), this.uid);
@@ -10089,7 +10327,10 @@ define("moxie/runtime/html4/file/FileInput", [
10089
10327
  if (shimContainer) {
10090
10328
  shimContainer.innerHTML = '';
10091
10329
  }
10092
- _uid = _files = _mimes = _options = null;
10330
+
10331
+ shim.removeInstance(this.uid);
10332
+
10333
+ _uid = _files = _mimes = _options = shimContainer = shim = null;
10093
10334
  }
10094
10335
  });
10095
10336
  }
@@ -10144,9 +10385,8 @@ define("moxie/runtime/html4/xhr/XMLHttpRequest", [
10144
10385
  "moxie/core/Exceptions",
10145
10386
  "moxie/core/utils/Events",
10146
10387
  "moxie/file/Blob",
10147
- "moxie/xhr/FormData",
10148
- "moxie/core/JSON"
10149
- ], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData, parseJSON) {
10388
+ "moxie/xhr/FormData"
10389
+ ], function(extensions, Basic, Dom, Url, x, Events, Blob, FormData) {
10150
10390
 
10151
10391
  function XMLHttpRequest() {
10152
10392
  var _status, _response, _iframe;
@@ -10228,7 +10468,7 @@ define("moxie/runtime/html4/xhr/XMLHttpRequest", [
10228
10468
  el = _iframe.contentWindow.document || _iframe.contentDocument || window.frames[_iframe.id].document;
10229
10469
 
10230
10470
  // try to detect some standard error pages
10231
- if (/^4\d{2}\s/.test(el.title) && el.getElementsByTagName('address').length) { // standard Apache style
10471
+ if (/^4(0[0-9]|1[0-7]|2[2346])\s/.test(el.title)) { // test if title starts with 4xx HTTP error
10232
10472
  _status = el.title.replace(/^(\d+).*$/, '$1');
10233
10473
  } else {
10234
10474
  _status = 200;
@@ -10306,7 +10546,12 @@ define("moxie/runtime/html4/xhr/XMLHttpRequest", [
10306
10546
  value : value
10307
10547
  });
10308
10548
 
10309
- form.appendChild(hidden);
10549
+ // make sure that input[type="file"], if it's there, comes last
10550
+ if (input) {
10551
+ form.insertBefore(hidden, input);
10552
+ } else {
10553
+ form.appendChild(hidden);
10554
+ }
10310
10555
  }
10311
10556
  });
10312
10557
  }
@@ -10326,9 +10571,9 @@ define("moxie/runtime/html4/xhr/XMLHttpRequest", [
10326
10571
  getResponse: function(responseType) {
10327
10572
  if ('json' === responseType) {
10328
10573
  // strip off <pre>..</pre> tags that might be enclosing the response
10329
- if (Basic.typeOf(_response) === 'string') {
10574
+ if (Basic.typeOf(_response) === 'string' && !!window.JSON) {
10330
10575
  try {
10331
- return parseJSON(_response.replace(/^\s*<pre[^>]*>/, '').replace(/<\/pre>\s*$/, ''));
10576
+ return JSON.parse(_response.replace(/^\s*<pre[^>]*>/, '').replace(/<\/pre>\s*$/, ''));
10332
10577
  } catch (ex) {
10333
10578
  return null;
10334
10579
  }
@@ -10386,7 +10631,7 @@ define("moxie/runtime/html4/image/Image", [
10386
10631
  return (extensions.Image = Image);
10387
10632
  });
10388
10633
 
10389
- expose(["moxie/core/utils/Basic","moxie/core/I18n","moxie/core/utils/Mime","moxie/core/utils/Env","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/EventTarget","moxie/core/utils/Encode","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/file/File","moxie/file/FileInput","moxie/file/FileDrop","moxie/runtime/RuntimeTarget","moxie/file/FileReader","moxie/core/utils/Url","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/core/JSON","moxie/image/Image","moxie/core/utils/Events"]);
10634
+ expose(["moxie/core/utils/Basic","moxie/core/I18n","moxie/core/utils/Mime","moxie/core/utils/Env","moxie/core/utils/Dom","moxie/core/Exceptions","moxie/core/EventTarget","moxie/core/utils/Encode","moxie/runtime/Runtime","moxie/runtime/RuntimeClient","moxie/file/Blob","moxie/file/File","moxie/file/FileInput","moxie/file/FileDrop","moxie/runtime/RuntimeTarget","moxie/file/FileReader","moxie/core/utils/Url","moxie/file/FileReaderSync","moxie/xhr/FormData","moxie/xhr/XMLHttpRequest","moxie/runtime/Transporter","moxie/image/Image","moxie/core/utils/Events"]);
10390
10635
  })(this);/**
10391
10636
  * o.js
10392
10637
  *