bedrock_sass 0.1.2 → 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (198) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/assets/_vendor/tinymce/plugins/advlist/index.js +7 -0
  4. data/assets/_vendor/tinymce/plugins/advlist/plugin.js +428 -0
  5. data/assets/_vendor/tinymce/plugins/advlist/plugin.min.js +1 -0
  6. data/assets/_vendor/tinymce/plugins/anchor/index.js +7 -0
  7. data/assets/_vendor/tinymce/plugins/anchor/plugin.js +338 -0
  8. data/assets/_vendor/tinymce/plugins/anchor/plugin.min.js +1 -0
  9. data/assets/_vendor/tinymce/plugins/autolink/index.js +7 -0
  10. data/assets/_vendor/tinymce/plugins/autolink/plugin.js +404 -0
  11. data/assets/_vendor/tinymce/plugins/autolink/plugin.min.js +1 -0
  12. data/assets/_vendor/tinymce/plugins/autoresize/index.js +7 -0
  13. data/assets/_vendor/tinymce/plugins/autoresize/plugin.js +451 -0
  14. data/assets/_vendor/tinymce/plugins/autoresize/plugin.min.js +1 -0
  15. data/assets/_vendor/tinymce/plugins/autosave/index.js +7 -0
  16. data/assets/_vendor/tinymce/plugins/autosave/plugin.js +608 -0
  17. data/assets/_vendor/tinymce/plugins/autosave/plugin.min.js +1 -0
  18. data/assets/_vendor/tinymce/plugins/bbcode/index.js +7 -0
  19. data/assets/_vendor/tinymce/plugins/bbcode/plugin.js +264 -0
  20. data/assets/_vendor/tinymce/plugins/bbcode/plugin.min.js +1 -0
  21. data/assets/_vendor/tinymce/plugins/charmap/index.js +7 -0
  22. data/assets/_vendor/tinymce/plugins/charmap/plugin.js +850 -0
  23. data/assets/_vendor/tinymce/plugins/charmap/plugin.min.js +1 -0
  24. data/assets/_vendor/tinymce/plugins/code/index.js +7 -0
  25. data/assets/_vendor/tinymce/plugins/code/plugin.js +338 -0
  26. data/assets/_vendor/tinymce/plugins/code/plugin.min.js +1 -0
  27. data/assets/_vendor/tinymce/plugins/codesample/css/prism.css +138 -0
  28. data/assets/_vendor/tinymce/plugins/codesample/index.js +7 -0
  29. data/assets/_vendor/tinymce/plugins/codesample/plugin.js +1582 -0
  30. data/assets/_vendor/tinymce/plugins/codesample/plugin.min.js +1 -0
  31. data/assets/_vendor/tinymce/plugins/colorpicker/index.js +7 -0
  32. data/assets/_vendor/tinymce/plugins/colorpicker/plugin.js +272 -0
  33. data/assets/_vendor/tinymce/plugins/colorpicker/plugin.min.js +1 -0
  34. data/assets/_vendor/tinymce/plugins/contextmenu/index.js +7 -0
  35. data/assets/_vendor/tinymce/plugins/contextmenu/plugin.js +496 -0
  36. data/assets/_vendor/tinymce/plugins/contextmenu/plugin.min.js +1 -0
  37. data/assets/_vendor/tinymce/plugins/directionality/index.js +7 -0
  38. data/assets/_vendor/tinymce/plugins/directionality/plugin.js +270 -0
  39. data/assets/_vendor/tinymce/plugins/directionality/plugin.min.js +1 -0
  40. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-cool.gif +0 -0
  41. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-cry.gif +0 -0
  42. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-embarassed.gif +0 -0
  43. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif +0 -0
  44. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-frown.gif +0 -0
  45. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-innocent.gif +0 -0
  46. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-kiss.gif +0 -0
  47. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-laughing.gif +0 -0
  48. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-money-mouth.gif +0 -0
  49. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-sealed.gif +0 -0
  50. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-smile.gif +0 -0
  51. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-surprised.gif +0 -0
  52. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-tongue-out.gif +0 -0
  53. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-undecided.gif +0 -0
  54. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-wink.gif +0 -0
  55. data/assets/_vendor/tinymce/plugins/emoticons/img/smiley-yell.gif +0 -0
  56. data/assets/_vendor/tinymce/plugins/emoticons/index.js +7 -0
  57. data/assets/_vendor/tinymce/plugins/emoticons/plugin.js +256 -0
  58. data/assets/_vendor/tinymce/plugins/emoticons/plugin.min.js +1 -0
  59. data/assets/_vendor/tinymce/plugins/fullpage/index.js +7 -0
  60. data/assets/_vendor/tinymce/plugins/fullpage/plugin.js +962 -0
  61. data/assets/_vendor/tinymce/plugins/fullpage/plugin.min.js +1 -0
  62. data/assets/_vendor/tinymce/plugins/fullscreen/index.js +7 -0
  63. data/assets/_vendor/tinymce/plugins/fullscreen/plugin.js +455 -0
  64. data/assets/_vendor/tinymce/plugins/fullscreen/plugin.min.js +1 -0
  65. data/assets/_vendor/tinymce/plugins/help/img/logo.png +0 -0
  66. data/assets/_vendor/tinymce/plugins/help/index.js +7 -0
  67. data/assets/_vendor/tinymce/plugins/help/plugin.js +1527 -0
  68. data/assets/_vendor/tinymce/plugins/help/plugin.min.js +1 -0
  69. data/assets/_vendor/tinymce/plugins/hr/index.js +7 -0
  70. data/assets/_vendor/tinymce/plugins/hr/plugin.js +195 -0
  71. data/assets/_vendor/tinymce/plugins/hr/plugin.min.js +1 -0
  72. data/assets/_vendor/tinymce/plugins/image/index.js +7 -0
  73. data/assets/_vendor/tinymce/plugins/image/plugin.js +1572 -0
  74. data/assets/_vendor/tinymce/plugins/image/plugin.min.js +1 -0
  75. data/assets/_vendor/tinymce/plugins/imagetools/index.js +7 -0
  76. data/assets/_vendor/tinymce/plugins/imagetools/plugin.js +4444 -0
  77. data/assets/_vendor/tinymce/plugins/imagetools/plugin.min.js +2 -0
  78. data/assets/_vendor/tinymce/plugins/importcss/index.js +7 -0
  79. data/assets/_vendor/tinymce/plugins/importcss/plugin.js +577 -0
  80. data/assets/_vendor/tinymce/plugins/importcss/plugin.min.js +1 -0
  81. data/assets/_vendor/tinymce/plugins/insertdatetime/index.js +7 -0
  82. data/assets/_vendor/tinymce/plugins/insertdatetime/plugin.js +482 -0
  83. data/assets/_vendor/tinymce/plugins/insertdatetime/plugin.min.js +1 -0
  84. data/assets/_vendor/tinymce/plugins/legacyoutput/index.js +7 -0
  85. data/assets/_vendor/tinymce/plugins/legacyoutput/plugin.js +395 -0
  86. data/assets/_vendor/tinymce/plugins/legacyoutput/plugin.min.js +1 -0
  87. data/assets/_vendor/tinymce/plugins/link/index.js +7 -0
  88. data/assets/_vendor/tinymce/plugins/link/plugin.js +1231 -0
  89. data/assets/_vendor/tinymce/plugins/link/plugin.min.js +1 -0
  90. data/assets/_vendor/tinymce/plugins/lists/index.js +7 -0
  91. data/assets/_vendor/tinymce/plugins/lists/plugin.js +1985 -0
  92. data/assets/_vendor/tinymce/plugins/lists/plugin.min.js +1 -0
  93. data/assets/_vendor/tinymce/plugins/media/index.js +7 -0
  94. data/assets/_vendor/tinymce/plugins/media/plugin.js +2026 -0
  95. data/assets/_vendor/tinymce/plugins/media/plugin.min.js +1 -0
  96. data/assets/_vendor/tinymce/plugins/nonbreaking/index.js +7 -0
  97. data/assets/_vendor/tinymce/plugins/nonbreaking/plugin.js +313 -0
  98. data/assets/_vendor/tinymce/plugins/nonbreaking/plugin.min.js +1 -0
  99. data/assets/_vendor/tinymce/plugins/noneditable/index.js +7 -0
  100. data/assets/_vendor/tinymce/plugins/noneditable/plugin.js +316 -0
  101. data/assets/_vendor/tinymce/plugins/noneditable/plugin.min.js +1 -0
  102. data/assets/_vendor/tinymce/plugins/pagebreak/index.js +7 -0
  103. data/assets/_vendor/tinymce/plugins/pagebreak/plugin.js +354 -0
  104. data/assets/_vendor/tinymce/plugins/pagebreak/plugin.min.js +1 -0
  105. data/assets/_vendor/tinymce/plugins/paste/index.js +7 -0
  106. data/assets/_vendor/tinymce/plugins/paste/plugin.js +2935 -0
  107. data/assets/_vendor/tinymce/plugins/paste/plugin.min.js +1 -0
  108. data/assets/_vendor/tinymce/plugins/preview/index.js +7 -0
  109. data/assets/_vendor/tinymce/plugins/preview/plugin.js +410 -0
  110. data/assets/_vendor/tinymce/plugins/preview/plugin.min.js +1 -0
  111. data/assets/_vendor/tinymce/plugins/print/index.js +7 -0
  112. data/assets/_vendor/tinymce/plugins/print/plugin.js +194 -0
  113. data/assets/_vendor/tinymce/plugins/print/plugin.min.js +1 -0
  114. data/assets/_vendor/tinymce/plugins/save/index.js +7 -0
  115. data/assets/_vendor/tinymce/plugins/save/plugin.js +370 -0
  116. data/assets/_vendor/tinymce/plugins/save/plugin.min.js +1 -0
  117. data/assets/_vendor/tinymce/plugins/searchreplace/index.js +7 -0
  118. data/assets/_vendor/tinymce/plugins/searchreplace/plugin.js +977 -0
  119. data/assets/_vendor/tinymce/plugins/searchreplace/plugin.min.js +1 -0
  120. data/assets/_vendor/tinymce/plugins/spellchecker/index.js +7 -0
  121. data/assets/_vendor/tinymce/plugins/spellchecker/plugin.js +1419 -0
  122. data/assets/_vendor/tinymce/plugins/spellchecker/plugin.min.js +1 -0
  123. data/assets/_vendor/tinymce/plugins/tabfocus/index.js +7 -0
  124. data/assets/_vendor/tinymce/plugins/tabfocus/plugin.js +419 -0
  125. data/assets/_vendor/tinymce/plugins/tabfocus/plugin.min.js +1 -0
  126. data/assets/_vendor/tinymce/plugins/table/index.js +7 -0
  127. data/assets/_vendor/tinymce/plugins/table/plugin.js +15527 -0
  128. data/assets/_vendor/tinymce/plugins/table/plugin.min.js +5 -0
  129. data/assets/_vendor/tinymce/plugins/template/index.js +7 -0
  130. data/assets/_vendor/tinymce/plugins/template/plugin.js +807 -0
  131. data/assets/_vendor/tinymce/plugins/template/plugin.min.js +1 -0
  132. data/assets/_vendor/tinymce/plugins/textcolor/index.js +7 -0
  133. data/assets/_vendor/tinymce/plugins/textcolor/plugin.js +619 -0
  134. data/assets/_vendor/tinymce/plugins/textcolor/plugin.min.js +1 -0
  135. data/assets/_vendor/tinymce/plugins/textpattern/index.js +7 -0
  136. data/assets/_vendor/tinymce/plugins/textpattern/plugin.js +718 -0
  137. data/assets/_vendor/tinymce/plugins/textpattern/plugin.min.js +1 -0
  138. data/assets/_vendor/tinymce/plugins/toc/index.js +7 -0
  139. data/assets/_vendor/tinymce/plugins/toc/plugin.js +559 -0
  140. data/assets/_vendor/tinymce/plugins/toc/plugin.min.js +1 -0
  141. data/assets/_vendor/tinymce/plugins/visualblocks/css/visualblocks.css +154 -0
  142. data/assets/_vendor/tinymce/plugins/visualblocks/index.js +7 -0
  143. data/assets/_vendor/tinymce/plugins/visualblocks/plugin.js +459 -0
  144. data/assets/_vendor/tinymce/plugins/visualblocks/plugin.min.js +1 -0
  145. data/assets/_vendor/tinymce/plugins/visualchars/index.js +7 -0
  146. data/assets/_vendor/tinymce/plugins/visualchars/plugin.js +1325 -0
  147. data/assets/_vendor/tinymce/plugins/visualchars/plugin.min.js +1 -0
  148. data/assets/_vendor/tinymce/plugins/wordcount/index.js +7 -0
  149. data/assets/_vendor/tinymce/plugins/wordcount/plugin.js +735 -0
  150. data/assets/_vendor/tinymce/plugins/wordcount/plugin.min.js +1 -0
  151. data/assets/_vendor/tinymce/skins/lightgray/content.inline.min.css +1 -0
  152. data/assets/_vendor/tinymce/skins/lightgray/content.min.css +1 -0
  153. data/assets/_vendor/tinymce/skins/lightgray/content.mobile.min.css +1 -0
  154. data/assets/_vendor/tinymce/skins/lightgray/fonts/tinymce-mobile.woff +0 -0
  155. data/assets/_vendor/tinymce/skins/lightgray/fonts/tinymce-small.eot +0 -0
  156. data/assets/_vendor/tinymce/skins/lightgray/fonts/tinymce-small.svg +63 -0
  157. data/assets/_vendor/tinymce/skins/lightgray/fonts/tinymce-small.ttf +0 -0
  158. data/assets/_vendor/tinymce/skins/lightgray/fonts/tinymce-small.woff +0 -0
  159. data/assets/_vendor/tinymce/skins/lightgray/fonts/tinymce.eot +0 -0
  160. data/assets/_vendor/tinymce/skins/lightgray/fonts/tinymce.svg +131 -0
  161. data/assets/_vendor/tinymce/skins/lightgray/fonts/tinymce.ttf +0 -0
  162. data/assets/_vendor/tinymce/skins/lightgray/fonts/tinymce.woff +0 -0
  163. data/assets/_vendor/tinymce/skins/lightgray/img/anchor.gif +0 -0
  164. data/assets/_vendor/tinymce/skins/lightgray/img/loader.gif +0 -0
  165. data/assets/_vendor/tinymce/skins/lightgray/img/object.gif +0 -0
  166. data/assets/_vendor/tinymce/skins/lightgray/img/trans.gif +0 -0
  167. data/assets/_vendor/tinymce/skins/lightgray/skin.min.css +1 -0
  168. data/assets/_vendor/tinymce/skins/lightgray/skin.mobile.min.css +2 -0
  169. data/assets/_vendor/tinymce/themes/inlite/index.js +7 -0
  170. data/assets/_vendor/tinymce/themes/inlite/theme.js +18787 -0
  171. data/assets/_vendor/tinymce/themes/inlite/theme.min.js +5 -0
  172. data/assets/_vendor/tinymce/themes/mobile/index.js +7 -0
  173. data/assets/_vendor/tinymce/themes/mobile/theme.js +23384 -0
  174. data/assets/_vendor/tinymce/themes/mobile/theme.min.js +8 -0
  175. data/assets/_vendor/tinymce/themes/modern/index.js +7 -0
  176. data/assets/_vendor/tinymce/themes/modern/theme.js +18311 -0
  177. data/assets/_vendor/tinymce/themes/modern/theme.min.js +5 -0
  178. data/assets/_vendor/tinymce/tinymce.js +44399 -0
  179. data/assets/bedrock/js/bedrock.js +16587 -6193
  180. data/assets/bedrock/scss/_bedrock-components.scss +16 -0
  181. data/assets/bedrock/scss/_bedrock-settings.scss +15 -0
  182. data/assets/bedrock/scss/components/attachments-grid.scss +138 -0
  183. data/assets/bedrock/scss/components/dropzone-upload.scss +158 -0
  184. data/assets/bedrock/scss/components/global.scss +16 -8
  185. data/assets/bedrock/scss/components/helper-classes.scss +59 -0
  186. data/assets/bedrock/scss/components/inline-edit-box.scss +80 -0
  187. data/assets/bedrock/scss/components/login-box.scss +48 -0
  188. data/assets/bedrock/scss/components/no-content.scss +31 -0
  189. data/assets/bedrock/scss/components/off-canvas-menu.scss +1 -1
  190. data/assets/bedrock/scss/components/page-content.scss +51 -0
  191. data/assets/bedrock/scss/components/reveal-panel.scss +89 -0
  192. data/assets/bedrock/scss/components/select-box.scss +332 -0
  193. data/assets/bedrock/scss/components/tiny-mce-editor.scss +14 -7
  194. data/lib/bedrock_sass.rb +6 -0
  195. data/lib/bedrock_sass/engine.rb +8 -0
  196. data/lib/bedrock_sass/version.rb +1 -1
  197. data/lib/tasks/before_assets_precompile.rake +11 -0
  198. metadata +188 -2
@@ -0,0 +1 @@
1
+ !function(){var a={},b=function(b){for(var c=a[b],e=c.deps,f=c.defn,g=e.length,h=new Array(g),i=0;i<g;++i)h[i]=d(e[i]);var j=f.apply(null,h);if(void 0===j)throw"module ["+b+"] returned undefined";c.instance=j},c=function(b,c,d){if("string"!=typeof b)throw"module id must be a string";if(void 0===c)throw"no dependencies for "+b;if(void 0===d)throw"no definition function for "+b;a[b]={deps:c,defn:d,instance:void 0}},d=function(c){var d=a[c];if(void 0===d)throw"module ["+c+"] was undefined";return void 0===d.instance&&b(c),d.instance},e=function(a,b){for(var c=a.length,e=new Array(c),f=0;f<c;++f)e[f]=d(a[f]);b.apply(null,e)},f={};f.bolt={module:{api:{define:c,require:e,demand:d}}};var g=c,h=function(a,b){g(a,[],function(){return b})};h("5",tinymce.util.Tools.resolve),g("1",["5"],function(a){return a("tinymce.PluginManager")}),h("8",Math),h("9",RegExp),g("7",["5"],function(a){return a("tinymce.util.Tools")}),g("a",[],function(){var a=function(a){return a.settings.image_dimensions!==!1},b=function(a){return a.settings.image_advtab===!0},c=function(a){return a.getParam("image_prepend_url","")},d=function(a){return a.getParam("image_class_list")},e=function(a){return a.settings.image_description!==!1},f=function(a){return a.settings.image_title===!0},g=function(a){return a.settings.image_caption===!0},h=function(a){return a.getParam("image_list",!1)},i=function(a){return a.getParam("images_upload_url",!1)},j=function(a){return a.getParam("images_upload_handler",!1)},k=function(a){return a.getParam("images_upload_url")},l=function(a){return a.getParam("images_upload_handler")},m=function(a){return a.getParam("images_upload_base_path")},n=function(a){return a.getParam("images_upload_credentials")};return{hasDimensions:a,hasAdvTab:b,getPrependUrl:c,getClassList:d,hasDescription:e,hasImageTitle:f,hasImageCaption:g,getImageList:h,hasUploadUrl:i,hasUploadHandler:j,getUploadUrl:k,getUploadHandler:l,getUploadBasePath:m,getUploadCredentials:n}}),h("g",document),g("r",[],function(){var a="undefined"!=typeof window?window:Function("return this;")();return a}),g("q",["r"],function(a){var b=function(b,c){for(var d=void 0!==c?c:a,e=0;e<b.length&&void 0!==d&&null!==d;++e)d=d[b[e]];return d},c=function(a,c){var d=a.split(".");return b(d,c)},d=function(a,b){return void 0!==a[b]&&null!==a[b]||(a[b]={}),a[b]},e=function(b,c){for(var e=void 0!==c?c:a,f=0;f<b.length;++f)e=d(e,b[f]);return e},f=function(a,b){var c=a.split(".");return e(c,b)};return{path:b,resolve:c,forge:e,namespace:f}}),g("n",["q"],function(a){var b=function(b,c){return a.resolve(b,c)},c=function(a,c){var d=b(a,c);if(void 0===d)throw a+" not available on this browser";return d};return{getOrDie:c}}),g("h",["n"],function(a){return function(){var b=a.getOrDie("FileReader");return new b}}),g("i",["5"],function(a){return a("tinymce.util.Promise")}),g("j",["5"],function(a){return a("tinymce.util.XHR")}),g("b",["8","g","h","i","7","j","a"],function(a,b,c,d,e,f,g){var h=function(b,c){return a.max(parseInt(b,10),parseInt(c,10))},i=function(a,c){function d(a,b){e.parentNode&&e.parentNode.removeChild(e),c({width:a,height:b})}var e=b.createElement("img");e.onload=function(){var a=h(e.width,e.clientWidth),b=h(e.height,e.clientHeight);d(a,b)},e.onerror=function(){d()};var f=e.style;f.visibility="hidden",f.position="fixed",f.bottom=f.left=0,f.width=f.height="auto",b.body.appendChild(e),e.src=a},j=function(a,b,c){function d(a,c){return c=c||[],e.each(a,function(a){var e={text:a.text||a.title};a.menu?e.menu=d(a.menu):(e.value=a.value,b(e)),c.push(e)}),c}return d(a,c||[])},k=function(a){return a&&(a=a.replace(/px$/,"")),a},l=function(a){return a.length>0&&/^[0-9]+$/.test(a)&&(a+="px"),a},m=function(a){if(a.margin){var b=a.margin.split(" ");switch(b.length){case 1:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[0],a["margin-bottom"]=a["margin-bottom"]||b[0],a["margin-left"]=a["margin-left"]||b[0];break;case 2:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[0],a["margin-left"]=a["margin-left"]||b[1];break;case 3:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[2],a["margin-left"]=a["margin-left"]||b[1];break;case 4:a["margin-top"]=a["margin-top"]||b[0],a["margin-right"]=a["margin-right"]||b[1],a["margin-bottom"]=a["margin-bottom"]||b[2],a["margin-left"]=a["margin-left"]||b[3]}delete a.margin}return a},n=function(a,b){var c=g.getImageList(a);"string"==typeof c?f.send({url:c,success:function(a){b(JSON.parse(a))}}):"function"==typeof c?c(b):b(c)},o=function(a,b,c){function d(){c.onload=c.onerror=null,a.selection&&(a.selection.select(c),a.nodeChanged())}c.onload=function(){b.width||b.height||!g.hasDimensions(a)||a.dom.setAttribs(c,{width:c.clientWidth,height:c.clientHeight}),d()},c.onerror=d},p=function(a){return new d(function(b,d){var e=new c;e.onload=function(){b(e.result)},e.onerror=function(){d(c.error.message)},e.readAsDataURL(a)})};return{getImageSize:i,buildListItems:j,removePixelSuffix:k,addPixelSuffix:l,mergeMargins:m,createImageList:n,waitLoadImage:o,blobToDataUri:p}}),g("c",["a","b"],function(a,b){var c=function(c){return function(d){var e=c.dom,f=d.control.rootControl;if(a.hasAdvTab(c)){var g=f.toJSON(),h=e.parseStyle(g.style);f.find("#vspace").value(""),f.find("#hspace").value(""),h=b.mergeMargins(h),(h["margin-top"]&&h["margin-bottom"]||h["margin-right"]&&h["margin-left"])&&(h["margin-top"]===h["margin-bottom"]?f.find("#vspace").value(b.removePixelSuffix(h["margin-top"])):f.find("#vspace").value(""),h["margin-right"]===h["margin-left"]?f.find("#hspace").value(b.removePixelSuffix(h["margin-right"])):f.find("#hspace").value("")),h["border-width"]&&f.find("#border").value(b.removePixelSuffix(h["border-width"])),f.find("#style").value(e.serializeStyle(e.parseStyle(e.serializeStyle(h))))}}},d=function(a,b){return{title:"Advanced",type:"form",pack:"start",items:[{label:"Style",name:"style",type:"textbox",onchange:c(a)},{type:"form",layout:"grid",packV:"start",columns:2,padding:0,alignH:["left","right"],defaults:{type:"textbox",maxWidth:50,onchange:function(c){b(a,c.control.rootControl)}},items:[{label:"Vertical space",name:"vspace"},{label:"Horizontal space",name:"hspace"},{label:"Border",name:"border"}]}]}};return{makeTab:d}}),g("e",[],function(){var a=function(a,b){a.state.set("oldVal",a.value()),b.state.set("oldVal",b.value())},b=function(a,b){var c=a.find("#width")[0],d=a.find("#height")[0],e=a.find("#constrain")[0];c&&d&&e&&b(c,d,e.checked())},c=function(b,c,d){var e=b.state.get("oldVal"),f=c.state.get("oldVal"),g=b.value(),h=c.value();d&&e&&f&&g&&h&&(g!==e?(h=Math.round(g/e*h),isNaN(h)||c.value(h)):(g=Math.round(h/f*g),isNaN(g)||b.value(g))),a(b,c)},d=function(c){b(c,a)},e=function(a){b(a,c)},f=function(){var a=function(a){e(a.control.rootControl)};return{type:"container",label:"Dimensions",layout:"flex",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:5,size:5,onchange:a,ariaLabel:"Width"},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:5,size:5,onchange:a,ariaLabel:"Height"},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}};return{createUi:f,syncSize:d,updateSize:e}}),g("d",["7","a","b","e"],function(a,b,c,d){var e=function(e,f){var g,h,i,j=e.meta||{},k=e.control,l=k.rootControl,m=l.find("#image-list")[0];m&&m.value(f.convertURL(k.value(),"src")),a.each(j,function(a,b){l.find("#"+b).value(a)}),j.width||j.height||(g=f.convertURL(k.value(),"src"),h=b.getPrependUrl(f),i=new RegExp("^(?:[a-z]+:)?//","i"),h&&!i.test(g)&&g.substring(0,h.length)!==h&&(g=h+g),k.value(g),c.getImageSize(f.documentBaseURI.toAbsolute(k.value()),function(a){a.width&&a.height&&b.hasDimensions(f)&&(l.find("#width").value(a.width),l.find("#height").value(a.height),d.updateSize(l))}))},f=function(a){a.meta=a.control.rootControl.toJSON()},g=function(a,g){var h=[{name:"src",type:"filepicker",filetype:"image",label:"Source",autofocus:!0,onchange:function(b){e(b,a)},onbeforecall:f},g];return b.hasDescription(a)&&h.push({name:"alt",type:"textbox",label:"Image description"}),b.hasImageTitle(a)&&h.push({name:"title",type:"textbox",label:"Image Title"}),b.hasDimensions(a)&&h.push(d.createUi()),b.getClassList(a)&&h.push({name:"class",type:"listbox",label:"Class",values:c.buildListItems(b.getClassList(a),function(b){b.value&&(b.textStyle=function(){return a.formatter.getCssText({inline:"img",classes:[b.value]})})})}),b.hasImageCaption(a)&&h.push({name:"caption",type:"checkbox",label:"Caption"}),h},h=function(a,b){return{title:"General",type:"form",items:g(a,b)}};return{makeTab:h,getGeneralItems:g}}),g("k",["n"],function(a){var b=function(){return a.getOrDie("URL")},c=function(a){return b().createObjectURL(a)},d=function(a){b().revokeObjectURL(a)};return{createObjectURL:c,revokeObjectURL:d}}),g("l",["5"],function(a){return a("tinymce.ui.Factory")}),g("o",["n"],function(a){return function(){var b=a.getOrDie("XMLHttpRequest");return new b}}),h("p",window),g("m",["o","g","p","i","7"],function(a,b,c,d,e){var f=function(){},g=function(a,b){return a?a.replace(/\/$/,"")+"/"+b.replace(/^\//,""):b};return function(b){var h=function(d,e,f,h){var i,j;i=new a,i.open("POST",b.url),i.withCredentials=b.credentials,i.upload.onprogress=function(a){h(a.loaded/a.total*100)},i.onerror=function(){f("Image upload failed due to a XHR Transport error. Code: "+i.status)},i.onload=function(){var a;return i.status<200||i.status>=300?void f("HTTP Error: "+i.status):(a=JSON.parse(i.responseText),a&&"string"==typeof a.location?void e(g(b.basePath,a.location)):void f("Invalid JSON: "+i.responseText))},j=new c.FormData,j.append("file",d.blob(),d.filename()),i.send(j)},i=function(a,b){return new d(function(c,d){try{b(a,c,d,f)}catch(a){d(a.message)}})},j=function(a){return a===h},k=function(a){return!b.url&&j(b.handler)?d.reject("Upload url missing from the settings."):i(a,b.handler)};return b=e.extend({credentials:!1,handler:h},b),{upload:k}}}),g("f",["k","l","a","b","m"],function(a,b,c,d,e){var f=function(f){return function(g){var h=b.get("Throbber"),i=g.control.rootControl,j=new h(i.getEl()),k=g.control.value(),l=a.createObjectURL(k),m=new e({url:c.getUploadUrl(f),basePath:c.getUploadBasePath(f),credentials:c.getUploadCredentials(f),handler:c.getUploadHandler(f)}),n=function(){j.hide(),a.revokeObjectURL(l)};return j.show(),d.blobToDataUri(k).then(function(a){var b=f.editorUpload.blobCache.create({blob:k,blobUri:l,name:k.name?k.name.replace(/\.[^\.]+$/,""):null,base64:a.split(",")[1]});return m.upload(b).then(function(a){var b=i.find("#src");return b.value(a),i.find("tabpanel")[0].activateTab(0),b.fire("change"),n(),a})})["catch"](function(a){f.windowManager.alert(a),n()})}},g=".jpg,.jpeg,.png,.gif",h=function(a){return{title:"Upload",type:"form",layout:"flex",direction:"column",align:"stretch",padding:"20 20 20 20",items:[{type:"container",layout:"flex",direction:"column",align:"center",spacing:10,items:[{text:"Browse for an image",type:"browsebutton",accept:g,onchange:f(a)},{text:"OR",type:"label"}]},{text:"Drop an image here",type:"dropzone",accept:g,height:100,onchange:f(a)}]}};return{makeTab:h}}),g("6",["8","9","7","a","b","c","d","e","f"],function(a,b,c,d,e,f,g,h,i){return function(a){function b(b){function j(){var b,d;h.updateSize(l),k(a,l),p=c.extend(p,l.toJSON()),p.alt||(p.alt=""),p.title||(p.title=""),""===p.width&&(p.width=null),""===p.height&&(p.height=null),p.style||(p.style=null),p={src:p.src,alt:p.alt,title:p.title,width:p.width,height:p.height,style:p.style,caption:p.caption,"class":p["class"]},a.undoManager.transact(function(){if(p.src){if(""===p.title&&(p.title=null),m?q.setAttribs(m,p):(p.id="__mcenew",a.focus(),a.selection.setContent(q.createHTML("img",p)),m=q.get("__mcenew"),q.setAttrib(m,"id",null)),a.editorUpload.uploadImagesAuto(),p.caption===!1&&q.is(m.parentNode,"figure.image")&&(b=m.parentNode,q.insertAfter(m,b),q.remove(b)),p.caption!==!0)e.waitLoadImage(a,p,m);else if(!q.is(m.parentNode,"figure.image")){d=m,m=m.cloneNode(!0),b=q.create("figure",{"class":"image"}),b.appendChild(m),b.appendChild(q.create("figcaption",{contentEditable:!0},"Caption")),b.contentEditable=!1;var c=q.getParent(d,function(b){return a.schema.getTextBlockElements()[b.nodeName]});c?q.split(c,d,b):q.replace(b,d),a.selection.select(b)}}else if(m){var f=q.is(m.parentNode,"figure.image")?m.parentNode:m;q.remove(f),a.focus(),a.nodeChanged(),q.isEmpty(a.getBody())&&(a.setContent(""),a.selection.setCursorLocation())}})}var l,m,n,o,p={},q=a.dom;if(m=a.selection.getNode(),n=q.getParent(m,"figure.image"),n&&(m=q.select("img",n)[0]),m&&("IMG"!==m.nodeName||m.getAttribute("data-mce-object")||m.getAttribute("data-mce-placeholder"))&&(m=null),m&&(p={src:q.getAttrib(m,"src"),alt:q.getAttrib(m,"alt"),title:q.getAttrib(m,"title"),"class":q.getAttrib(m,"class"),width:q.getAttrib(m,"width"),height:q.getAttrib(m,"height"),caption:!!n}),b&&(o={type:"listbox",label:"Image list",name:"image-list",values:e.buildListItems(b,function(b){b.value=a.convertURL(b.value||b.url,"src")},[{text:"None",value:""}]),value:p.src&&a.convertURL(p.src,"src"),onselect:function(a){var b=l.find("#alt");(!b.value()||a.lastControl&&b.value()===a.lastControl.text())&&b.value(a.control.text()),l.find("#src").value(a.control.value()).fire("change")},onPostRender:function(){o=this}}),d.hasAdvTab(a)||d.hasUploadUrl(a)||d.hasUploadHandler(a)){var r=[g.makeTab(a,o)];d.hasAdvTab(a)&&(m&&(m.style.marginLeft&&m.style.marginRight&&m.style.marginLeft===m.style.marginRight&&(p.hspace=e.removePixelSuffix(m.style.marginLeft)),m.style.marginTop&&m.style.marginBottom&&m.style.marginTop===m.style.marginBottom&&(p.vspace=e.removePixelSuffix(m.style.marginTop)),m.style.borderWidth&&(p.border=e.removePixelSuffix(m.style.borderWidth)),p.style=a.dom.serializeStyle(a.dom.parseStyle(a.dom.getAttrib(m,"style")))),r.push(f.makeTab(a,k))),(d.hasUploadUrl(a)||d.hasUploadHandler(a))&&r.push(i.makeTab(a)),l=a.windowManager.open({title:"Insert/edit image",data:p,bodyType:"tabpanel",body:r,onSubmit:j})}else l=a.windowManager.open({title:"Insert/edit image",data:p,body:g.getGeneralItems(a,o),onSubmit:j});h.syncSize(l)}function j(){e.createImageList(a,b)}var k=function(a,b){if(d.hasAdvTab(a)){var c=a.dom,f=b.toJSON(),g=c.parseStyle(f.style);g=e.mergeMargins(g),f.vspace&&(g["margin-top"]=g["margin-bottom"]=e.addPixelSuffix(f.vspace)),f.hspace&&(g["margin-left"]=g["margin-right"]=e.addPixelSuffix(f.hspace)),f.border&&(g["border-width"]=e.addPixelSuffix(f.border)),b.find("#style").value(c.serializeStyle(c.parseStyle(c.serializeStyle(g))))}};return{open:j}}}),g("2",["6"],function(a){var b=function(b){b.addCommand("mceImage",a(b).open)};return{register:b}}),g("3",["7"],function(a){var b=function(a){var b=a.attr("class");return b&&/\bimage\b/.test(b)},c=function(c){return function(d){for(var e,f=d.length,g=function(a){a.attr("contenteditable",c?"true":null)};f--;)e=d[f],b(e)&&(e.attr("contenteditable",c?"false":null),a.each(e.getAll("figcaption"),g))}},d=function(a){a.on("preInit",function(){a.parser.addNodeFilter("figure",c(!0)),a.serializer.addNodeFilter("figure",c(!1))})};return{setup:d}}),g("4",["6"],function(a){var b=function(b){b.addButton("image",{icon:"image",tooltip:"Insert/edit image",onclick:a(b).open,stateSelector:"img:not([data-mce-object],[data-mce-placeholder]),figure.image"}),b.addMenuItem("image",{icon:"image",text:"Image",onclick:a(b).open,context:"insert",prependToContext:!0})};return{register:b}}),g("0",["1","2","3","4"],function(a,b,c,d){return a.add("image",function(a){c.setup(a),d.register(a),b.register(a)}),function(){}}),d("0")()}();
@@ -0,0 +1,7 @@
1
+ // Exports the "imagetools" plugin for usage with module loaders
2
+ // Usage:
3
+ // CommonJS:
4
+ // require('tinymce/plugins/imagetools')
5
+ // ES2015:
6
+ // import 'tinymce/plugins/imagetools'
7
+ require('./plugin.js');
@@ -0,0 +1,4444 @@
1
+ (function () {
2
+
3
+ var defs = {}; // id -> {dependencies, definition, instance (possibly undefined)}
4
+
5
+ // Used when there is no 'main' module.
6
+ // The name is probably (hopefully) unique so minification removes for releases.
7
+ var register_3795 = function (id) {
8
+ var module = dem(id);
9
+ var fragments = id.split('.');
10
+ var target = Function('return this;')();
11
+ for (var i = 0; i < fragments.length - 1; ++i) {
12
+ if (target[fragments[i]] === undefined)
13
+ target[fragments[i]] = {};
14
+ target = target[fragments[i]];
15
+ }
16
+ target[fragments[fragments.length - 1]] = module;
17
+ };
18
+
19
+ var instantiate = function (id) {
20
+ var actual = defs[id];
21
+ var dependencies = actual.deps;
22
+ var definition = actual.defn;
23
+ var len = dependencies.length;
24
+ var instances = new Array(len);
25
+ for (var i = 0; i < len; ++i)
26
+ instances[i] = dem(dependencies[i]);
27
+ var defResult = definition.apply(null, instances);
28
+ if (defResult === undefined)
29
+ throw 'module [' + id + '] returned undefined';
30
+ actual.instance = defResult;
31
+ };
32
+
33
+ var def = function (id, dependencies, definition) {
34
+ if (typeof id !== 'string')
35
+ throw 'module id must be a string';
36
+ else if (dependencies === undefined)
37
+ throw 'no dependencies for ' + id;
38
+ else if (definition === undefined)
39
+ throw 'no definition function for ' + id;
40
+ defs[id] = {
41
+ deps: dependencies,
42
+ defn: definition,
43
+ instance: undefined
44
+ };
45
+ };
46
+
47
+ var dem = function (id) {
48
+ var actual = defs[id];
49
+ if (actual === undefined)
50
+ throw 'module [' + id + '] was undefined';
51
+ else if (actual.instance === undefined)
52
+ instantiate(id);
53
+ return actual.instance;
54
+ };
55
+
56
+ var req = function (ids, callback) {
57
+ var len = ids.length;
58
+ var instances = new Array(len);
59
+ for (var i = 0; i < len; ++i)
60
+ instances[i] = dem(ids[i]);
61
+ callback.apply(null, instances);
62
+ };
63
+
64
+ var ephox = {};
65
+
66
+ ephox.bolt = {
67
+ module: {
68
+ api: {
69
+ define: def,
70
+ require: req,
71
+ demand: dem
72
+ }
73
+ }
74
+ };
75
+
76
+ var define = def;
77
+ var require = req;
78
+ var demand = dem;
79
+ // this helps with minification when using a lot of global references
80
+ var defineGlobal = function (id, ref) {
81
+ define(id, [], function () { return ref; });
82
+ };
83
+ /*jsc
84
+ ["tinymce.plugins.imagetools.Plugin","ephox.katamari.api.Cell","tinymce.core.PluginManager","tinymce.plugins.imagetools.api.Commands","tinymce.plugins.imagetools.core.UploadSelectedImage","tinymce.plugins.imagetools.ui.Buttons","tinymce.plugins.imagetools.ui.ContextToolbar","global!tinymce.util.Tools.resolve","tinymce.core.util.Tools","tinymce.plugins.imagetools.core.Actions","ephox.katamari.api.Fun","tinymce.plugins.imagetools.api.Settings","ephox.imagetools.api.BlobConversions","ephox.imagetools.api.ImageTransformations","ephox.imagetools.api.ResultConversions","global!Array","global!Error","ephox.sand.api.URL","global!clearTimeout","tinymce.core.util.Delay","tinymce.core.util.Promise","tinymce.core.util.URI","tinymce.plugins.imagetools.core.ImageSize","tinymce.plugins.imagetools.core.Proxy","tinymce.plugins.imagetools.ui.Dialog","ephox.imagetools.util.Conversions","ephox.katamari.api.Option","ephox.imagetools.transformations.Filters","ephox.imagetools.transformations.ImageTools","ephox.imagetools.util.ImageResult","ephox.sand.util.Global","tinymce.plugins.imagetools.core.Errors","tinymce.plugins.imagetools.core.Utils","global!Math","global!setTimeout","tinymce.core.dom.DOMUtils","tinymce.core.ui.Factory","tinymce.plugins.imagetools.core.UndoStack","tinymce.plugins.imagetools.ui.ImagePanel","ephox.imagetools.util.Canvas","ephox.imagetools.util.ImageSize","ephox.imagetools.util.Promise","global!Object","ephox.sand.api.Blob","ephox.sand.api.FileReader","ephox.sand.api.Uint8Array","ephox.sand.api.Window","ephox.imagetools.transformations.ColorMatrix","ephox.imagetools.transformations.ImageResizerCanvas","ephox.katamari.api.Resolve","ephox.katamari.api.Arr","ephox.sand.api.XMLHttpRequest","global!document","global!Image","tinymce.core.geom.Rect","tinymce.plugins.imagetools.core.LoadImage","tinymce.plugins.imagetools.ui.CropRect","ephox.katamari.api.Global","global!String","tinymce.core.dom.DomQuery","tinymce.core.util.Observable","tinymce.core.util.VK"]
85
+ jsc*/
86
+ define(
87
+ 'ephox.katamari.api.Cell',
88
+
89
+ [
90
+ ],
91
+
92
+ function () {
93
+ var Cell = function (initial) {
94
+ var value = initial;
95
+
96
+ var get = function () {
97
+ return value;
98
+ };
99
+
100
+ var set = function (v) {
101
+ value = v;
102
+ };
103
+
104
+ var clone = function () {
105
+ return Cell(get());
106
+ };
107
+
108
+ return {
109
+ get: get,
110
+ set: set,
111
+ clone: clone
112
+ };
113
+ };
114
+
115
+ return Cell;
116
+ }
117
+ );
118
+
119
+ defineGlobal("global!tinymce.util.Tools.resolve", tinymce.util.Tools.resolve);
120
+ /**
121
+ * ResolveGlobal.js
122
+ *
123
+ * Released under LGPL License.
124
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
125
+ *
126
+ * License: http://www.tinymce.com/license
127
+ * Contributing: http://www.tinymce.com/contributing
128
+ */
129
+
130
+ define(
131
+ 'tinymce.core.PluginManager',
132
+ [
133
+ 'global!tinymce.util.Tools.resolve'
134
+ ],
135
+ function (resolve) {
136
+ return resolve('tinymce.PluginManager');
137
+ }
138
+ );
139
+
140
+ /**
141
+ * ResolveGlobal.js
142
+ *
143
+ * Released under LGPL License.
144
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
145
+ *
146
+ * License: http://www.tinymce.com/license
147
+ * Contributing: http://www.tinymce.com/contributing
148
+ */
149
+
150
+ define(
151
+ 'tinymce.core.util.Tools',
152
+ [
153
+ 'global!tinymce.util.Tools.resolve'
154
+ ],
155
+ function (resolve) {
156
+ return resolve('tinymce.util.Tools');
157
+ }
158
+ );
159
+
160
+ define(
161
+ 'ephox.imagetools.util.Canvas',
162
+ [
163
+ ],
164
+ function () {
165
+ function create(width, height) {
166
+ return resize(document.createElement('canvas'), width, height);
167
+ }
168
+
169
+ function clone(canvas) {
170
+ var tCanvas, ctx;
171
+ tCanvas = create(canvas.width, canvas.height);
172
+ ctx = get2dContext(tCanvas);
173
+ ctx.drawImage(canvas, 0, 0);
174
+ return tCanvas;
175
+ }
176
+
177
+ function get2dContext(canvas) {
178
+ return canvas.getContext("2d");
179
+ }
180
+
181
+ function get3dContext(canvas) {
182
+ var gl = null;
183
+ try {
184
+ gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
185
+ }
186
+ catch (e) { }
187
+
188
+ if (!gl) { // it seems that sometimes it doesn't throw exception, but still fails to get context
189
+ gl = null;
190
+ }
191
+ return gl;
192
+ }
193
+
194
+ function resize(canvas, width, height) {
195
+ canvas.width = width;
196
+ canvas.height = height;
197
+
198
+ return canvas;
199
+ }
200
+
201
+ return {
202
+ create: create,
203
+ clone: clone,
204
+ resize: resize,
205
+ get2dContext: get2dContext,
206
+ get3dContext: get3dContext
207
+ };
208
+ });
209
+ define(
210
+ 'ephox.imagetools.util.ImageSize',
211
+ [
212
+ ],
213
+ function() {
214
+ function getWidth(image) {
215
+ return image.naturalWidth || image.width;
216
+ }
217
+
218
+ function getHeight(image) {
219
+ return image.naturalHeight || image.height;
220
+ }
221
+
222
+ return {
223
+ getWidth: getWidth,
224
+ getHeight: getHeight
225
+ };
226
+ });
227
+ /* eslint-disable */
228
+ /* jshint ignore:start */
229
+
230
+ /**
231
+ * Modifed to be a feature fill and wrapped as tinymce module.
232
+ *
233
+ * Promise polyfill under MIT license: https://github.com/taylorhakes/promise-polyfill
234
+ */
235
+ define(
236
+ 'ephox.imagetools.util.Promise',
237
+ [
238
+ ],
239
+ function () {
240
+ if (window.Promise) {
241
+ return window.Promise;
242
+ }
243
+
244
+ // Use polyfill for setImmediate for performance gains
245
+ var asap = Promise.immediateFn || (typeof setImmediate === 'function' && setImmediate) ||
246
+ function (fn) { setTimeout(fn, 1); };
247
+
248
+ // Polyfill for Function.prototype.bind
249
+ function bind(fn, thisArg) {
250
+ return function () {
251
+ fn.apply(thisArg, arguments);
252
+ };
253
+ }
254
+
255
+ var isArray = Array.isArray || function (value) { return Object.prototype.toString.call(value) === "[object Array]"; };
256
+
257
+ function Promise(fn) {
258
+ if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
259
+ if (typeof fn !== 'function') throw new TypeError('not a function');
260
+ this._state = null;
261
+ this._value = null;
262
+ this._deferreds = [];
263
+
264
+ doResolve(fn, bind(resolve, this), bind(reject, this));
265
+ }
266
+
267
+ function handle(deferred) {
268
+ var me = this;
269
+ if (this._state === null) {
270
+ this._deferreds.push(deferred);
271
+ return;
272
+ }
273
+ asap(function () {
274
+ var cb = me._state ? deferred.onFulfilled : deferred.onRejected;
275
+ if (cb === null) {
276
+ (me._state ? deferred.resolve : deferred.reject)(me._value);
277
+ return;
278
+ }
279
+ var ret;
280
+ try {
281
+ ret = cb(me._value);
282
+ }
283
+ catch (e) {
284
+ deferred.reject(e);
285
+ return;
286
+ }
287
+ deferred.resolve(ret);
288
+ });
289
+ }
290
+
291
+ function resolve(newValue) {
292
+ try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
293
+ if (newValue === this) throw new TypeError('A promise cannot be resolved with itself.');
294
+ if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
295
+ var then = newValue.then;
296
+ if (typeof then === 'function') {
297
+ doResolve(bind(then, newValue), bind(resolve, this), bind(reject, this));
298
+ return;
299
+ }
300
+ }
301
+ this._state = true;
302
+ this._value = newValue;
303
+ finale.call(this);
304
+ } catch (e) { reject.call(this, e); }
305
+ }
306
+
307
+ function reject(newValue) {
308
+ this._state = false;
309
+ this._value = newValue;
310
+ finale.call(this);
311
+ }
312
+
313
+ function finale() {
314
+ for (var i = 0, len = this._deferreds.length; i < len; i++) {
315
+ handle.call(this, this._deferreds[i]);
316
+ }
317
+ this._deferreds = null;
318
+ }
319
+
320
+ function Handler(onFulfilled, onRejected, resolve, reject) {
321
+ this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
322
+ this.onRejected = typeof onRejected === 'function' ? onRejected : null;
323
+ this.resolve = resolve;
324
+ this.reject = reject;
325
+ }
326
+
327
+ /**
328
+ * Take a potentially misbehaving resolver function and make sure
329
+ * onFulfilled and onRejected are only called once.
330
+ *
331
+ * Makes no guarantees about asynchrony.
332
+ */
333
+ function doResolve(fn, onFulfilled, onRejected) {
334
+ var done = false;
335
+ try {
336
+ fn(function (value) {
337
+ if (done) return;
338
+ done = true;
339
+ onFulfilled(value);
340
+ }, function (reason) {
341
+ if (done) return;
342
+ done = true;
343
+ onRejected(reason);
344
+ });
345
+ } catch (ex) {
346
+ if (done) return;
347
+ done = true;
348
+ onRejected(ex);
349
+ }
350
+ }
351
+
352
+ Promise.prototype['catch'] = function (onRejected) {
353
+ return this.then(null, onRejected);
354
+ };
355
+
356
+ Promise.prototype.then = function (onFulfilled, onRejected) {
357
+ var me = this;
358
+ return new Promise(function (resolve, reject) {
359
+ handle.call(me, new Handler(onFulfilled, onRejected, resolve, reject));
360
+ });
361
+ };
362
+
363
+ Promise.all = function () {
364
+ var args = Array.prototype.slice.call(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);
365
+
366
+ return new Promise(function (resolve, reject) {
367
+ if (args.length === 0) return resolve([]);
368
+ var remaining = args.length;
369
+ function res(i, val) {
370
+ try {
371
+ if (val && (typeof val === 'object' || typeof val === 'function')) {
372
+ var then = val.then;
373
+ if (typeof then === 'function') {
374
+ then.call(val, function (val) { res(i, val); }, reject);
375
+ return;
376
+ }
377
+ }
378
+ args[i] = val;
379
+ if (--remaining === 0) {
380
+ resolve(args);
381
+ }
382
+ } catch (ex) {
383
+ reject(ex);
384
+ }
385
+ }
386
+ for (var i = 0; i < args.length; i++) {
387
+ res(i, args[i]);
388
+ }
389
+ });
390
+ };
391
+
392
+ Promise.resolve = function (value) {
393
+ if (value && typeof value === 'object' && value.constructor === Promise) {
394
+ return value;
395
+ }
396
+
397
+ return new Promise(function (resolve) {
398
+ resolve(value);
399
+ });
400
+ };
401
+
402
+ Promise.reject = function (value) {
403
+ return new Promise(function (resolve, reject) {
404
+ reject(value);
405
+ });
406
+ };
407
+
408
+ Promise.race = function (values) {
409
+ return new Promise(function (resolve, reject) {
410
+ for (var i = 0, len = values.length; i < len; i++) {
411
+ values[i].then(resolve, reject);
412
+ }
413
+ });
414
+ };
415
+
416
+ return Promise;
417
+ });
418
+
419
+ /* jshint ignore:end */
420
+ /* eslint-enable */
421
+
422
+ defineGlobal("global!Array", Array);
423
+ defineGlobal("global!Error", Error);
424
+ define(
425
+ 'ephox.katamari.api.Fun',
426
+
427
+ [
428
+ 'global!Array',
429
+ 'global!Error'
430
+ ],
431
+
432
+ function (Array, Error) {
433
+
434
+ var noop = function () { };
435
+
436
+ var noarg = function (f) {
437
+ return function () {
438
+ return f();
439
+ };
440
+ };
441
+
442
+ var compose = function (fa, fb) {
443
+ return function () {
444
+ return fa(fb.apply(null, arguments));
445
+ };
446
+ };
447
+
448
+ var constant = function (value) {
449
+ return function () {
450
+ return value;
451
+ };
452
+ };
453
+
454
+ var identity = function (x) {
455
+ return x;
456
+ };
457
+
458
+ var tripleEquals = function(a, b) {
459
+ return a === b;
460
+ };
461
+
462
+ // Don't use array slice(arguments), makes the whole function unoptimisable on Chrome
463
+ var curry = function (f) {
464
+ // equivalent to arguments.slice(1)
465
+ // starting at 1 because 0 is the f, makes things tricky.
466
+ // Pay attention to what variable is where, and the -1 magic.
467
+ // thankfully, we have tests for this.
468
+ var args = new Array(arguments.length - 1);
469
+ for (var i = 1; i < arguments.length; i++) args[i-1] = arguments[i];
470
+
471
+ return function () {
472
+ var newArgs = new Array(arguments.length);
473
+ for (var j = 0; j < newArgs.length; j++) newArgs[j] = arguments[j];
474
+
475
+ var all = args.concat(newArgs);
476
+ return f.apply(null, all);
477
+ };
478
+ };
479
+
480
+ var not = function (f) {
481
+ return function () {
482
+ return !f.apply(null, arguments);
483
+ };
484
+ };
485
+
486
+ var die = function (msg) {
487
+ return function () {
488
+ throw new Error(msg);
489
+ };
490
+ };
491
+
492
+ var apply = function (f) {
493
+ return f();
494
+ };
495
+
496
+ var call = function(f) {
497
+ f();
498
+ };
499
+
500
+ var never = constant(false);
501
+ var always = constant(true);
502
+
503
+
504
+ return {
505
+ noop: noop,
506
+ noarg: noarg,
507
+ compose: compose,
508
+ constant: constant,
509
+ identity: identity,
510
+ tripleEquals: tripleEquals,
511
+ curry: curry,
512
+ not: not,
513
+ die: die,
514
+ apply: apply,
515
+ call: call,
516
+ never: never,
517
+ always: always
518
+ };
519
+ }
520
+ );
521
+
522
+ defineGlobal("global!Object", Object);
523
+ define(
524
+ 'ephox.katamari.api.Option',
525
+
526
+ [
527
+ 'ephox.katamari.api.Fun',
528
+ 'global!Object'
529
+ ],
530
+
531
+ function (Fun, Object) {
532
+
533
+ var never = Fun.never;
534
+ var always = Fun.always;
535
+
536
+ /**
537
+ Option objects support the following methods:
538
+
539
+ fold :: this Option a -> ((() -> b, a -> b)) -> Option b
540
+
541
+ is :: this Option a -> a -> Boolean
542
+
543
+ isSome :: this Option a -> () -> Boolean
544
+
545
+ isNone :: this Option a -> () -> Boolean
546
+
547
+ getOr :: this Option a -> a -> a
548
+
549
+ getOrThunk :: this Option a -> (() -> a) -> a
550
+
551
+ getOrDie :: this Option a -> String -> a
552
+
553
+ or :: this Option a -> Option a -> Option a
554
+ - if some: return self
555
+ - if none: return opt
556
+
557
+ orThunk :: this Option a -> (() -> Option a) -> Option a
558
+ - Same as "or", but uses a thunk instead of a value
559
+
560
+ map :: this Option a -> (a -> b) -> Option b
561
+ - "fmap" operation on the Option Functor.
562
+ - same as 'each'
563
+
564
+ ap :: this Option a -> Option (a -> b) -> Option b
565
+ - "apply" operation on the Option Apply/Applicative.
566
+ - Equivalent to <*> in Haskell/PureScript.
567
+
568
+ each :: this Option a -> (a -> b) -> undefined
569
+ - similar to 'map', but doesn't return a value.
570
+ - intended for clarity when performing side effects.
571
+
572
+ bind :: this Option a -> (a -> Option b) -> Option b
573
+ - "bind"/"flatMap" operation on the Option Bind/Monad.
574
+ - Equivalent to >>= in Haskell/PureScript; flatMap in Scala.
575
+
576
+ flatten :: {this Option (Option a))} -> () -> Option a
577
+ - "flatten"/"join" operation on the Option Monad.
578
+
579
+ exists :: this Option a -> (a -> Boolean) -> Boolean
580
+
581
+ forall :: this Option a -> (a -> Boolean) -> Boolean
582
+
583
+ filter :: this Option a -> (a -> Boolean) -> Option a
584
+
585
+ equals :: this Option a -> Option a -> Boolean
586
+
587
+ equals_ :: this Option a -> (Option a, a -> Boolean) -> Boolean
588
+
589
+ toArray :: this Option a -> () -> [a]
590
+
591
+ */
592
+
593
+ var none = function () { return NONE; };
594
+
595
+ var NONE = (function () {
596
+ var eq = function (o) {
597
+ return o.isNone();
598
+ };
599
+
600
+ // inlined from peanut, maybe a micro-optimisation?
601
+ var call = function (thunk) { return thunk(); };
602
+ var id = function (n) { return n; };
603
+ var noop = function () { };
604
+
605
+ var me = {
606
+ fold: function (n, s) { return n(); },
607
+ is: never,
608
+ isSome: never,
609
+ isNone: always,
610
+ getOr: id,
611
+ getOrThunk: call,
612
+ getOrDie: function (msg) {
613
+ throw new Error(msg || 'error: getOrDie called on none.');
614
+ },
615
+ or: id,
616
+ orThunk: call,
617
+ map: none,
618
+ ap: none,
619
+ each: noop,
620
+ bind: none,
621
+ flatten: none,
622
+ exists: never,
623
+ forall: always,
624
+ filter: none,
625
+ equals: eq,
626
+ equals_: eq,
627
+ toArray: function () { return []; },
628
+ toString: Fun.constant("none()")
629
+ };
630
+ if (Object.freeze) Object.freeze(me);
631
+ return me;
632
+ })();
633
+
634
+
635
+ /** some :: a -> Option a */
636
+ var some = function (a) {
637
+
638
+ // inlined from peanut, maybe a micro-optimisation?
639
+ var constant_a = function () { return a; };
640
+
641
+ var self = function () {
642
+ // can't Fun.constant this one
643
+ return me;
644
+ };
645
+
646
+ var map = function (f) {
647
+ return some(f(a));
648
+ };
649
+
650
+ var bind = function (f) {
651
+ return f(a);
652
+ };
653
+
654
+ var me = {
655
+ fold: function (n, s) { return s(a); },
656
+ is: function (v) { return a === v; },
657
+ isSome: always,
658
+ isNone: never,
659
+ getOr: constant_a,
660
+ getOrThunk: constant_a,
661
+ getOrDie: constant_a,
662
+ or: self,
663
+ orThunk: self,
664
+ map: map,
665
+ ap: function (optfab) {
666
+ return optfab.fold(none, function(fab) {
667
+ return some(fab(a));
668
+ });
669
+ },
670
+ each: function (f) {
671
+ f(a);
672
+ },
673
+ bind: bind,
674
+ flatten: constant_a,
675
+ exists: bind,
676
+ forall: bind,
677
+ filter: function (f) {
678
+ return f(a) ? me : NONE;
679
+ },
680
+ equals: function (o) {
681
+ return o.is(a);
682
+ },
683
+ equals_: function (o, elementEq) {
684
+ return o.fold(
685
+ never,
686
+ function (b) { return elementEq(a, b); }
687
+ );
688
+ },
689
+ toArray: function () {
690
+ return [a];
691
+ },
692
+ toString: function () {
693
+ return 'some(' + a + ')';
694
+ }
695
+ };
696
+ return me;
697
+ };
698
+
699
+ /** from :: undefined|null|a -> Option a */
700
+ var from = function (value) {
701
+ return value === null || value === undefined ? NONE : some(value);
702
+ };
703
+
704
+ return {
705
+ some: some,
706
+ none: none,
707
+ from: from
708
+ };
709
+ }
710
+ );
711
+
712
+ define(
713
+ 'ephox.katamari.api.Global',
714
+
715
+ [
716
+ ],
717
+
718
+ function () {
719
+ // Use window object as the global if it's available since CSP will block script evals
720
+ var global = typeof window !== 'undefined' ? window : Function('return this;')();
721
+ return global;
722
+ }
723
+ );
724
+
725
+
726
+ define(
727
+ 'ephox.katamari.api.Resolve',
728
+
729
+ [
730
+ 'ephox.katamari.api.Global'
731
+ ],
732
+
733
+ function (Global) {
734
+ /** path :: ([String], JsObj?) -> JsObj */
735
+ var path = function (parts, scope) {
736
+ var o = scope !== undefined ? scope : Global;
737
+ for (var i = 0; i < parts.length && o !== undefined && o !== null; ++i)
738
+ o = o[parts[i]];
739
+ return o;
740
+ };
741
+
742
+ /** resolve :: (String, JsObj?) -> JsObj */
743
+ var resolve = function (p, scope) {
744
+ var parts = p.split('.');
745
+ return path(parts, scope);
746
+ };
747
+
748
+ /** step :: (JsObj, String) -> JsObj */
749
+ var step = function (o, part) {
750
+ if (o[part] === undefined || o[part] === null)
751
+ o[part] = {};
752
+ return o[part];
753
+ };
754
+
755
+ /** forge :: ([String], JsObj?) -> JsObj */
756
+ var forge = function (parts, target) {
757
+ var o = target !== undefined ? target : Global;
758
+ for (var i = 0; i < parts.length; ++i)
759
+ o = step(o, parts[i]);
760
+ return o;
761
+ };
762
+
763
+ /** namespace :: (String, JsObj?) -> JsObj */
764
+ var namespace = function (name, target) {
765
+ var parts = name.split('.');
766
+ return forge(parts, target);
767
+ };
768
+
769
+ return {
770
+ path: path,
771
+ resolve: resolve,
772
+ forge: forge,
773
+ namespace: namespace
774
+ };
775
+ }
776
+ );
777
+
778
+
779
+ define(
780
+ 'ephox.sand.util.Global',
781
+
782
+ [
783
+ 'ephox.katamari.api.Resolve'
784
+ ],
785
+
786
+ function (Resolve) {
787
+ var unsafe = function (name, scope) {
788
+ return Resolve.resolve(name, scope);
789
+ };
790
+
791
+ var getOrDie = function (name, scope) {
792
+ var actual = unsafe(name, scope);
793
+
794
+ if (actual === undefined) throw name + ' not available on this browser';
795
+ return actual;
796
+ };
797
+
798
+ return {
799
+ getOrDie: getOrDie
800
+ };
801
+ }
802
+ );
803
+ define(
804
+ 'ephox.sand.api.Blob',
805
+
806
+ [
807
+ 'ephox.sand.util.Global'
808
+ ],
809
+
810
+ function (Global) {
811
+ /*
812
+ * IE10 and above per
813
+ * https://developer.mozilla.org/en-US/docs/Web/API/Blob
814
+ */
815
+ return function (parts, properties) {
816
+ var f = Global.getOrDie('Blob');
817
+ return new f(parts, properties);
818
+ };
819
+ }
820
+ );
821
+ define(
822
+ 'ephox.sand.api.FileReader',
823
+
824
+ [
825
+ 'ephox.sand.util.Global'
826
+ ],
827
+
828
+ function (Global) {
829
+ /*
830
+ * IE10 and above per
831
+ * https://developer.mozilla.org/en-US/docs/Web/API/FileReader
832
+ */
833
+ return function () {
834
+ var f = Global.getOrDie('FileReader');
835
+ return new f();
836
+ };
837
+ }
838
+ );
839
+ define(
840
+ 'ephox.sand.api.Uint8Array',
841
+
842
+ [
843
+ 'ephox.sand.util.Global'
844
+ ],
845
+
846
+ function (Global) {
847
+ /*
848
+ * https://developer.mozilla.org/en-US/docs/Web/API/Uint8Array
849
+ *
850
+ * IE10 and above per
851
+ * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays
852
+ */
853
+ return function (arr) {
854
+ var f = Global.getOrDie('Uint8Array');
855
+ return new f(arr);
856
+ };
857
+ }
858
+ );
859
+ define(
860
+ 'ephox.sand.api.Window',
861
+
862
+ [
863
+ 'ephox.sand.util.Global'
864
+ ],
865
+
866
+ function (Global) {
867
+ /******************************************************************************************
868
+ * BIG BIG WARNING: Don't put anything other than top-level window functions in here.
869
+ *
870
+ * Objects that are technically available as window.X should be in their own module X (e.g. Blob, FileReader, URL).
871
+ ******************************************************************************************
872
+ */
873
+
874
+ /*
875
+ * IE10 and above per
876
+ * https://developer.mozilla.org/en/docs/Web/API/window.requestAnimationFrame
877
+ */
878
+ var requestAnimationFrame = function (callback) {
879
+ var f = Global.getOrDie('requestAnimationFrame');
880
+ f(callback);
881
+ };
882
+
883
+ /*
884
+ * IE10 and above per
885
+ * https://developer.mozilla.org/en-US/docs/Web/API/WindowBase64.atob
886
+ */
887
+ var atob = function (base64) {
888
+ var f = Global.getOrDie('atob');
889
+ return f(base64);
890
+ };
891
+
892
+ return {
893
+ atob: atob,
894
+ requestAnimationFrame: requestAnimationFrame
895
+ };
896
+ }
897
+ );
898
+ defineGlobal("global!Math", Math);
899
+ define(
900
+ 'ephox.imagetools.util.Conversions',
901
+ [
902
+ 'ephox.imagetools.util.Canvas',
903
+ 'ephox.imagetools.util.ImageSize',
904
+ 'ephox.imagetools.util.Promise',
905
+ 'ephox.katamari.api.Option',
906
+ 'ephox.sand.api.Blob',
907
+ 'ephox.sand.api.FileReader',
908
+ 'ephox.sand.api.Uint8Array',
909
+ 'ephox.sand.api.Window',
910
+ 'global!Array',
911
+ 'global!Math'
912
+ ],
913
+ function (Canvas, ImageSize, Promise, Option, Blob, FileReader, Uint8Array, Window, Array, Math) {
914
+ function loadImage(image) {
915
+ return new Promise(function (resolve) {
916
+ function loaded() {
917
+ image.removeEventListener('load', loaded);
918
+ resolve(image);
919
+ }
920
+
921
+ if (image.complete) {
922
+ resolve(image);
923
+ } else {
924
+ image.addEventListener('load', loaded);
925
+ }
926
+ });
927
+ }
928
+
929
+ function imageToBlob(image) {
930
+ return loadImage(image).then(function (image) {
931
+ var src = image.src;
932
+
933
+ if (src.indexOf('blob:') === 0) {
934
+ return anyUriToBlob(src);
935
+ }
936
+
937
+ if (src.indexOf('data:') === 0) {
938
+ return dataUriToBlob(src);
939
+ }
940
+
941
+ return anyUriToBlob(src);
942
+ });
943
+ }
944
+
945
+ function blobToImage(blob) {
946
+ return new Promise(function (resolve, reject) {
947
+ var blobUrl = URL.createObjectURL(blob);
948
+
949
+ var image = new Image();
950
+
951
+ var removeListeners = function () {
952
+ image.removeEventListener('load', loaded);
953
+ image.removeEventListener('error', error);
954
+ };
955
+
956
+ function loaded() {
957
+ removeListeners();
958
+ resolve(image);
959
+ }
960
+
961
+ function error() {
962
+ removeListeners();
963
+ reject('Unable to load data of type ' + blob.type + ': ' + blobUrl);
964
+ }
965
+
966
+ image.addEventListener('load', loaded);
967
+ image.addEventListener('error', error);
968
+ image.src = blobUrl;
969
+
970
+ if (image.complete) {
971
+ loaded();
972
+ }
973
+ });
974
+ }
975
+
976
+ function anyUriToBlob(url) {
977
+ return new Promise(function (resolve) {
978
+ var xhr = new XMLHttpRequest();
979
+
980
+ xhr.open('GET', url, true);
981
+
982
+ // works with IE10+
983
+ xhr.responseType = 'blob';
984
+
985
+ xhr.onload = function () {
986
+ if (this.status == 200) {
987
+ resolve(this.response);
988
+ }
989
+ };
990
+
991
+ xhr.send();
992
+ });
993
+ }
994
+
995
+ function dataUriToBlobSync(uri) {
996
+ var data = uri.split(',');
997
+
998
+ var matches = /data:([^;]+)/.exec(data[0]);
999
+ if (!matches) return Option.none();
1000
+
1001
+ var mimetype = matches[1];
1002
+ var base64 = data[1];
1003
+
1004
+ // al gore rhythm via http://stackoverflow.com/questions/16245767/creating-a-blob-from-a-base64-string-in-javascript
1005
+ var sliceSize = 1024;
1006
+ var byteCharacters = Window.atob(base64);
1007
+ var bytesLength = byteCharacters.length;
1008
+ var slicesCount = Math.ceil(bytesLength / sliceSize);
1009
+ var byteArrays = new Array(slicesCount);
1010
+
1011
+ for (var sliceIndex = 0; sliceIndex < slicesCount; ++sliceIndex) {
1012
+ var begin = sliceIndex * sliceSize;
1013
+ var end = Math.min(begin + sliceSize, bytesLength);
1014
+
1015
+ var bytes = new Array(end - begin);
1016
+ for (var offset = begin, i = 0; offset < end; ++i, ++offset) {
1017
+ bytes[i] = byteCharacters[offset].charCodeAt(0);
1018
+ }
1019
+ byteArrays[sliceIndex] = Uint8Array(bytes);
1020
+ }
1021
+ return Option.some(Blob(byteArrays, { type: mimetype }));
1022
+ }
1023
+
1024
+ function dataUriToBlob(uri) {
1025
+ return new Promise(function (resolve, reject) {
1026
+ dataUriToBlobSync(uri).fold(function () {
1027
+ // uri isn't valid
1028
+ reject('uri is not base64: ' + uri);
1029
+ }, resolve);
1030
+ });
1031
+ }
1032
+
1033
+ function uriToBlob(url) {
1034
+ if (url.indexOf('blob:') === 0) {
1035
+ return anyUriToBlob(url);
1036
+ }
1037
+
1038
+ if (url.indexOf('data:') === 0) {
1039
+ return dataUriToBlob(url);
1040
+ }
1041
+
1042
+ return null;
1043
+ }
1044
+
1045
+ function canvasToBlob(canvas, type, quality) {
1046
+ type = type || 'image/png';
1047
+
1048
+ if (HTMLCanvasElement.prototype.toBlob) {
1049
+ return new Promise(function (resolve) {
1050
+ canvas.toBlob(function (blob) {
1051
+ resolve(blob);
1052
+ }, type, quality);
1053
+ });
1054
+ } else {
1055
+ return dataUriToBlob(canvas.toDataURL(type, quality));
1056
+ }
1057
+ }
1058
+
1059
+ function canvasToDataURL(getCanvas, type, quality) {
1060
+ type = type || 'image/png';
1061
+ return getCanvas.then(function (canvas) {
1062
+ return canvas.toDataURL(type, quality);
1063
+ });
1064
+ }
1065
+
1066
+ function blobToCanvas(blob) {
1067
+ return blobToImage(blob).then(function (image) {
1068
+ // we aren't retaining the image, so revoke the URL immediately
1069
+ revokeImageUrl(image);
1070
+
1071
+ var context, canvas;
1072
+
1073
+ canvas = Canvas.create(ImageSize.getWidth(image), ImageSize.getHeight(image));
1074
+ context = Canvas.get2dContext(canvas);
1075
+ context.drawImage(image, 0, 0);
1076
+
1077
+ return canvas;
1078
+ });
1079
+ }
1080
+
1081
+ function blobToDataUri(blob) {
1082
+ return new Promise(function (resolve) {
1083
+ var reader = new FileReader();
1084
+
1085
+ reader.onloadend = function () {
1086
+ resolve(reader.result);
1087
+ };
1088
+
1089
+ reader.readAsDataURL(blob);
1090
+ });
1091
+ }
1092
+
1093
+ function blobToBase64(blob) {
1094
+ return blobToDataUri(blob).then(function (dataUri) {
1095
+ return dataUri.split(',')[1];
1096
+ });
1097
+ }
1098
+
1099
+ function revokeImageUrl(image) {
1100
+ URL.revokeObjectURL(image.src);
1101
+ }
1102
+
1103
+ return {
1104
+ // used outside
1105
+ blobToImage: blobToImage,
1106
+ imageToBlob: imageToBlob,
1107
+ blobToDataUri: blobToDataUri,
1108
+ blobToBase64: blobToBase64,
1109
+ dataUriToBlobSync: dataUriToBlobSync,
1110
+
1111
+ // helper method
1112
+ canvasToBlob: canvasToBlob,
1113
+ canvasToDataURL: canvasToDataURL,
1114
+ blobToCanvas: blobToCanvas,
1115
+ uriToBlob: uriToBlob
1116
+ };
1117
+ });
1118
+ define(
1119
+ 'ephox.imagetools.api.BlobConversions',
1120
+ [
1121
+ 'ephox.imagetools.util.Conversions',
1122
+ 'ephox.katamari.api.Option'
1123
+ ],
1124
+ function (Conversions, Option) {
1125
+ var blobToImage = function (image) {
1126
+ return Conversions.blobToImage(image);
1127
+ };
1128
+
1129
+ var imageToBlob = function (blob) {
1130
+ return Conversions.imageToBlob(blob);
1131
+ };
1132
+
1133
+ var blobToDataUri = function (blob) {
1134
+ return Conversions.blobToDataUri(blob);
1135
+ };
1136
+
1137
+ var blobToBase64 = function (blob) {
1138
+ return Conversions.blobToBase64(blob);
1139
+ };
1140
+
1141
+ var dataUriToBlobSync = function (uri) {
1142
+ return Conversions.dataUriToBlobSync(uri);
1143
+ };
1144
+
1145
+ var uriToBlob = function (uri) {
1146
+ return Option.from(Conversions.uriToBlob(uri));
1147
+ };
1148
+
1149
+ return {
1150
+ // used outside
1151
+ blobToImage: blobToImage,
1152
+ imageToBlob: imageToBlob,
1153
+ blobToDataUri: blobToDataUri,
1154
+ blobToBase64: blobToBase64,
1155
+ dataUriToBlobSync: dataUriToBlobSync,
1156
+ uriToBlob: uriToBlob
1157
+ };
1158
+ }
1159
+ );
1160
+ define(
1161
+ 'ephox.imagetools.util.ImageResult',
1162
+ [
1163
+ 'ephox.imagetools.util.Canvas',
1164
+ 'ephox.imagetools.util.Conversions',
1165
+ 'ephox.imagetools.util.Promise',
1166
+ 'ephox.katamari.api.Fun'
1167
+ ],
1168
+ function (Canvas, Conversions, Promise, Fun) {
1169
+ function create(getCanvas, blob, uri) {
1170
+ var initialType = blob.type;
1171
+
1172
+ var getType = Fun.constant(initialType);
1173
+
1174
+ function toBlob() {
1175
+ return Promise.resolve(blob);
1176
+ }
1177
+
1178
+ function toDataURL() {
1179
+ return uri;
1180
+ }
1181
+
1182
+ function toBase64() {
1183
+ return uri.split(',')[1];
1184
+ }
1185
+
1186
+ function toAdjustedBlob(type, quality) {
1187
+ return getCanvas.then(function (canvas) {
1188
+ return Conversions.canvasToBlob(canvas, type, quality);
1189
+ });
1190
+ }
1191
+
1192
+ function toAdjustedDataURL(type, quality) {
1193
+ return getCanvas.then(function (canvas) {
1194
+ return Conversions.canvasToDataURL(canvas, type, quality);
1195
+ });
1196
+ }
1197
+
1198
+ function toAdjustedBase64(type, quality) {
1199
+ return toAdjustedDataURL(type, quality).then(function (dataurl) {
1200
+ return dataurl.split(',')[1];
1201
+ });
1202
+ }
1203
+
1204
+ function toCanvas() {
1205
+ return getCanvas.then(Canvas.clone);
1206
+ }
1207
+
1208
+ return {
1209
+ getType: getType,
1210
+ toBlob: toBlob,
1211
+ toDataURL: toDataURL,
1212
+ toBase64: toBase64,
1213
+ toAdjustedBlob: toAdjustedBlob,
1214
+ toAdjustedDataURL: toAdjustedDataURL,
1215
+ toAdjustedBase64: toAdjustedBase64,
1216
+ toCanvas: toCanvas
1217
+ };
1218
+ }
1219
+
1220
+ function fromBlob(blob) {
1221
+ return Conversions.blobToDataUri(blob).then(function (uri) {
1222
+ return create(Conversions.blobToCanvas(blob), blob, uri);
1223
+ });
1224
+ }
1225
+
1226
+ function fromCanvas(canvas, type) {
1227
+ return Conversions.canvasToBlob(canvas, type).then(function (blob) {
1228
+ return create(Promise.resolve(canvas), blob, canvas.toDataURL());
1229
+ });
1230
+ }
1231
+
1232
+ function fromImage(image) {
1233
+ return Conversions.imageToBlob(image).then(function (blob) {
1234
+ return fromBlob(blob);
1235
+ });
1236
+ }
1237
+
1238
+ var fromBlobAndUrlSync = function (blob, url) {
1239
+ return create(Conversions.blobToCanvas(blob), blob, url);
1240
+ };
1241
+
1242
+ return {
1243
+ fromBlob: fromBlob,
1244
+ fromCanvas: fromCanvas,
1245
+ fromImage: fromImage,
1246
+ fromBlobAndUrlSync: fromBlobAndUrlSync
1247
+ };
1248
+ });
1249
+
1250
+ define(
1251
+ 'ephox.imagetools.transformations.ColorMatrix',
1252
+ [
1253
+ ],
1254
+ function () {
1255
+ function clamp(value, min, max) {
1256
+ value = parseFloat(value);
1257
+
1258
+ if (value > max) {
1259
+ value = max;
1260
+ } else if (value < min) {
1261
+ value = min;
1262
+ }
1263
+
1264
+ return value;
1265
+ }
1266
+
1267
+ function identity() {
1268
+ return [
1269
+ 1, 0, 0, 0, 0,
1270
+ 0, 1, 0, 0, 0,
1271
+ 0, 0, 1, 0, 0,
1272
+ 0, 0, 0, 1, 0,
1273
+ 0, 0, 0, 0, 1
1274
+ ];
1275
+ }
1276
+
1277
+ var DELTA_INDEX = [
1278
+ 0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11,
1279
+ 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
1280
+ 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
1281
+ 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68,
1282
+ 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
1283
+ 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
1284
+ 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25,
1285
+ 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8,
1286
+ 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0,
1287
+ 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8,
1288
+ 10.0
1289
+ ];
1290
+
1291
+ function multiply(matrix1, matrix2) {
1292
+ var i, j, k, val, col = [], out = new Array(10);
1293
+
1294
+ for (i = 0; i < 5; i++) {
1295
+ for (j = 0; j < 5; j++) {
1296
+ col[j] = matrix2[j + i * 5];
1297
+ }
1298
+
1299
+ for (j = 0; j < 5; j++) {
1300
+ val = 0;
1301
+
1302
+ for (k = 0; k < 5; k++) {
1303
+ val += matrix1[j + k * 5] * col[k];
1304
+ }
1305
+
1306
+ out[j + i * 5] = val;
1307
+ }
1308
+ }
1309
+
1310
+ return out;
1311
+ }
1312
+
1313
+ function adjust(matrix, adjustValue) {
1314
+ adjustValue = clamp(adjustValue, 0, 1);
1315
+
1316
+ return matrix.map(function (value, index) {
1317
+ if (index % 6 === 0) {
1318
+ value = 1.0 - ((1 - value) * adjustValue);
1319
+ } else {
1320
+ value *= adjustValue;
1321
+ }
1322
+
1323
+ return clamp(value, 0, 1);
1324
+ });
1325
+ }
1326
+
1327
+ function adjustContrast(matrix, value) {
1328
+ var x;
1329
+
1330
+ value = clamp(value, -1, 1);
1331
+ value *= 100;
1332
+
1333
+ if (value < 0) {
1334
+ x = 127 + value / 100 * 127;
1335
+ } else {
1336
+ x = value % 1;
1337
+
1338
+ if (x === 0) {
1339
+ x = DELTA_INDEX[value];
1340
+ } else {
1341
+ // use linear interpolation for more granularity.
1342
+ x = DELTA_INDEX[(Math.floor(value))] * (1 - x) + DELTA_INDEX[(Math.floor(value)) + 1] * x;
1343
+ }
1344
+
1345
+ x = x * 127 + 127;
1346
+ }
1347
+
1348
+ return multiply(matrix, [
1349
+ x / 127, 0, 0, 0, 0.5 * (127 - x),
1350
+ 0, x / 127, 0, 0, 0.5 * (127 - x),
1351
+ 0, 0, x / 127, 0, 0.5 * (127 - x),
1352
+ 0, 0, 0, 1, 0,
1353
+ 0, 0, 0, 0, 1
1354
+ ]);
1355
+ }
1356
+
1357
+ function adjustSaturation(matrix, value) {
1358
+ var x, lumR, lumG, lumB;
1359
+
1360
+ value = clamp(value, -1, 1);
1361
+ x = 1 + ((value > 0) ? 3 * value : value);
1362
+ lumR = 0.3086;
1363
+ lumG = 0.6094;
1364
+ lumB = 0.0820;
1365
+
1366
+ return multiply(matrix, [
1367
+ lumR * (1 - x) + x, lumG * (1 - x), lumB * (1 - x), 0, 0,
1368
+ lumR * (1 - x), lumG * (1 - x) + x, lumB * (1 - x), 0, 0,
1369
+ lumR * (1 - x), lumG * (1 - x), lumB * (1 - x) + x, 0, 0,
1370
+ 0, 0, 0, 1, 0,
1371
+ 0, 0, 0, 0, 1
1372
+ ]);
1373
+ }
1374
+
1375
+ function adjustHue(matrix, angle) {
1376
+ var cosVal, sinVal, lumR, lumG, lumB;
1377
+
1378
+ angle = clamp(angle, -180, 180) / 180 * Math.PI;
1379
+ cosVal = Math.cos(angle);
1380
+ sinVal = Math.sin(angle);
1381
+ lumR = 0.213;
1382
+ lumG = 0.715;
1383
+ lumB = 0.072;
1384
+
1385
+ return multiply(matrix, [
1386
+ lumR + cosVal * (1 - lumR) + sinVal * (-lumR), lumG + cosVal * (-lumG) + sinVal * (-lumG),
1387
+ lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0,
1388
+ lumR + cosVal * (-lumR) + sinVal * (0.143), lumG + cosVal * (1 - lumG) + sinVal * (0.140),
1389
+ lumB + cosVal * (-lumB) + sinVal * (-0.283), 0, 0,
1390
+ lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)), lumG + cosVal * (-lumG) + sinVal * (lumG),
1391
+ lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0,
1392
+ 0, 0, 0, 1, 0,
1393
+ 0, 0, 0, 0, 1
1394
+ ]);
1395
+ }
1396
+
1397
+ function adjustBrightness(matrix, value) {
1398
+ value = clamp(255 * value, -255, 255);
1399
+
1400
+ return multiply(matrix, [
1401
+ 1, 0, 0, 0, value,
1402
+ 0, 1, 0, 0, value,
1403
+ 0, 0, 1, 0, value,
1404
+ 0, 0, 0, 1, 0,
1405
+ 0, 0, 0, 0, 1
1406
+ ]);
1407
+ }
1408
+
1409
+ function adjustColors(matrix, adjustR, adjustG, adjustB) {
1410
+ adjustR = clamp(adjustR, 0, 2);
1411
+ adjustG = clamp(adjustG, 0, 2);
1412
+ adjustB = clamp(adjustB, 0, 2);
1413
+
1414
+ return multiply(matrix, [
1415
+ adjustR, 0, 0, 0, 0,
1416
+ 0, adjustG, 0, 0, 0,
1417
+ 0, 0, adjustB, 0, 0,
1418
+ 0, 0, 0, 1, 0,
1419
+ 0, 0, 0, 0, 1
1420
+ ]);
1421
+ }
1422
+
1423
+ function adjustSepia(matrix, value) {
1424
+ value = clamp(value, 0, 1);
1425
+
1426
+ return multiply(matrix, adjust([
1427
+ 0.393, 0.769, 0.189, 0, 0,
1428
+ 0.349, 0.686, 0.168, 0, 0,
1429
+ 0.272, 0.534, 0.131, 0, 0,
1430
+ 0, 0, 0, 1, 0,
1431
+ 0, 0, 0, 0, 1
1432
+ ], value));
1433
+ }
1434
+
1435
+ function adjustGrayscale(matrix, value) {
1436
+ value = clamp(value, 0, 1);
1437
+
1438
+ return multiply(matrix, adjust([
1439
+ 0.33, 0.34, 0.33, 0, 0,
1440
+ 0.33, 0.34, 0.33, 0, 0,
1441
+ 0.33, 0.34, 0.33, 0, 0,
1442
+ 0, 0, 0, 1, 0,
1443
+ 0, 0, 0, 0, 1
1444
+ ], value));
1445
+ }
1446
+
1447
+ return {
1448
+ identity: identity,
1449
+ adjust: adjust,
1450
+ multiply: multiply,
1451
+ adjustContrast: adjustContrast,
1452
+ adjustBrightness: adjustBrightness,
1453
+ adjustSaturation: adjustSaturation,
1454
+ adjustHue: adjustHue,
1455
+ adjustColors: adjustColors,
1456
+ adjustSepia: adjustSepia,
1457
+ adjustGrayscale: adjustGrayscale
1458
+ };
1459
+ });
1460
+ define(
1461
+ 'ephox.imagetools.transformations.Filters',
1462
+ [
1463
+ 'ephox.imagetools.util.Canvas',
1464
+ 'ephox.imagetools.util.ImageResult',
1465
+ 'ephox.imagetools.transformations.ColorMatrix'
1466
+ ],
1467
+ function (Canvas, ImageResult, ColorMatrix) {
1468
+ function colorFilter(ir, matrix) {
1469
+ return ir.toCanvas().then(function (canvas) {
1470
+ return applyColorFilter(canvas, ir.getType(), matrix);
1471
+ });
1472
+ }
1473
+
1474
+ function applyColorFilter(canvas, type, matrix) {
1475
+ var context = Canvas.get2dContext(canvas);
1476
+ var pixels;
1477
+
1478
+ function applyMatrix(pixels, m) {
1479
+ var d = pixels.data, r, g, b, a, i,
1480
+ m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], m4 = m[4],
1481
+ m5 = m[5], m6 = m[6], m7 = m[7], m8 = m[8], m9 = m[9],
1482
+ m10 = m[10], m11 = m[11], m12 = m[12], m13 = m[13], m14 = m[14],
1483
+ m15 = m[15], m16 = m[16], m17 = m[17], m18 = m[18], m19 = m[19];
1484
+
1485
+ for (i = 0; i < d.length; i += 4) {
1486
+ r = d[i];
1487
+ g = d[i + 1];
1488
+ b = d[i + 2];
1489
+ a = d[i + 3];
1490
+
1491
+ d[i] = r * m0 + g * m1 + b * m2 + a * m3 + m4;
1492
+ d[i + 1] = r * m5 + g * m6 + b * m7 + a * m8 + m9;
1493
+ d[i + 2] = r * m10 + g * m11 + b * m12 + a * m13 + m14;
1494
+ d[i + 3] = r * m15 + g * m16 + b * m17 + a * m18 + m19;
1495
+ }
1496
+
1497
+ return pixels;
1498
+ }
1499
+
1500
+ pixels = applyMatrix(context.getImageData(0, 0, canvas.width, canvas.height), matrix);
1501
+ context.putImageData(pixels, 0, 0);
1502
+
1503
+ return ImageResult.fromCanvas(canvas, type);
1504
+ }
1505
+
1506
+ function convoluteFilter(ir, matrix) {
1507
+ return ir.toCanvas().then(function (canvas) {
1508
+ return applyConvoluteFilter(canvas, ir.getType(), matrix);
1509
+ });
1510
+ }
1511
+
1512
+ function applyConvoluteFilter(canvas, type, matrix) {
1513
+ var context = Canvas.get2dContext(canvas);
1514
+ var pixelsIn, pixelsOut;
1515
+
1516
+ function applyMatrix(pixelsIn, pixelsOut, matrix) {
1517
+ var rgba, drgba, side, halfSide, x, y, r, g, b,
1518
+ cx, cy, scx, scy, offset, wt, w, h;
1519
+
1520
+ function clamp(value, min, max) {
1521
+ if (value > max) {
1522
+ value = max;
1523
+ } else if (value < min) {
1524
+ value = min;
1525
+ }
1526
+
1527
+ return value;
1528
+ }
1529
+
1530
+ // Calc side and half side of matrix
1531
+ side = Math.round(Math.sqrt(matrix.length));
1532
+ halfSide = Math.floor(side / 2);
1533
+ rgba = pixelsIn.data;
1534
+ drgba = pixelsOut.data;
1535
+ w = pixelsIn.width;
1536
+ h = pixelsIn.height;
1537
+
1538
+ // Apply convolution matrix to pixels
1539
+ for (y = 0; y < h; y++) {
1540
+ for (x = 0; x < w; x++) {
1541
+ r = g = b = 0;
1542
+
1543
+ for (cy = 0; cy < side; cy++) {
1544
+ for (cx = 0; cx < side; cx++) {
1545
+ // Calc relative x, y based on matrix
1546
+ scx = clamp(x + cx - halfSide, 0, w - 1);
1547
+ scy = clamp(y + cy - halfSide, 0, h - 1);
1548
+
1549
+ // Calc r, g, b
1550
+ offset = (scy * w + scx) * 4;
1551
+ wt = matrix[cy * side + cx];
1552
+ r += rgba[offset] * wt;
1553
+ g += rgba[offset + 1] * wt;
1554
+ b += rgba[offset + 2] * wt;
1555
+ }
1556
+ }
1557
+
1558
+ // Set new RGB to destination buffer
1559
+ offset = (y * w + x) * 4;
1560
+ drgba[offset] = clamp(r, 0, 255);
1561
+ drgba[offset + 1] = clamp(g, 0, 255);
1562
+ drgba[offset + 2] = clamp(b, 0, 255);
1563
+ }
1564
+ }
1565
+
1566
+ return pixelsOut;
1567
+ }
1568
+
1569
+ pixelsIn = context.getImageData(0, 0, canvas.width, canvas.height);
1570
+ pixelsOut = context.getImageData(0, 0, canvas.width, canvas.height);
1571
+ pixelsOut = applyMatrix(pixelsIn, pixelsOut, matrix);
1572
+ context.putImageData(pixelsOut, 0, 0);
1573
+
1574
+ return ImageResult.fromCanvas(canvas, type);
1575
+ }
1576
+
1577
+ function functionColorFilter(colorFn) {
1578
+ var filterImpl = function (canvas, type, value) {
1579
+ var context = Canvas.get2dContext(canvas);
1580
+ var pixels, i, lookup = new Array(256);
1581
+
1582
+ function applyLookup(pixels, lookup) {
1583
+ var d = pixels.data, i;
1584
+
1585
+ for (i = 0; i < d.length; i += 4) {
1586
+ d[i] = lookup[d[i]];
1587
+ d[i + 1] = lookup[d[i + 1]];
1588
+ d[i + 2] = lookup[d[i + 2]];
1589
+ }
1590
+
1591
+ return pixels;
1592
+ }
1593
+
1594
+ for (i = 0; i < lookup.length; i++) {
1595
+ lookup[i] = colorFn(i, value);
1596
+ }
1597
+
1598
+ pixels = applyLookup(context.getImageData(0, 0, canvas.width, canvas.height), lookup);
1599
+ context.putImageData(pixels, 0, 0);
1600
+
1601
+ return ImageResult.fromCanvas(canvas, type);
1602
+ };
1603
+
1604
+ return function (ir, value) {
1605
+ return ir.toCanvas().then(function (canvas) {
1606
+ return filterImpl(canvas, ir.getType(), value);
1607
+ });
1608
+ };
1609
+ }
1610
+
1611
+ function complexAdjustableColorFilter(matrixAdjustFn) {
1612
+ return function (ir, adjust) {
1613
+ return colorFilter(ir, matrixAdjustFn(ColorMatrix.identity(), adjust));
1614
+ };
1615
+ }
1616
+
1617
+ function basicColorFilter(matrix) {
1618
+ return function (ir) {
1619
+ return colorFilter(ir, matrix);
1620
+ };
1621
+ }
1622
+
1623
+ function basicConvolutionFilter(kernel) {
1624
+ return function (ir) {
1625
+ return convoluteFilter(ir, kernel);
1626
+ };
1627
+ }
1628
+
1629
+ return {
1630
+ invert: basicColorFilter([
1631
+ -1, 0, 0, 0, 255,
1632
+ 0, -1, 0, 0, 255,
1633
+ 0, 0, -1, 0, 255,
1634
+ 0, 0, 0, 1, 0
1635
+ ]),
1636
+
1637
+ brightness: complexAdjustableColorFilter(ColorMatrix.adjustBrightness),
1638
+ hue: complexAdjustableColorFilter(ColorMatrix.adjustHue),
1639
+ saturate: complexAdjustableColorFilter(ColorMatrix.adjustSaturation),
1640
+ contrast: complexAdjustableColorFilter(ColorMatrix.adjustContrast),
1641
+ grayscale: complexAdjustableColorFilter(ColorMatrix.adjustGrayscale),
1642
+ sepia: complexAdjustableColorFilter(ColorMatrix.adjustSepia),
1643
+ colorize: function (ir, adjustR, adjustG, adjustB) {
1644
+ return colorFilter(ir, ColorMatrix.adjustColors(ColorMatrix.identity(), adjustR, adjustG, adjustB));
1645
+ },
1646
+
1647
+ sharpen: basicConvolutionFilter([
1648
+ 0, -1, 0,
1649
+ -1, 5, -1,
1650
+ 0, -1, 0
1651
+ ]),
1652
+
1653
+ emboss: basicConvolutionFilter([
1654
+ -2, -1, 0,
1655
+ -1, 1, 1,
1656
+ 0, 1, 2
1657
+ ]),
1658
+
1659
+ gamma: functionColorFilter(function (color, value) {
1660
+ return Math.pow(color / 255, 1 - value) * 255;
1661
+ }),
1662
+
1663
+ exposure: functionColorFilter(function (color, value) {
1664
+ return 255 * (1 - Math.exp(-(color / 255) * value));
1665
+ }),
1666
+
1667
+ colorFilter: colorFilter,
1668
+ convoluteFilter: convoluteFilter
1669
+ };
1670
+ });
1671
+ define(
1672
+ 'ephox.imagetools.transformations.ImageResizerCanvas',
1673
+ [
1674
+ 'ephox.imagetools.util.Canvas',
1675
+ 'ephox.imagetools.util.ImageSize',
1676
+ 'ephox.imagetools.util.Promise'
1677
+ ],
1678
+ function (Canvas, ImageSize, Promise) {
1679
+ /**
1680
+ * @method scale
1681
+ * @static
1682
+ * @param image {Image|Canvas}
1683
+ * @param dW {Number} Width that the image should be scaled to
1684
+ * @param dH {Number} Height that the image should be scaled to
1685
+ * @returns {Promise}
1686
+ */
1687
+ function scale(image, dW, dH) {
1688
+ var sW = ImageSize.getWidth(image);
1689
+ var sH = ImageSize.getHeight(image);
1690
+ var wRatio = dW / sW;
1691
+ var hRatio = dH / sH;
1692
+ var scaleCapped = false;
1693
+
1694
+ if (wRatio < 0.5 || wRatio > 2) {
1695
+ wRatio = wRatio < 0.5 ? 0.5 : 2;
1696
+ scaleCapped = true;
1697
+ }
1698
+ if (hRatio < 0.5 || hRatio > 2) {
1699
+ hRatio = hRatio < 0.5 ? 0.5 : 2;
1700
+ scaleCapped = true;
1701
+ }
1702
+
1703
+ var scaled = _scale(image, wRatio, hRatio);
1704
+
1705
+ return !scaleCapped ? scaled : scaled.then(function (tCanvas) {
1706
+ return scale(tCanvas, dW, dH);
1707
+ });
1708
+ }
1709
+
1710
+
1711
+ function _scale(image, wRatio, hRatio) {
1712
+ return new Promise(function (resolve) {
1713
+ var sW = ImageSize.getWidth(image);
1714
+ var sH = ImageSize.getHeight(image);
1715
+ var dW = Math.floor(sW * wRatio);
1716
+ var dH = Math.floor(sH * hRatio);
1717
+ var canvas = Canvas.create(dW, dH);
1718
+ var context = Canvas.get2dContext(canvas);
1719
+
1720
+ context.drawImage(image, 0, 0, sW, sH, 0, 0, dW, dH);
1721
+
1722
+ resolve(canvas);
1723
+ });
1724
+ }
1725
+
1726
+ return {
1727
+ scale: scale
1728
+ };
1729
+
1730
+ });
1731
+
1732
+ define(
1733
+ 'ephox.imagetools.transformations.ImageTools',
1734
+ [
1735
+ 'ephox.imagetools.util.Canvas',
1736
+ 'ephox.imagetools.util.ImageResult',
1737
+ 'ephox.imagetools.transformations.ImageResizerCanvas'
1738
+ ],
1739
+ function (Canvas, ImageResult, ImageResizerCanvas) {
1740
+ function rotate(ir, angle) {
1741
+ return ir.toCanvas().then(function (canvas) {
1742
+ return applyRotate(canvas, ir.getType(), angle);
1743
+ });
1744
+ }
1745
+ function applyRotate(image, type, angle) {
1746
+ var canvas = Canvas.create(image.width, image.height);
1747
+ var context = Canvas.get2dContext(canvas);
1748
+ var translateX = 0, translateY = 0;
1749
+
1750
+ angle = angle < 0 ? 360 + angle : angle;
1751
+
1752
+ if (angle == 90 || angle == 270) {
1753
+ Canvas.resize(canvas, canvas.height, canvas.width);
1754
+ }
1755
+
1756
+ if (angle == 90 || angle == 180) {
1757
+ translateX = canvas.width;
1758
+ }
1759
+
1760
+ if (angle == 270 || angle == 180) {
1761
+ translateY = canvas.height;
1762
+ }
1763
+
1764
+ context.translate(translateX, translateY);
1765
+ context.rotate(angle * Math.PI / 180);
1766
+ context.drawImage(image, 0, 0);
1767
+
1768
+ return ImageResult.fromCanvas(canvas, type);
1769
+ }
1770
+
1771
+ function flip(ir, axis) {
1772
+ return ir.toCanvas().then(function (canvas) {
1773
+ return applyFlip(canvas, ir.getType(), axis);
1774
+ });
1775
+ }
1776
+ function applyFlip(image, type, axis) {
1777
+ var canvas = Canvas.create(image.width, image.height);
1778
+ var context = Canvas.get2dContext(canvas);
1779
+
1780
+ if (axis == 'v') {
1781
+ context.scale(1, -1);
1782
+ context.drawImage(image, 0, -canvas.height);
1783
+ } else {
1784
+ context.scale(-1, 1);
1785
+ context.drawImage(image, -canvas.width, 0);
1786
+ }
1787
+
1788
+ return ImageResult.fromCanvas(canvas, type);
1789
+ }
1790
+
1791
+ function crop(ir, x, y, w, h) {
1792
+ return ir.toCanvas().then(function (canvas) {
1793
+ return applyCrop(canvas, ir.getType(), x, y, w, h);
1794
+ });
1795
+ }
1796
+ function applyCrop(image, type, x, y, w, h) {
1797
+ var canvas = Canvas.create(w, h);
1798
+ var context = Canvas.get2dContext(canvas);
1799
+
1800
+ context.drawImage(image, -x, -y);
1801
+
1802
+ return ImageResult.fromCanvas(canvas, type);
1803
+ }
1804
+
1805
+
1806
+ function resize(ir, w, h) {
1807
+ return ir.toCanvas().then(function (canvas) {
1808
+ return ImageResizerCanvas.scale(canvas, w, h)
1809
+ .then(function (newCanvas) {
1810
+ return ImageResult.fromCanvas(newCanvas, ir.getType());
1811
+ });
1812
+ });
1813
+ }
1814
+
1815
+ return {
1816
+ rotate: rotate,
1817
+ flip: flip,
1818
+ crop: crop,
1819
+ resize: resize
1820
+ };
1821
+ });
1822
+
1823
+ define(
1824
+ 'ephox.imagetools.api.ImageTransformations',
1825
+ [
1826
+ 'ephox.imagetools.transformations.Filters',
1827
+ 'ephox.imagetools.transformations.ImageTools'
1828
+ ],
1829
+ function (Filters, ImageTools) {
1830
+ var invert = function (ir) {
1831
+ return Filters.invert(ir);
1832
+ };
1833
+
1834
+ var sharpen = function (ir) {
1835
+ return Filters.sharpen(ir);
1836
+ };
1837
+
1838
+ var emboss = function (ir) {
1839
+ return Filters.emboss(ir);
1840
+ };
1841
+
1842
+ var gamma = function (ir, value) {
1843
+ return Filters.gamma(ir, value);
1844
+ };
1845
+
1846
+ var exposure = function (ir, value) {
1847
+ return Filters.exposure(ir, value);
1848
+ };
1849
+
1850
+ var colorize = function (ir, adjustR, adjustG, adjustB) {
1851
+ return Filters.colorize(ir, adjustR, adjustG, adjustB);
1852
+ };
1853
+
1854
+ var brightness = function (ir, adjust) {
1855
+ return Filters.brightness(ir, adjust);
1856
+ };
1857
+
1858
+ var hue = function (ir, adjust) {
1859
+ return Filters.hue(ir, adjust);
1860
+ };
1861
+
1862
+ var saturate = function (ir, adjust) {
1863
+ return Filters.saturate(ir, adjust);
1864
+ };
1865
+
1866
+ var contrast = function (ir, adjust) {
1867
+ return Filters.contrast(ir, adjust);
1868
+ };
1869
+
1870
+ var grayscale = function (ir, adjust) {
1871
+ return Filters.grayscale(ir, adjust);
1872
+ };
1873
+
1874
+ var sepia = function (ir, adjust) {
1875
+ return Filters.sepia(ir, adjust);
1876
+ };
1877
+
1878
+ var flip = function (ir, axis) {
1879
+ return ImageTools.flip(ir, axis);
1880
+ };
1881
+
1882
+ var crop = function (ir, x, y, w, h) {
1883
+ return ImageTools.crop(ir, x, y, w, h);
1884
+ };
1885
+
1886
+ var resize = function (ir, w, h) {
1887
+ return ImageTools.resize(ir, w, h);
1888
+ };
1889
+
1890
+ var rotate = function (ir, angle) {
1891
+ return ImageTools.rotate(ir, angle);
1892
+ };
1893
+
1894
+ return {
1895
+ invert: invert,
1896
+ sharpen: sharpen,
1897
+ emboss: emboss,
1898
+ brightness: brightness,
1899
+ hue: hue,
1900
+ saturate: saturate,
1901
+ contrast: contrast,
1902
+ grayscale: grayscale,
1903
+ sepia: sepia,
1904
+ colorize: colorize,
1905
+ gamma: gamma,
1906
+ exposure: exposure,
1907
+
1908
+ flip: flip,
1909
+ crop: crop,
1910
+ resize: resize,
1911
+ rotate: rotate
1912
+ };
1913
+ }
1914
+ );
1915
+ define(
1916
+ 'ephox.imagetools.api.ResultConversions',
1917
+
1918
+ [
1919
+ 'ephox.imagetools.util.ImageResult'
1920
+ ],
1921
+
1922
+ function (ImageResult) {
1923
+
1924
+ var blobToImageResult = function (blob) {
1925
+ return ImageResult.fromBlob(blob);
1926
+ };
1927
+
1928
+ var fromBlobAndUrlSync = function (blob, uri) {
1929
+ // we have no reason to doubt the uri is valid
1930
+ return ImageResult.fromBlobAndUrlSync(blob, uri);
1931
+ };
1932
+
1933
+ var imageToImageResult = function (image) {
1934
+ return ImageResult.fromImage(image);
1935
+
1936
+ };
1937
+
1938
+ var imageResultToBlob = function (ir, type, quality) {
1939
+ // Shortcut to not lose the blob filename when we aren't editing the image
1940
+ if (type === undefined && quality === undefined) {
1941
+ return imageResultToOriginalBlob(ir);
1942
+ } else {
1943
+ return ir.toAdjustedBlob(type, quality);
1944
+ }
1945
+ };
1946
+
1947
+ var imageResultToOriginalBlob = function (ir) {
1948
+ return ir.toBlob();
1949
+ };
1950
+
1951
+ var imageResultToDataURL = function (ir) {
1952
+ return ir.toDataURL();
1953
+ };
1954
+
1955
+ return {
1956
+ // used outside
1957
+ blobToImageResult: blobToImageResult,
1958
+ fromBlobAndUrlSync: fromBlobAndUrlSync,
1959
+ imageToImageResult: imageToImageResult,
1960
+ imageResultToBlob: imageResultToBlob,
1961
+ imageResultToOriginalBlob: imageResultToOriginalBlob,
1962
+ imageResultToDataURL: imageResultToDataURL
1963
+ };
1964
+ }
1965
+ );
1966
+
1967
+ define(
1968
+ 'ephox.sand.api.URL',
1969
+
1970
+ [
1971
+ 'ephox.sand.util.Global'
1972
+ ],
1973
+
1974
+ function (Global) {
1975
+ /*
1976
+ * IE10 and above per
1977
+ * https://developer.mozilla.org/en-US/docs/Web/API/URL.createObjectURL
1978
+ *
1979
+ * Also Safari 6.1+
1980
+ * Safari 6.0 has 'webkitURL' instead, but doesn't support flexbox so we
1981
+ * aren't supporting it anyway
1982
+ */
1983
+ var url = function () {
1984
+ return Global.getOrDie('URL');
1985
+ };
1986
+
1987
+ var createObjectURL = function (blob) {
1988
+ return url().createObjectURL(blob);
1989
+ };
1990
+
1991
+ var revokeObjectURL = function (u) {
1992
+ url().revokeObjectURL(u);
1993
+ };
1994
+
1995
+ return {
1996
+ createObjectURL: createObjectURL,
1997
+ revokeObjectURL: revokeObjectURL
1998
+ };
1999
+ }
2000
+ );
2001
+ defineGlobal("global!clearTimeout", clearTimeout);
2002
+ /**
2003
+ * ResolveGlobal.js
2004
+ *
2005
+ * Released under LGPL License.
2006
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2007
+ *
2008
+ * License: http://www.tinymce.com/license
2009
+ * Contributing: http://www.tinymce.com/contributing
2010
+ */
2011
+
2012
+ define(
2013
+ 'tinymce.core.util.Delay',
2014
+ [
2015
+ 'global!tinymce.util.Tools.resolve'
2016
+ ],
2017
+ function (resolve) {
2018
+ return resolve('tinymce.util.Delay');
2019
+ }
2020
+ );
2021
+
2022
+ /**
2023
+ * ResolveGlobal.js
2024
+ *
2025
+ * Released under LGPL License.
2026
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2027
+ *
2028
+ * License: http://www.tinymce.com/license
2029
+ * Contributing: http://www.tinymce.com/contributing
2030
+ */
2031
+
2032
+ define(
2033
+ 'tinymce.core.util.Promise',
2034
+ [
2035
+ 'global!tinymce.util.Tools.resolve'
2036
+ ],
2037
+ function (resolve) {
2038
+ return resolve('tinymce.util.Promise');
2039
+ }
2040
+ );
2041
+
2042
+ /**
2043
+ * ResolveGlobal.js
2044
+ *
2045
+ * Released under LGPL License.
2046
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2047
+ *
2048
+ * License: http://www.tinymce.com/license
2049
+ * Contributing: http://www.tinymce.com/contributing
2050
+ */
2051
+
2052
+ define(
2053
+ 'tinymce.core.util.URI',
2054
+ [
2055
+ 'global!tinymce.util.Tools.resolve'
2056
+ ],
2057
+ function (resolve) {
2058
+ return resolve('tinymce.util.URI');
2059
+ }
2060
+ );
2061
+
2062
+ /**
2063
+ * Settings.js
2064
+ *
2065
+ * Released under LGPL License.
2066
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2067
+ *
2068
+ * License: http://www.tinymce.com/license
2069
+ * Contributing: http://www.tinymce.com/contributing
2070
+ */
2071
+
2072
+ define(
2073
+ 'tinymce.plugins.imagetools.api.Settings',
2074
+ [
2075
+ ],
2076
+ function () {
2077
+ var getToolbarItems = function (editor) {
2078
+ return editor.getParam('imagetools_toolbar', 'rotateleft rotateright | flipv fliph | crop editimage imageoptions');
2079
+ };
2080
+
2081
+ var getProxyUrl = function (editor) {
2082
+ return editor.getParam('imagetools_proxy');
2083
+ };
2084
+
2085
+ return {
2086
+ getToolbarItems: getToolbarItems,
2087
+ getProxyUrl: getProxyUrl
2088
+ };
2089
+ }
2090
+ );
2091
+
2092
+ /**
2093
+ * ImageSize.js
2094
+ *
2095
+ * Released under LGPL License.
2096
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2097
+ *
2098
+ * License: http://www.tinymce.com/license
2099
+ * Contributing: http://www.tinymce.com/contributing
2100
+ */
2101
+
2102
+ define(
2103
+ 'tinymce.plugins.imagetools.core.ImageSize',
2104
+ [
2105
+ ],
2106
+ function () {
2107
+ function getImageSize(img) {
2108
+ var width, height;
2109
+
2110
+ function isPxValue(value) {
2111
+ return /^[0-9\.]+px$/.test(value);
2112
+ }
2113
+
2114
+ width = img.style.width;
2115
+ height = img.style.height;
2116
+ if (width || height) {
2117
+ if (isPxValue(width) && isPxValue(height)) {
2118
+ return {
2119
+ w: parseInt(width, 10),
2120
+ h: parseInt(height, 10)
2121
+ };
2122
+ }
2123
+
2124
+ return null;
2125
+ }
2126
+
2127
+ width = img.width;
2128
+ height = img.height;
2129
+
2130
+ if (width && height) {
2131
+ return {
2132
+ w: parseInt(width, 10),
2133
+ h: parseInt(height, 10)
2134
+ };
2135
+ }
2136
+
2137
+ return null;
2138
+ }
2139
+
2140
+ function setImageSize(img, size) {
2141
+ var width, height;
2142
+
2143
+ if (size) {
2144
+ width = img.style.width;
2145
+ height = img.style.height;
2146
+
2147
+ if (width || height) {
2148
+ img.style.width = size.w + 'px';
2149
+ img.style.height = size.h + 'px';
2150
+ img.removeAttribute('data-mce-style');
2151
+ }
2152
+
2153
+ width = img.width;
2154
+ height = img.height;
2155
+
2156
+ if (width || height) {
2157
+ img.setAttribute('width', size.w);
2158
+ img.setAttribute('height', size.h);
2159
+ }
2160
+ }
2161
+ }
2162
+
2163
+ function getNaturalImageSize(img) {
2164
+ return {
2165
+ w: img.naturalWidth,
2166
+ h: img.naturalHeight
2167
+ };
2168
+ }
2169
+
2170
+ return {
2171
+ getImageSize: getImageSize,
2172
+ setImageSize: setImageSize,
2173
+ getNaturalImageSize: getNaturalImageSize
2174
+ };
2175
+ }
2176
+ );
2177
+
2178
+ defineGlobal("global!String", String);
2179
+ define(
2180
+ 'ephox.katamari.api.Arr',
2181
+
2182
+ [
2183
+ 'ephox.katamari.api.Option',
2184
+ 'global!Array',
2185
+ 'global!Error',
2186
+ 'global!String'
2187
+ ],
2188
+
2189
+ function (Option, Array, Error, String) {
2190
+ // Use the native Array.indexOf if it is available (IE9+) otherwise fall back to manual iteration
2191
+ // https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf
2192
+ var rawIndexOf = (function () {
2193
+ var pIndexOf = Array.prototype.indexOf;
2194
+
2195
+ var fastIndex = function (xs, x) { return pIndexOf.call(xs, x); };
2196
+
2197
+ var slowIndex = function(xs, x) { return slowIndexOf(xs, x); };
2198
+
2199
+ return pIndexOf === undefined ? slowIndex : fastIndex;
2200
+ })();
2201
+
2202
+ var indexOf = function (xs, x) {
2203
+ // The rawIndexOf method does not wrap up in an option. This is for performance reasons.
2204
+ var r = rawIndexOf(xs, x);
2205
+ return r === -1 ? Option.none() : Option.some(r);
2206
+ };
2207
+
2208
+ var contains = function (xs, x) {
2209
+ return rawIndexOf(xs, x) > -1;
2210
+ };
2211
+
2212
+ // Using findIndex is likely less optimal in Chrome (dynamic return type instead of bool)
2213
+ // but if we need that micro-optimisation we can inline it later.
2214
+ var exists = function (xs, pred) {
2215
+ return findIndex(xs, pred).isSome();
2216
+ };
2217
+
2218
+ var range = function (num, f) {
2219
+ var r = [];
2220
+ for (var i = 0; i < num; i++) {
2221
+ r.push(f(i));
2222
+ }
2223
+ return r;
2224
+ };
2225
+
2226
+ // It's a total micro optimisation, but these do make some difference.
2227
+ // Particularly for browsers other than Chrome.
2228
+ // - length caching
2229
+ // http://jsperf.com/browser-diet-jquery-each-vs-for-loop/69
2230
+ // - not using push
2231
+ // http://jsperf.com/array-direct-assignment-vs-push/2
2232
+
2233
+ var chunk = function (array, size) {
2234
+ var r = [];
2235
+ for (var i = 0; i < array.length; i += size) {
2236
+ var s = array.slice(i, i + size);
2237
+ r.push(s);
2238
+ }
2239
+ return r;
2240
+ };
2241
+
2242
+ var map = function(xs, f) {
2243
+ // pre-allocating array size when it's guaranteed to be known
2244
+ // http://jsperf.com/push-allocated-vs-dynamic/22
2245
+ var len = xs.length;
2246
+ var r = new Array(len);
2247
+ for (var i = 0; i < len; i++) {
2248
+ var x = xs[i];
2249
+ r[i] = f(x, i, xs);
2250
+ }
2251
+ return r;
2252
+ };
2253
+
2254
+ // Unwound implementing other functions in terms of each.
2255
+ // The code size is roughly the same, and it should allow for better optimisation.
2256
+ var each = function(xs, f) {
2257
+ for (var i = 0, len = xs.length; i < len; i++) {
2258
+ var x = xs[i];
2259
+ f(x, i, xs);
2260
+ }
2261
+ };
2262
+
2263
+ var eachr = function (xs, f) {
2264
+ for (var i = xs.length - 1; i >= 0; i--) {
2265
+ var x = xs[i];
2266
+ f(x, i, xs);
2267
+ }
2268
+ };
2269
+
2270
+ var partition = function(xs, pred) {
2271
+ var pass = [];
2272
+ var fail = [];
2273
+ for (var i = 0, len = xs.length; i < len; i++) {
2274
+ var x = xs[i];
2275
+ var arr = pred(x, i, xs) ? pass : fail;
2276
+ arr.push(x);
2277
+ }
2278
+ return { pass: pass, fail: fail };
2279
+ };
2280
+
2281
+ var filter = function(xs, pred) {
2282
+ var r = [];
2283
+ for (var i = 0, len = xs.length; i < len; i++) {
2284
+ var x = xs[i];
2285
+ if (pred(x, i, xs)) {
2286
+ r.push(x);
2287
+ }
2288
+ }
2289
+ return r;
2290
+ };
2291
+
2292
+ /*
2293
+ * Groups an array into contiguous arrays of like elements. Whether an element is like or not depends on f.
2294
+ *
2295
+ * f is a function that derives a value from an element - e.g. true or false, or a string.
2296
+ * Elements are like if this function generates the same value for them (according to ===).
2297
+ *
2298
+ *
2299
+ * Order of the elements is preserved. Arr.flatten() on the result will return the original list, as with Haskell groupBy function.
2300
+ * For a good explanation, see the group function (which is a special case of groupBy)
2301
+ * http://hackage.haskell.org/package/base-4.7.0.0/docs/Data-List.html#v:group
2302
+ */
2303
+ var groupBy = function (xs, f) {
2304
+ if (xs.length === 0) {
2305
+ return [];
2306
+ } else {
2307
+ var wasType = f(xs[0]); // initial case for matching
2308
+ var r = [];
2309
+ var group = [];
2310
+
2311
+ for (var i = 0, len = xs.length; i < len; i++) {
2312
+ var x = xs[i];
2313
+ var type = f(x);
2314
+ if (type !== wasType) {
2315
+ r.push(group);
2316
+ group = [];
2317
+ }
2318
+ wasType = type;
2319
+ group.push(x);
2320
+ }
2321
+ if (group.length !== 0) {
2322
+ r.push(group);
2323
+ }
2324
+ return r;
2325
+ }
2326
+ };
2327
+
2328
+ var foldr = function (xs, f, acc) {
2329
+ eachr(xs, function (x) {
2330
+ acc = f(acc, x);
2331
+ });
2332
+ return acc;
2333
+ };
2334
+
2335
+ var foldl = function (xs, f, acc) {
2336
+ each(xs, function (x) {
2337
+ acc = f(acc, x);
2338
+ });
2339
+ return acc;
2340
+ };
2341
+
2342
+ var find = function (xs, pred) {
2343
+ for (var i = 0, len = xs.length; i < len; i++) {
2344
+ var x = xs[i];
2345
+ if (pred(x, i, xs)) {
2346
+ return Option.some(x);
2347
+ }
2348
+ }
2349
+ return Option.none();
2350
+ };
2351
+
2352
+ var findIndex = function (xs, pred) {
2353
+ for (var i = 0, len = xs.length; i < len; i++) {
2354
+ var x = xs[i];
2355
+ if (pred(x, i, xs)) {
2356
+ return Option.some(i);
2357
+ }
2358
+ }
2359
+
2360
+ return Option.none();
2361
+ };
2362
+
2363
+ var slowIndexOf = function (xs, x) {
2364
+ for (var i = 0, len = xs.length; i < len; ++i) {
2365
+ if (xs[i] === x) {
2366
+ return i;
2367
+ }
2368
+ }
2369
+
2370
+ return -1;
2371
+ };
2372
+
2373
+ var push = Array.prototype.push;
2374
+ var flatten = function (xs) {
2375
+ // Note, this is possible because push supports multiple arguments:
2376
+ // http://jsperf.com/concat-push/6
2377
+ // Note that in the past, concat() would silently work (very slowly) for array-like objects.
2378
+ // With this change it will throw an error.
2379
+ var r = [];
2380
+ for (var i = 0, len = xs.length; i < len; ++i) {
2381
+ // Ensure that each value is an array itself
2382
+ if (! Array.prototype.isPrototypeOf(xs[i])) throw new Error('Arr.flatten item ' + i + ' was not an array, input: ' + xs);
2383
+ push.apply(r, xs[i]);
2384
+ }
2385
+ return r;
2386
+ };
2387
+
2388
+ var bind = function (xs, f) {
2389
+ var output = map(xs, f);
2390
+ return flatten(output);
2391
+ };
2392
+
2393
+ var forall = function (xs, pred) {
2394
+ for (var i = 0, len = xs.length; i < len; ++i) {
2395
+ var x = xs[i];
2396
+ if (pred(x, i, xs) !== true) {
2397
+ return false;
2398
+ }
2399
+ }
2400
+ return true;
2401
+ };
2402
+
2403
+ var equal = function (a1, a2) {
2404
+ return a1.length === a2.length && forall(a1, function (x, i) {
2405
+ return x === a2[i];
2406
+ });
2407
+ };
2408
+
2409
+ var slice = Array.prototype.slice;
2410
+ var reverse = function (xs) {
2411
+ var r = slice.call(xs, 0);
2412
+ r.reverse();
2413
+ return r;
2414
+ };
2415
+
2416
+ var difference = function (a1, a2) {
2417
+ return filter(a1, function (x) {
2418
+ return !contains(a2, x);
2419
+ });
2420
+ };
2421
+
2422
+ var mapToObject = function(xs, f) {
2423
+ var r = {};
2424
+ for (var i = 0, len = xs.length; i < len; i++) {
2425
+ var x = xs[i];
2426
+ r[String(x)] = f(x, i);
2427
+ }
2428
+ return r;
2429
+ };
2430
+
2431
+ var pure = function(x) {
2432
+ return [x];
2433
+ };
2434
+
2435
+ var sort = function (xs, comparator) {
2436
+ var copy = slice.call(xs, 0);
2437
+ copy.sort(comparator);
2438
+ return copy;
2439
+ };
2440
+
2441
+ var head = function (xs) {
2442
+ return xs.length === 0 ? Option.none() : Option.some(xs[0]);
2443
+ };
2444
+
2445
+ var last = function (xs) {
2446
+ return xs.length === 0 ? Option.none() : Option.some(xs[xs.length - 1]);
2447
+ };
2448
+
2449
+ return {
2450
+ map: map,
2451
+ each: each,
2452
+ eachr: eachr,
2453
+ partition: partition,
2454
+ filter: filter,
2455
+ groupBy: groupBy,
2456
+ indexOf: indexOf,
2457
+ foldr: foldr,
2458
+ foldl: foldl,
2459
+ find: find,
2460
+ findIndex: findIndex,
2461
+ flatten: flatten,
2462
+ bind: bind,
2463
+ forall: forall,
2464
+ exists: exists,
2465
+ contains: contains,
2466
+ equal: equal,
2467
+ reverse: reverse,
2468
+ chunk: chunk,
2469
+ difference: difference,
2470
+ mapToObject: mapToObject,
2471
+ pure: pure,
2472
+ sort: sort,
2473
+ range: range,
2474
+ head: head,
2475
+ last: last
2476
+ };
2477
+ }
2478
+ );
2479
+ define(
2480
+ 'ephox.sand.api.XMLHttpRequest',
2481
+
2482
+ [
2483
+ 'ephox.sand.util.Global'
2484
+ ],
2485
+
2486
+ function (Global) {
2487
+ /*
2488
+ * IE8 and above per
2489
+ * https://developer.mozilla.org/en/docs/XMLHttpRequest
2490
+ */
2491
+ return function () {
2492
+ var f = Global.getOrDie('XMLHttpRequest');
2493
+ return new f();
2494
+ };
2495
+ }
2496
+ );
2497
+ /**
2498
+ * Utils.js
2499
+ *
2500
+ * Released under LGPL License.
2501
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2502
+ *
2503
+ * License: http://www.tinymce.com/license
2504
+ * Contributing: http://www.tinymce.com/contributing
2505
+ */
2506
+
2507
+ define(
2508
+ 'tinymce.plugins.imagetools.core.Utils',
2509
+ [
2510
+ 'ephox.sand.api.FileReader',
2511
+ 'ephox.sand.api.XMLHttpRequest',
2512
+ 'tinymce.core.util.Promise',
2513
+ 'tinymce.core.util.Tools'
2514
+ ],
2515
+ function (FileReader, XMLHttpRequest, Promise, Tools) {
2516
+ var isValue = function (obj) {
2517
+ return obj !== null && obj !== undefined;
2518
+ };
2519
+
2520
+ var traverse = function (json, path) {
2521
+ var value;
2522
+
2523
+ value = path.reduce(function (result, key) {
2524
+ return isValue(result) ? result[key] : undefined;
2525
+ }, json);
2526
+
2527
+ return isValue(value) ? value : null;
2528
+ };
2529
+
2530
+ var requestUrlAsBlob = function (url, headers) {
2531
+ return new Promise(function (resolve) {
2532
+ var xhr;
2533
+
2534
+ xhr = new XMLHttpRequest();
2535
+
2536
+ xhr.onreadystatechange = function () {
2537
+ if (xhr.readyState === 4) {
2538
+ resolve({
2539
+ status: xhr.status,
2540
+ blob: this.response
2541
+ });
2542
+ }
2543
+ };
2544
+
2545
+ xhr.open('GET', url, true);
2546
+
2547
+ Tools.each(headers, function (value, key) {
2548
+ xhr.setRequestHeader(key, value);
2549
+ });
2550
+
2551
+ xhr.responseType = 'blob';
2552
+ xhr.send();
2553
+ });
2554
+ };
2555
+
2556
+ var readBlob = function (blob) {
2557
+ return new Promise(function (resolve) {
2558
+ var fr = new FileReader();
2559
+
2560
+ fr.onload = function (e) {
2561
+ var data = e.target;
2562
+ resolve(data.result);
2563
+ };
2564
+
2565
+ fr.readAsText(blob);
2566
+ });
2567
+ };
2568
+
2569
+ var parseJson = function (text) {
2570
+ var json;
2571
+
2572
+ try {
2573
+ json = JSON.parse(text);
2574
+ } catch (ex) {
2575
+ // Ignore
2576
+ }
2577
+
2578
+ return json;
2579
+ };
2580
+
2581
+ return {
2582
+ traverse: traverse,
2583
+ readBlob: readBlob,
2584
+ requestUrlAsBlob: requestUrlAsBlob,
2585
+ parseJson: parseJson
2586
+ };
2587
+ }
2588
+ );
2589
+
2590
+ define(
2591
+ 'tinymce.plugins.imagetools.core.Errors',
2592
+
2593
+ [
2594
+ 'ephox.katamari.api.Arr',
2595
+ 'ephox.katamari.api.Fun',
2596
+ 'tinymce.core.util.Promise',
2597
+ 'tinymce.plugins.imagetools.core.Utils'
2598
+ ],
2599
+
2600
+ function (Arr, Fun, Promise, Utils) {
2601
+ var friendlyHttpErrors = [
2602
+ { code: 404, message: 'Could not find Image Proxy' },
2603
+ { code: 403, message: 'Rejected request' },
2604
+ { code: 0, message: 'Incorrect Image Proxy URL' }
2605
+ ];
2606
+ var friendlyServiceErrors = [
2607
+ { type: 'key_missing', message: 'The request did not include an api key.' },
2608
+ { type: 'key_not_found', message: 'The provided api key could not be found.' },
2609
+ { type: 'domain_not_trusted', message: 'The api key is not valid for the request origins.' }
2610
+ ];
2611
+
2612
+ var isServiceErrorCode = function (code) {
2613
+ return code === 400 || code === 403 || code === 500;
2614
+ };
2615
+
2616
+ var getHttpErrorMsg = function (status) {
2617
+ var message = Arr.find(friendlyHttpErrors, function (error) {
2618
+ return status === error.code;
2619
+ }).fold(
2620
+ Fun.constant('Unknown ImageProxy error'),
2621
+ function (error) {
2622
+ return error.message;
2623
+ }
2624
+ );
2625
+
2626
+ return "ImageProxy HTTP error: " + message;
2627
+ };
2628
+
2629
+ var handleHttpError = function (status) {
2630
+ var message = getHttpErrorMsg(status);
2631
+
2632
+ return Promise.reject(message);
2633
+ };
2634
+
2635
+ var getServiceErrorMsg = function (type) {
2636
+ return Arr.find(friendlyServiceErrors, function (error) {
2637
+ return error.type === type;
2638
+ }).fold(
2639
+ Fun.constant('Unknown service error'),
2640
+ function (error) {
2641
+ return error.message;
2642
+ }
2643
+ );
2644
+ };
2645
+
2646
+ var getServiceError = function (text) {
2647
+ var serviceError = Utils.parseJson(text);
2648
+ var errorType = Utils.traverse(serviceError, ['error', 'type']);
2649
+ var errorMsg = errorType ? getServiceErrorMsg(errorType) : 'Invalid JSON in service error message';
2650
+
2651
+ return "ImageProxy Service error: " + errorMsg;
2652
+ };
2653
+
2654
+ var handleServiceError = function (status, blob) {
2655
+ return Utils.readBlob(blob).then(function (text) {
2656
+ var serviceError = getServiceError(text);
2657
+
2658
+ return Promise.reject(serviceError);
2659
+ });
2660
+ };
2661
+
2662
+ var handleServiceErrorResponse = function (status, blob) {
2663
+ return isServiceErrorCode(status) ? handleServiceError(status, blob) : handleHttpError(status);
2664
+ };
2665
+
2666
+ return {
2667
+ handleServiceErrorResponse: handleServiceErrorResponse,
2668
+ handleHttpError: handleHttpError,
2669
+ getHttpErrorMsg: getHttpErrorMsg,
2670
+ getServiceErrorMsg: getServiceErrorMsg
2671
+ };
2672
+ }
2673
+ );
2674
+
2675
+ /**
2676
+ * Proxy.js
2677
+ *
2678
+ * Released under LGPL License.
2679
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2680
+ *
2681
+ * License: http://www.tinymce.com/license
2682
+ * Contributing: http://www.tinymce.com/contributing
2683
+ */
2684
+
2685
+ /**
2686
+ * Handles loading images though a proxy for working around cors.
2687
+ */
2688
+ define(
2689
+ 'tinymce.plugins.imagetools.core.Proxy',
2690
+ [
2691
+ 'tinymce.core.util.Promise',
2692
+ 'tinymce.core.util.Tools',
2693
+ 'tinymce.plugins.imagetools.core.Errors',
2694
+ 'tinymce.plugins.imagetools.core.Utils'
2695
+ ],
2696
+ function (Promise, Tools, Errors, Utils) {
2697
+ var appendApiKey = function (url, apiKey) {
2698
+ var separator = url.indexOf('?') === -1 ? '?' : '&';
2699
+ if (/[?&]apiKey=/.test(url) || !apiKey) {
2700
+ return url;
2701
+ } else {
2702
+ return url + separator + 'apiKey=' + encodeURIComponent(apiKey);
2703
+ }
2704
+ };
2705
+
2706
+ var requestServiceBlob = function (url, apiKey) {
2707
+ return Utils.requestUrlAsBlob(appendApiKey(url, apiKey), {
2708
+ 'Content-Type': 'application/json;charset=UTF-8',
2709
+ 'tiny-api-key': apiKey
2710
+ }).then(function (result) {
2711
+ return result.status < 200 || result.status >= 300 ? Errors.handleServiceErrorResponse(result.status, result.blob) : Promise.resolve(result.blob);
2712
+ });
2713
+ };
2714
+
2715
+ function requestBlob(url) {
2716
+ return Utils.requestUrlAsBlob(url, {})
2717
+ .then(function (result) {
2718
+ return result.status < 200 || result.status >= 300 ? Errors.handleHttpError(result.status) : Promise.resolve(result.blob);
2719
+ });
2720
+ }
2721
+
2722
+ var getUrl = function (url, apiKey) {
2723
+ return apiKey ? requestServiceBlob(url, apiKey) : requestBlob(url);
2724
+ };
2725
+
2726
+ return {
2727
+ getUrl: getUrl
2728
+ };
2729
+ }
2730
+ );
2731
+
2732
+ defineGlobal("global!setTimeout", setTimeout);
2733
+ /**
2734
+ * ResolveGlobal.js
2735
+ *
2736
+ * Released under LGPL License.
2737
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2738
+ *
2739
+ * License: http://www.tinymce.com/license
2740
+ * Contributing: http://www.tinymce.com/contributing
2741
+ */
2742
+
2743
+ define(
2744
+ 'tinymce.core.dom.DOMUtils',
2745
+ [
2746
+ 'global!tinymce.util.Tools.resolve'
2747
+ ],
2748
+ function (resolve) {
2749
+ return resolve('tinymce.dom.DOMUtils');
2750
+ }
2751
+ );
2752
+
2753
+ /**
2754
+ * ResolveGlobal.js
2755
+ *
2756
+ * Released under LGPL License.
2757
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2758
+ *
2759
+ * License: http://www.tinymce.com/license
2760
+ * Contributing: http://www.tinymce.com/contributing
2761
+ */
2762
+
2763
+ define(
2764
+ 'tinymce.core.ui.Factory',
2765
+ [
2766
+ 'global!tinymce.util.Tools.resolve'
2767
+ ],
2768
+ function (resolve) {
2769
+ return resolve('tinymce.ui.Factory');
2770
+ }
2771
+ );
2772
+
2773
+ /**
2774
+ * UndoStack.js
2775
+ *
2776
+ * Released under LGPL License.
2777
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2778
+ *
2779
+ * License: http://www.tinymce.com/license
2780
+ * Contributing: http://www.tinymce.com/contributing
2781
+ */
2782
+
2783
+ define(
2784
+ 'tinymce.plugins.imagetools.core.UndoStack',
2785
+ [
2786
+ ],
2787
+ function () {
2788
+ return function () {
2789
+ var data = [], index = -1;
2790
+
2791
+ function add(state) {
2792
+ var removed;
2793
+
2794
+ removed = data.splice(++index);
2795
+ data.push(state);
2796
+
2797
+ return {
2798
+ state: state,
2799
+ removed: removed
2800
+ };
2801
+ }
2802
+
2803
+ function undo() {
2804
+ if (canUndo()) {
2805
+ return data[--index];
2806
+ }
2807
+ }
2808
+
2809
+ function redo() {
2810
+ if (canRedo()) {
2811
+ return data[++index];
2812
+ }
2813
+ }
2814
+
2815
+ function canUndo() {
2816
+ return index > 0;
2817
+ }
2818
+
2819
+ function canRedo() {
2820
+ return index !== -1 && index < data.length - 1;
2821
+ }
2822
+
2823
+ return {
2824
+ data: data,
2825
+ add: add,
2826
+ undo: undo,
2827
+ redo: redo,
2828
+ canUndo: canUndo,
2829
+ canRedo: canRedo
2830
+ };
2831
+ };
2832
+ }
2833
+ );
2834
+
2835
+ defineGlobal("global!document", document);
2836
+ defineGlobal("global!Image", Image);
2837
+ /**
2838
+ * ResolveGlobal.js
2839
+ *
2840
+ * Released under LGPL License.
2841
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2842
+ *
2843
+ * License: http://www.tinymce.com/license
2844
+ * Contributing: http://www.tinymce.com/contributing
2845
+ */
2846
+
2847
+ define(
2848
+ 'tinymce.core.geom.Rect',
2849
+ [
2850
+ 'global!tinymce.util.Tools.resolve'
2851
+ ],
2852
+ function (resolve) {
2853
+ return resolve('tinymce.geom.Rect');
2854
+ }
2855
+ );
2856
+
2857
+ /**
2858
+ * LoadImage.js
2859
+ *
2860
+ * Released under LGPL License.
2861
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2862
+ *
2863
+ * License: http://www.tinymce.com/license
2864
+ * Contributing: http://www.tinymce.com/contributing
2865
+ */
2866
+
2867
+ define(
2868
+ 'tinymce.plugins.imagetools.core.LoadImage',
2869
+ [
2870
+ 'tinymce.core.util.Promise'
2871
+ ],
2872
+ function (Promise) {
2873
+ var loadImage = function (image) {
2874
+ return new Promise(function (resolve) {
2875
+ var loaded = function () {
2876
+ image.removeEventListener('load', loaded);
2877
+ resolve(image);
2878
+ };
2879
+
2880
+ if (image.complete) {
2881
+ resolve(image);
2882
+ } else {
2883
+ image.addEventListener('load', loaded);
2884
+ }
2885
+ });
2886
+ };
2887
+
2888
+ return {
2889
+ loadImage: loadImage
2890
+ };
2891
+ }
2892
+ );
2893
+
2894
+ /**
2895
+ * ResolveGlobal.js
2896
+ *
2897
+ * Released under LGPL License.
2898
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2899
+ *
2900
+ * License: http://www.tinymce.com/license
2901
+ * Contributing: http://www.tinymce.com/contributing
2902
+ */
2903
+
2904
+ define(
2905
+ 'tinymce.core.dom.DomQuery',
2906
+ [
2907
+ 'global!tinymce.util.Tools.resolve'
2908
+ ],
2909
+ function (resolve) {
2910
+ return resolve('tinymce.dom.DomQuery');
2911
+ }
2912
+ );
2913
+
2914
+ /**
2915
+ * ResolveGlobal.js
2916
+ *
2917
+ * Released under LGPL License.
2918
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2919
+ *
2920
+ * License: http://www.tinymce.com/license
2921
+ * Contributing: http://www.tinymce.com/contributing
2922
+ */
2923
+
2924
+ define(
2925
+ 'tinymce.core.util.Observable',
2926
+ [
2927
+ 'global!tinymce.util.Tools.resolve'
2928
+ ],
2929
+ function (resolve) {
2930
+ return resolve('tinymce.util.Observable');
2931
+ }
2932
+ );
2933
+
2934
+ /**
2935
+ * ResolveGlobal.js
2936
+ *
2937
+ * Released under LGPL License.
2938
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2939
+ *
2940
+ * License: http://www.tinymce.com/license
2941
+ * Contributing: http://www.tinymce.com/contributing
2942
+ */
2943
+
2944
+ define(
2945
+ 'tinymce.core.util.VK',
2946
+ [
2947
+ 'global!tinymce.util.Tools.resolve'
2948
+ ],
2949
+ function (resolve) {
2950
+ return resolve('tinymce.util.VK');
2951
+ }
2952
+ );
2953
+
2954
+ /**
2955
+ * CropRect.js
2956
+ *
2957
+ * Released under LGPL License.
2958
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
2959
+ *
2960
+ * License: http://www.tinymce.com/license
2961
+ * Contributing: http://www.tinymce.com/contributing
2962
+ */
2963
+
2964
+ define(
2965
+ 'tinymce.plugins.imagetools.ui.CropRect',
2966
+ [
2967
+ 'tinymce.core.dom.DomQuery',
2968
+ 'tinymce.core.geom.Rect',
2969
+ 'tinymce.core.ui.Factory',
2970
+ 'tinymce.core.util.Observable',
2971
+ 'tinymce.core.util.Tools',
2972
+ 'tinymce.core.util.VK'
2973
+ ],
2974
+ function (DomQuery, Rect, Factory, Observable, Tools, VK) {
2975
+ var count = 0;
2976
+
2977
+ return function (currentRect, viewPortRect, clampRect, containerElm, action) {
2978
+ var instance, handles, dragHelpers, blockers, prefix = 'mce-', id = prefix + 'crid-' + (count++);
2979
+
2980
+ handles = [
2981
+ { name: 'move', xMul: 0, yMul: 0, deltaX: 1, deltaY: 1, deltaW: 0, deltaH: 0, label: 'Crop Mask' },
2982
+ { name: 'nw', xMul: 0, yMul: 0, deltaX: 1, deltaY: 1, deltaW: -1, deltaH: -1, label: 'Top Left Crop Handle' },
2983
+ { name: 'ne', xMul: 1, yMul: 0, deltaX: 0, deltaY: 1, deltaW: 1, deltaH: -1, label: 'Top Right Crop Handle' },
2984
+ { name: 'sw', xMul: 0, yMul: 1, deltaX: 1, deltaY: 0, deltaW: -1, deltaH: 1, label: 'Bottom Left Crop Handle' },
2985
+ { name: 'se', xMul: 1, yMul: 1, deltaX: 0, deltaY: 0, deltaW: 1, deltaH: 1, label: 'Bottom Right Crop Handle' }
2986
+ ];
2987
+
2988
+ blockers = ["top", "right", "bottom", "left"];
2989
+
2990
+ function getAbsoluteRect(outerRect, relativeRect) {
2991
+ return {
2992
+ x: relativeRect.x + outerRect.x,
2993
+ y: relativeRect.y + outerRect.y,
2994
+ w: relativeRect.w,
2995
+ h: relativeRect.h
2996
+ };
2997
+ }
2998
+
2999
+ function getRelativeRect(outerRect, innerRect) {
3000
+ return {
3001
+ x: innerRect.x - outerRect.x,
3002
+ y: innerRect.y - outerRect.y,
3003
+ w: innerRect.w,
3004
+ h: innerRect.h
3005
+ };
3006
+ }
3007
+
3008
+ function getInnerRect() {
3009
+ return getRelativeRect(clampRect, currentRect);
3010
+ }
3011
+
3012
+ function moveRect(handle, startRect, deltaX, deltaY) {
3013
+ var x, y, w, h, rect;
3014
+
3015
+ x = startRect.x;
3016
+ y = startRect.y;
3017
+ w = startRect.w;
3018
+ h = startRect.h;
3019
+
3020
+ x += deltaX * handle.deltaX;
3021
+ y += deltaY * handle.deltaY;
3022
+ w += deltaX * handle.deltaW;
3023
+ h += deltaY * handle.deltaH;
3024
+
3025
+ if (w < 20) {
3026
+ w = 20;
3027
+ }
3028
+
3029
+ if (h < 20) {
3030
+ h = 20;
3031
+ }
3032
+
3033
+ rect = currentRect = Rect.clamp({ x: x, y: y, w: w, h: h }, clampRect, handle.name === 'move');
3034
+ rect = getRelativeRect(clampRect, rect);
3035
+
3036
+ instance.fire('updateRect', { rect: rect });
3037
+ setInnerRect(rect);
3038
+ }
3039
+
3040
+ function render() {
3041
+ function createDragHelper(handle) {
3042
+ var startRect;
3043
+ var DragHelper = Factory.get('DragHelper');
3044
+
3045
+ return new DragHelper(id, {
3046
+ document: containerElm.ownerDocument,
3047
+ handle: id + '-' + handle.name,
3048
+
3049
+ start: function () {
3050
+ startRect = currentRect;
3051
+ },
3052
+
3053
+ drag: function (e) {
3054
+ moveRect(handle, startRect, e.deltaX, e.deltaY);
3055
+ }
3056
+ });
3057
+ }
3058
+
3059
+ DomQuery(
3060
+ '<div id="' + id + '" class="' + prefix + 'croprect-container"' +
3061
+ ' role="grid" aria-dropeffect="execute">'
3062
+ ).appendTo(containerElm);
3063
+
3064
+ Tools.each(blockers, function (blocker) {
3065
+ DomQuery('#' + id, containerElm).append(
3066
+ '<div id="' + id + '-' + blocker + '"class="' + prefix + 'croprect-block" style="display: none" data-mce-bogus="all">'
3067
+ );
3068
+ });
3069
+
3070
+ Tools.each(handles, function (handle) {
3071
+ DomQuery('#' + id, containerElm).append(
3072
+ '<div id="' + id + '-' + handle.name + '" class="' + prefix +
3073
+ 'croprect-handle ' + prefix + 'croprect-handle-' + handle.name + '"' +
3074
+ 'style="display: none" data-mce-bogus="all" role="gridcell" tabindex="-1"' +
3075
+ ' aria-label="' + handle.label + '" aria-grabbed="false">'
3076
+ );
3077
+ });
3078
+
3079
+ dragHelpers = Tools.map(handles, createDragHelper);
3080
+
3081
+ repaint(currentRect);
3082
+
3083
+ DomQuery(containerElm).on('focusin focusout', function (e) {
3084
+ DomQuery(e.target).attr('aria-grabbed', e.type === 'focus');
3085
+ });
3086
+
3087
+ DomQuery(containerElm).on('keydown', function (e) {
3088
+ var activeHandle;
3089
+
3090
+ Tools.each(handles, function (handle) {
3091
+ if (e.target.id === id + '-' + handle.name) {
3092
+ activeHandle = handle;
3093
+ return false;
3094
+ }
3095
+ });
3096
+
3097
+ function moveAndBlock(evt, handle, startRect, deltaX, deltaY) {
3098
+ evt.stopPropagation();
3099
+ evt.preventDefault();
3100
+
3101
+ moveRect(activeHandle, startRect, deltaX, deltaY);
3102
+ }
3103
+
3104
+ switch (e.keyCode) {
3105
+ case VK.LEFT:
3106
+ moveAndBlock(e, activeHandle, currentRect, -10, 0);
3107
+ break;
3108
+
3109
+ case VK.RIGHT:
3110
+ moveAndBlock(e, activeHandle, currentRect, 10, 0);
3111
+ break;
3112
+
3113
+ case VK.UP:
3114
+ moveAndBlock(e, activeHandle, currentRect, 0, -10);
3115
+ break;
3116
+
3117
+ case VK.DOWN:
3118
+ moveAndBlock(e, activeHandle, currentRect, 0, 10);
3119
+ break;
3120
+
3121
+ case VK.ENTER:
3122
+ case VK.SPACEBAR:
3123
+ e.preventDefault();
3124
+ action();
3125
+ break;
3126
+ }
3127
+ });
3128
+ }
3129
+
3130
+ function toggleVisibility(state) {
3131
+ var selectors;
3132
+
3133
+ selectors = Tools.map(handles, function (handle) {
3134
+ return '#' + id + '-' + handle.name;
3135
+ }).concat(Tools.map(blockers, function (blocker) {
3136
+ return '#' + id + '-' + blocker;
3137
+ })).join(',');
3138
+
3139
+ if (state) {
3140
+ DomQuery(selectors, containerElm).show();
3141
+ } else {
3142
+ DomQuery(selectors, containerElm).hide();
3143
+ }
3144
+ }
3145
+
3146
+ function repaint(rect) {
3147
+ function updateElementRect(name, rect) {
3148
+ if (rect.h < 0) {
3149
+ rect.h = 0;
3150
+ }
3151
+
3152
+ if (rect.w < 0) {
3153
+ rect.w = 0;
3154
+ }
3155
+
3156
+ DomQuery('#' + id + '-' + name, containerElm).css({
3157
+ left: rect.x,
3158
+ top: rect.y,
3159
+ width: rect.w,
3160
+ height: rect.h
3161
+ });
3162
+ }
3163
+
3164
+ Tools.each(handles, function (handle) {
3165
+ DomQuery('#' + id + '-' + handle.name, containerElm).css({
3166
+ left: rect.w * handle.xMul + rect.x,
3167
+ top: rect.h * handle.yMul + rect.y
3168
+ });
3169
+ });
3170
+
3171
+ updateElementRect('top', { x: viewPortRect.x, y: viewPortRect.y, w: viewPortRect.w, h: rect.y - viewPortRect.y });
3172
+ updateElementRect('right', { x: rect.x + rect.w, y: rect.y, w: viewPortRect.w - rect.x - rect.w + viewPortRect.x, h: rect.h });
3173
+ updateElementRect('bottom', {
3174
+ x: viewPortRect.x,
3175
+ y: rect.y + rect.h,
3176
+ w: viewPortRect.w,
3177
+ h: viewPortRect.h - rect.y - rect.h + viewPortRect.y
3178
+ });
3179
+ updateElementRect('left', { x: viewPortRect.x, y: rect.y, w: rect.x - viewPortRect.x, h: rect.h });
3180
+ updateElementRect('move', rect);
3181
+ }
3182
+
3183
+ function setRect(rect) {
3184
+ currentRect = rect;
3185
+ repaint(currentRect);
3186
+ }
3187
+
3188
+ function setViewPortRect(rect) {
3189
+ viewPortRect = rect;
3190
+ repaint(currentRect);
3191
+ }
3192
+
3193
+ function setInnerRect(rect) {
3194
+ setRect(getAbsoluteRect(clampRect, rect));
3195
+ }
3196
+
3197
+ function setClampRect(rect) {
3198
+ clampRect = rect;
3199
+ repaint(currentRect);
3200
+ }
3201
+
3202
+ function destroy() {
3203
+ Tools.each(dragHelpers, function (helper) {
3204
+ helper.destroy();
3205
+ });
3206
+
3207
+ dragHelpers = [];
3208
+ }
3209
+
3210
+ render(containerElm);
3211
+
3212
+ instance = Tools.extend({
3213
+ toggleVisibility: toggleVisibility,
3214
+ setClampRect: setClampRect,
3215
+ setRect: setRect,
3216
+ getInnerRect: getInnerRect,
3217
+ setInnerRect: setInnerRect,
3218
+ setViewPortRect: setViewPortRect,
3219
+ destroy: destroy
3220
+ }, Observable);
3221
+
3222
+ return instance;
3223
+ };
3224
+ }
3225
+ );
3226
+
3227
+ /**
3228
+ * ImagePanel.js
3229
+ *
3230
+ * Released under LGPL License.
3231
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
3232
+ *
3233
+ * License: http://www.tinymce.com/license
3234
+ * Contributing: http://www.tinymce.com/contributing
3235
+ */
3236
+
3237
+ define(
3238
+ 'tinymce.plugins.imagetools.ui.ImagePanel',
3239
+ [
3240
+ 'global!document',
3241
+ 'global!Image',
3242
+ 'tinymce.core.geom.Rect',
3243
+ 'tinymce.core.ui.Factory',
3244
+ 'tinymce.core.util.Promise',
3245
+ 'tinymce.core.util.Tools',
3246
+ 'tinymce.plugins.imagetools.core.LoadImage',
3247
+ 'tinymce.plugins.imagetools.ui.CropRect'
3248
+ ],
3249
+ function (document, Image, Rect, Factory, Promise, Tools, LoadImage, CropRect) {
3250
+ var create = function (settings) {
3251
+ var Control = Factory.get('Control');
3252
+ var ImagePanel = Control.extend({
3253
+ Defaults: {
3254
+ classes: "imagepanel"
3255
+ },
3256
+
3257
+ selection: function (rect) {
3258
+ if (arguments.length) {
3259
+ this.state.set('rect', rect);
3260
+ return this;
3261
+ }
3262
+
3263
+ return this.state.get('rect');
3264
+ },
3265
+
3266
+ imageSize: function () {
3267
+ var viewRect = this.state.get('viewRect');
3268
+
3269
+ return {
3270
+ w: viewRect.w,
3271
+ h: viewRect.h
3272
+ };
3273
+ },
3274
+
3275
+ toggleCropRect: function (state) {
3276
+ this.state.set('cropEnabled', state);
3277
+ },
3278
+
3279
+ imageSrc: function (url) {
3280
+ var self = this, img = new Image();
3281
+
3282
+ img.src = url;
3283
+
3284
+ LoadImage.loadImage(img).then(function () {
3285
+ var rect, $img, lastRect = self.state.get('viewRect');
3286
+
3287
+ $img = self.$el.find('img');
3288
+ if ($img[0]) {
3289
+ $img.replaceWith(img);
3290
+ } else {
3291
+ var bg = document.createElement('div');
3292
+ bg.className = 'mce-imagepanel-bg';
3293
+ self.getEl().appendChild(bg);
3294
+ self.getEl().appendChild(img);
3295
+ }
3296
+
3297
+ rect = { x: 0, y: 0, w: img.naturalWidth, h: img.naturalHeight };
3298
+ self.state.set('viewRect', rect);
3299
+ self.state.set('rect', Rect.inflate(rect, -20, -20));
3300
+
3301
+ if (!lastRect || lastRect.w !== rect.w || lastRect.h !== rect.h) {
3302
+ self.zoomFit();
3303
+ }
3304
+
3305
+ self.repaintImage();
3306
+ self.fire('load');
3307
+ });
3308
+ },
3309
+
3310
+ zoom: function (value) {
3311
+ if (arguments.length) {
3312
+ this.state.set('zoom', value);
3313
+ return this;
3314
+ }
3315
+
3316
+ return this.state.get('zoom');
3317
+ },
3318
+
3319
+ postRender: function () {
3320
+ this.imageSrc(this.settings.imageSrc);
3321
+ return this._super();
3322
+ },
3323
+
3324
+ zoomFit: function () {
3325
+ var self = this, $img, pw, ph, w, h, zoom, padding;
3326
+
3327
+ padding = 10;
3328
+ $img = self.$el.find('img');
3329
+ pw = self.getEl().clientWidth;
3330
+ ph = self.getEl().clientHeight;
3331
+ w = $img[0].naturalWidth;
3332
+ h = $img[0].naturalHeight;
3333
+ zoom = Math.min((pw - padding) / w, (ph - padding) / h);
3334
+
3335
+ if (zoom >= 1) {
3336
+ zoom = 1;
3337
+ }
3338
+
3339
+ self.zoom(zoom);
3340
+ },
3341
+
3342
+ repaintImage: function () {
3343
+ var x, y, w, h, pw, ph, $img, $bg, zoom, rect, elm;
3344
+
3345
+ elm = this.getEl();
3346
+ zoom = this.zoom();
3347
+ rect = this.state.get('rect');
3348
+ $img = this.$el.find('img');
3349
+ $bg = this.$el.find('.mce-imagepanel-bg');
3350
+ pw = elm.offsetWidth;
3351
+ ph = elm.offsetHeight;
3352
+ w = $img[0].naturalWidth * zoom;
3353
+ h = $img[0].naturalHeight * zoom;
3354
+ x = Math.max(0, pw / 2 - w / 2);
3355
+ y = Math.max(0, ph / 2 - h / 2);
3356
+
3357
+ $img.css({
3358
+ left: x,
3359
+ top: y,
3360
+ width: w,
3361
+ height: h
3362
+ });
3363
+
3364
+ $bg.css({
3365
+ left: x,
3366
+ top: y,
3367
+ width: w,
3368
+ height: h
3369
+ });
3370
+
3371
+ if (this.cropRect) {
3372
+ this.cropRect.setRect({
3373
+ x: rect.x * zoom + x,
3374
+ y: rect.y * zoom + y,
3375
+ w: rect.w * zoom,
3376
+ h: rect.h * zoom
3377
+ });
3378
+
3379
+ this.cropRect.setClampRect({
3380
+ x: x,
3381
+ y: y,
3382
+ w: w,
3383
+ h: h
3384
+ });
3385
+
3386
+ this.cropRect.setViewPortRect({
3387
+ x: 0,
3388
+ y: 0,
3389
+ w: pw,
3390
+ h: ph
3391
+ });
3392
+ }
3393
+ },
3394
+
3395
+ bindStates: function () {
3396
+ var self = this;
3397
+
3398
+ function setupCropRect(rect) {
3399
+ self.cropRect = new CropRect(
3400
+ rect,
3401
+ self.state.get('viewRect'),
3402
+ self.state.get('viewRect'),
3403
+ self.getEl(),
3404
+ function () {
3405
+ self.fire('crop');
3406
+ }
3407
+ );
3408
+
3409
+ self.cropRect.on('updateRect', function (e) {
3410
+ var rect = e.rect, zoom = self.zoom();
3411
+
3412
+ rect = {
3413
+ x: Math.round(rect.x / zoom),
3414
+ y: Math.round(rect.y / zoom),
3415
+ w: Math.round(rect.w / zoom),
3416
+ h: Math.round(rect.h / zoom)
3417
+ };
3418
+
3419
+ self.state.set('rect', rect);
3420
+ });
3421
+
3422
+ self.on('remove', self.cropRect.destroy);
3423
+ }
3424
+
3425
+ self.state.on('change:cropEnabled', function (e) {
3426
+ self.cropRect.toggleVisibility(e.value);
3427
+ self.repaintImage();
3428
+ });
3429
+
3430
+ self.state.on('change:zoom', function () {
3431
+ self.repaintImage();
3432
+ });
3433
+
3434
+ self.state.on('change:rect', function (e) {
3435
+ var rect = e.value;
3436
+
3437
+ if (!self.cropRect) {
3438
+ setupCropRect(rect);
3439
+ }
3440
+
3441
+ self.cropRect.setRect(rect);
3442
+ });
3443
+ }
3444
+ });
3445
+
3446
+ return new ImagePanel(settings);
3447
+ };
3448
+
3449
+ return {
3450
+ create: create
3451
+ };
3452
+ }
3453
+ );
3454
+
3455
+ /**
3456
+ * Dialog.js
3457
+ *
3458
+ * Released under LGPL License.
3459
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
3460
+ *
3461
+ * License: http://www.tinymce.com/license
3462
+ * Contributing: http://www.tinymce.com/contributing
3463
+ */
3464
+
3465
+ define(
3466
+ 'tinymce.plugins.imagetools.ui.Dialog',
3467
+ [
3468
+ 'ephox.imagetools.api.ImageTransformations',
3469
+ 'ephox.imagetools.api.ResultConversions',
3470
+ 'ephox.sand.api.URL',
3471
+ 'global!Math',
3472
+ 'global!setTimeout',
3473
+ 'tinymce.core.dom.DOMUtils',
3474
+ 'tinymce.core.ui.Factory',
3475
+ 'tinymce.core.util.Promise',
3476
+ 'tinymce.core.util.Tools',
3477
+ 'tinymce.plugins.imagetools.core.UndoStack',
3478
+ 'tinymce.plugins.imagetools.ui.ImagePanel'
3479
+ ],
3480
+ function (ImageTransformations, ResultConversions, URL, Math, setTimeout, DOMUtils, Factory, Promise, Tools, UndoStack, ImagePanel) {
3481
+ function createState(blob) {
3482
+ return {
3483
+ blob: blob,
3484
+ url: URL.createObjectURL(blob)
3485
+ };
3486
+ }
3487
+
3488
+ function destroyState(state) {
3489
+ if (state) {
3490
+ URL.revokeObjectURL(state.url);
3491
+ }
3492
+ }
3493
+
3494
+ function destroyStates(states) {
3495
+ Tools.each(states, destroyState);
3496
+ }
3497
+
3498
+ function open(editor, currentState, resolve, reject) {
3499
+ var win, undoStack = new UndoStack(), mainPanel, filtersPanel, tempState,
3500
+ cropPanel, resizePanel, flipRotatePanel, imagePanel, sidePanel, mainViewContainer,
3501
+ invertPanel, brightnessPanel, huePanel, saturatePanel, contrastPanel, grayscalePanel,
3502
+ sepiaPanel, colorizePanel, sharpenPanel, embossPanel, gammaPanel, exposurePanel, panels,
3503
+ width, height, ratioW, ratioH;
3504
+
3505
+ function recalcSize(e) {
3506
+ var widthCtrl, heightCtrl, newWidth, newHeight;
3507
+
3508
+ widthCtrl = win.find('#w')[0];
3509
+ heightCtrl = win.find('#h')[0];
3510
+
3511
+ newWidth = parseInt(widthCtrl.value(), 10);
3512
+ newHeight = parseInt(heightCtrl.value(), 10);
3513
+
3514
+ if (win.find('#constrain')[0].checked() && width && height && newWidth && newHeight) {
3515
+ if (e.control.settings.name === 'w') {
3516
+ newHeight = Math.round(newWidth * ratioW);
3517
+ heightCtrl.value(newHeight);
3518
+ } else {
3519
+ newWidth = Math.round(newHeight * ratioH);
3520
+ widthCtrl.value(newWidth);
3521
+ }
3522
+ }
3523
+
3524
+ width = newWidth;
3525
+ height = newHeight;
3526
+ }
3527
+
3528
+ function floatToPercent(value) {
3529
+ return Math.round(value * 100) + '%';
3530
+ }
3531
+
3532
+ function updateButtonUndoStates() {
3533
+ win.find('#undo').disabled(!undoStack.canUndo());
3534
+ win.find('#redo').disabled(!undoStack.canRedo());
3535
+ win.statusbar.find('#save').disabled(!undoStack.canUndo());
3536
+ }
3537
+
3538
+ function disableUndoRedo() {
3539
+ win.find('#undo').disabled(true);
3540
+ win.find('#redo').disabled(true);
3541
+ }
3542
+
3543
+ function displayState(state) {
3544
+ if (state) {
3545
+ imagePanel.imageSrc(state.url);
3546
+ }
3547
+ }
3548
+
3549
+ function switchPanel(targetPanel) {
3550
+ return function () {
3551
+ var hidePanels = Tools.grep(panels, function (panel) {
3552
+ return panel.settings.name !== targetPanel;
3553
+ });
3554
+
3555
+ Tools.each(hidePanels, function (panel) {
3556
+ panel.hide();
3557
+ });
3558
+
3559
+ targetPanel.show();
3560
+ targetPanel.focus();
3561
+ };
3562
+ }
3563
+
3564
+ function addTempState(blob) {
3565
+ tempState = createState(blob);
3566
+ displayState(tempState);
3567
+ }
3568
+
3569
+ function addBlobState(blob) {
3570
+ currentState = createState(blob);
3571
+ displayState(currentState);
3572
+ destroyStates(undoStack.add(currentState).removed);
3573
+ updateButtonUndoStates();
3574
+ }
3575
+
3576
+ function crop() {
3577
+ var rect = imagePanel.selection();
3578
+
3579
+ ResultConversions.blobToImageResult(currentState.blob).
3580
+ then(function (ir) {
3581
+ ImageTransformations.crop(ir, rect.x, rect.y, rect.w, rect.h).
3582
+ then(imageResultToBlob).
3583
+ then(function (blob) {
3584
+ addBlobState(blob);
3585
+ cancel();
3586
+ });
3587
+ });
3588
+ }
3589
+
3590
+ function tempAction(fn) {
3591
+ var args = [].slice.call(arguments, 1);
3592
+
3593
+ return function () {
3594
+ var state = tempState || currentState;
3595
+
3596
+ ResultConversions.blobToImageResult(state.blob).
3597
+ then(function (ir) {
3598
+ fn.apply(this, [ir].concat(args)).then(imageResultToBlob).then(addTempState);
3599
+ });
3600
+ };
3601
+ }
3602
+
3603
+ function action(fn) {
3604
+ var args = [].slice.call(arguments, 1);
3605
+
3606
+ return function () {
3607
+ ResultConversions.blobToImageResult(currentState.blob).
3608
+ then(function (ir) {
3609
+ fn.apply(this, [ir].concat(args)).then(imageResultToBlob).then(addBlobState);
3610
+ });
3611
+ };
3612
+ }
3613
+
3614
+ function cancel() {
3615
+ displayState(currentState);
3616
+ destroyState(tempState);
3617
+ switchPanel(mainPanel)();
3618
+ updateButtonUndoStates();
3619
+ }
3620
+
3621
+ function waitForTempState(times, applyCall) {
3622
+ if (tempState) {
3623
+ applyCall();
3624
+ } else {
3625
+ setTimeout(function () {
3626
+ if (times-- > 0) {
3627
+ waitForTempState(times, applyCall);
3628
+ } else {
3629
+ editor.windowManager.alert('Error: failed to apply image operation.');
3630
+ }
3631
+ }, 10);
3632
+ }
3633
+ }
3634
+
3635
+ function applyTempState() {
3636
+ if (tempState) {
3637
+ addBlobState(tempState.blob);
3638
+ cancel();
3639
+ } else {
3640
+ waitForTempState(100, applyTempState);
3641
+ }
3642
+ }
3643
+
3644
+ function zoomIn() {
3645
+ var zoom = imagePanel.zoom();
3646
+
3647
+ if (zoom < 2) {
3648
+ zoom += 0.1;
3649
+ }
3650
+
3651
+ imagePanel.zoom(zoom);
3652
+ }
3653
+
3654
+ function zoomOut() {
3655
+ var zoom = imagePanel.zoom();
3656
+
3657
+ if (zoom > 0.1) {
3658
+ zoom -= 0.1;
3659
+ }
3660
+
3661
+ imagePanel.zoom(zoom);
3662
+ }
3663
+
3664
+ function undo() {
3665
+ currentState = undoStack.undo();
3666
+ displayState(currentState);
3667
+ updateButtonUndoStates();
3668
+ }
3669
+
3670
+ function redo() {
3671
+ currentState = undoStack.redo();
3672
+ displayState(currentState);
3673
+ updateButtonUndoStates();
3674
+ }
3675
+
3676
+ function save() {
3677
+ resolve(currentState.blob);
3678
+ win.close();
3679
+ }
3680
+
3681
+ function createPanel(items) {
3682
+ return Factory.create('Form', {
3683
+ layout: 'flex',
3684
+ direction: 'row',
3685
+ labelGap: 5,
3686
+ border: '0 0 1 0',
3687
+ align: 'center',
3688
+ pack: 'center',
3689
+ padding: '0 10 0 10',
3690
+ spacing: 5,
3691
+ flex: 0,
3692
+ minHeight: 60,
3693
+ defaults: {
3694
+ classes: 'imagetool',
3695
+ type: 'button'
3696
+ },
3697
+ items: items
3698
+ });
3699
+ }
3700
+
3701
+ var imageResultToBlob = function (ir) {
3702
+ return ir.toBlob();
3703
+ };
3704
+
3705
+ function createFilterPanel(title, filter) {
3706
+ return createPanel([
3707
+ { text: 'Back', onclick: cancel },
3708
+ { type: 'spacer', flex: 1 },
3709
+ { text: 'Apply', subtype: 'primary', onclick: applyTempState }
3710
+ ]).hide().on('show', function () {
3711
+ disableUndoRedo();
3712
+
3713
+ ResultConversions.blobToImageResult(currentState.blob).
3714
+ then(function (ir) {
3715
+ return filter(ir);
3716
+ }).
3717
+ then(imageResultToBlob).
3718
+ then(function (blob) {
3719
+ var newTempState = createState(blob);
3720
+
3721
+ displayState(newTempState);
3722
+ destroyState(tempState);
3723
+ tempState = newTempState;
3724
+ });
3725
+ });
3726
+ }
3727
+
3728
+ function createVariableFilterPanel(title, filter, value, min, max) {
3729
+ function update(value) {
3730
+ ResultConversions.blobToImageResult(currentState.blob).
3731
+ then(function (ir) {
3732
+ return filter(ir, value);
3733
+ }).
3734
+ then(imageResultToBlob).
3735
+ then(function (blob) {
3736
+ var newTempState = createState(blob);
3737
+ displayState(newTempState);
3738
+ destroyState(tempState);
3739
+ tempState = newTempState;
3740
+ });
3741
+ }
3742
+
3743
+ return createPanel([
3744
+ { text: 'Back', onclick: cancel },
3745
+ { type: 'spacer', flex: 1 },
3746
+ {
3747
+ type: 'slider',
3748
+ flex: 1,
3749
+ ondragend: function (e) {
3750
+ update(e.value);
3751
+ },
3752
+ minValue: min,
3753
+ maxValue: max,
3754
+ value: value,
3755
+ previewFilter: floatToPercent
3756
+ },
3757
+ { type: 'spacer', flex: 1 },
3758
+ { text: 'Apply', subtype: 'primary', onclick: applyTempState }
3759
+ ]).hide().on('show', function () {
3760
+ this.find('slider').value(value);
3761
+ disableUndoRedo();
3762
+ });
3763
+ }
3764
+
3765
+ function createRgbFilterPanel(title, filter) {
3766
+ function update() {
3767
+ var r, g, b;
3768
+
3769
+ r = win.find('#r')[0].value();
3770
+ g = win.find('#g')[0].value();
3771
+ b = win.find('#b')[0].value();
3772
+
3773
+ ResultConversions.blobToImageResult(currentState.blob).
3774
+ then(function (ir) {
3775
+ return filter(ir, r, g, b);
3776
+ }).
3777
+ then(imageResultToBlob).
3778
+ then(function (blob) {
3779
+ var newTempState = createState(blob);
3780
+ displayState(newTempState);
3781
+ destroyState(tempState);
3782
+ tempState = newTempState;
3783
+ });
3784
+ }
3785
+
3786
+ return createPanel([
3787
+ { text: 'Back', onclick: cancel },
3788
+ { type: 'spacer', flex: 1 },
3789
+ {
3790
+ type: 'slider', label: 'R', name: 'r', minValue: 0,
3791
+ value: 1, maxValue: 2, ondragend: update, previewFilter: floatToPercent
3792
+ },
3793
+ {
3794
+ type: 'slider', label: 'G', name: 'g', minValue: 0,
3795
+ value: 1, maxValue: 2, ondragend: update, previewFilter: floatToPercent
3796
+ },
3797
+ {
3798
+ type: 'slider', label: 'B', name: 'b', minValue: 0,
3799
+ value: 1, maxValue: 2, ondragend: update, previewFilter: floatToPercent
3800
+ },
3801
+ { type: 'spacer', flex: 1 },
3802
+ { text: 'Apply', subtype: 'primary', onclick: applyTempState }
3803
+ ]).hide().on('show', function () {
3804
+ win.find('#r,#g,#b').value(1);
3805
+ disableUndoRedo();
3806
+ });
3807
+ }
3808
+
3809
+ cropPanel = createPanel([
3810
+ { text: 'Back', onclick: cancel },
3811
+ { type: 'spacer', flex: 1 },
3812
+ { text: 'Apply', subtype: 'primary', onclick: crop }
3813
+ ]).hide().on('show hide', function (e) {
3814
+ imagePanel.toggleCropRect(e.type === 'show');
3815
+ }).on('show', disableUndoRedo);
3816
+
3817
+ function toggleConstrain(e) {
3818
+ if (e.control.value() === true) {
3819
+ ratioW = height / width;
3820
+ ratioH = width / height;
3821
+ }
3822
+ }
3823
+
3824
+ resizePanel = createPanel([
3825
+ { text: 'Back', onclick: cancel },
3826
+ { type: 'spacer', flex: 1 },
3827
+ { type: 'textbox', name: 'w', label: 'Width', size: 4, onkeyup: recalcSize },
3828
+ { type: 'textbox', name: 'h', label: 'Height', size: 4, onkeyup: recalcSize },
3829
+ { type: 'checkbox', name: 'constrain', text: 'Constrain proportions', checked: true, onchange: toggleConstrain },
3830
+ { type: 'spacer', flex: 1 },
3831
+ { text: 'Apply', subtype: 'primary', onclick: 'submit' }
3832
+ ]).hide().on('submit', function (e) {
3833
+ var width = parseInt(win.find('#w').value(), 10),
3834
+ height = parseInt(win.find('#h').value(), 10);
3835
+
3836
+ e.preventDefault();
3837
+
3838
+ action(ImageTransformations.resize, width, height)();
3839
+ cancel();
3840
+ }).on('show', disableUndoRedo);
3841
+
3842
+ flipRotatePanel = createPanel([
3843
+ { text: 'Back', onclick: cancel },
3844
+ { type: 'spacer', flex: 1 },
3845
+ { icon: 'fliph', tooltip: 'Flip horizontally', onclick: tempAction(ImageTransformations.flip, 'h') },
3846
+ { icon: 'flipv', tooltip: 'Flip vertically', onclick: tempAction(ImageTransformations.flip, 'v') },
3847
+ { icon: 'rotateleft', tooltip: 'Rotate counterclockwise', onclick: tempAction(ImageTransformations.rotate, -90) },
3848
+ { icon: 'rotateright', tooltip: 'Rotate clockwise', onclick: tempAction(ImageTransformations.rotate, 90) },
3849
+ { type: 'spacer', flex: 1 },
3850
+ { text: 'Apply', subtype: 'primary', onclick: applyTempState }
3851
+ ]).hide().on('show', disableUndoRedo);
3852
+
3853
+ invertPanel = createFilterPanel("Invert", ImageTransformations.invert);
3854
+ sharpenPanel = createFilterPanel("Sharpen", ImageTransformations.sharpen);
3855
+ embossPanel = createFilterPanel("Emboss", ImageTransformations.emboss);
3856
+
3857
+ brightnessPanel = createVariableFilterPanel("Brightness", ImageTransformations.brightness, 0, -1, 1);
3858
+ huePanel = createVariableFilterPanel("Hue", ImageTransformations.hue, 180, 0, 360);
3859
+ saturatePanel = createVariableFilterPanel("Saturate", ImageTransformations.saturate, 0, -1, 1);
3860
+ contrastPanel = createVariableFilterPanel("Contrast", ImageTransformations.contrast, 0, -1, 1);
3861
+ grayscalePanel = createVariableFilterPanel("Grayscale", ImageTransformations.grayscale, 0, 0, 1);
3862
+ sepiaPanel = createVariableFilterPanel("Sepia", ImageTransformations.sepia, 0, 0, 1);
3863
+ colorizePanel = createRgbFilterPanel("Colorize", ImageTransformations.colorize);
3864
+ gammaPanel = createVariableFilterPanel("Gamma", ImageTransformations.gamma, 0, -1, 1);
3865
+ exposurePanel = createVariableFilterPanel("Exposure", ImageTransformations.exposure, 1, 0, 2);
3866
+
3867
+ filtersPanel = createPanel([
3868
+ { text: 'Back', onclick: cancel },
3869
+ { type: 'spacer', flex: 1 },
3870
+ { text: 'hue', icon: 'hue', onclick: switchPanel(huePanel) },
3871
+ { text: 'saturate', icon: 'saturate', onclick: switchPanel(saturatePanel) },
3872
+ { text: 'sepia', icon: 'sepia', onclick: switchPanel(sepiaPanel) },
3873
+ { text: 'emboss', icon: 'emboss', onclick: switchPanel(embossPanel) },
3874
+ { text: 'exposure', icon: 'exposure', onclick: switchPanel(exposurePanel) },
3875
+ { type: 'spacer', flex: 1 }
3876
+ ]).hide();
3877
+
3878
+ mainPanel = createPanel([
3879
+ { tooltip: 'Crop', icon: 'crop', onclick: switchPanel(cropPanel) },
3880
+ { tooltip: 'Resize', icon: 'resize2', onclick: switchPanel(resizePanel) },
3881
+ { tooltip: 'Orientation', icon: 'orientation', onclick: switchPanel(flipRotatePanel) },
3882
+ { tooltip: 'Brightness', icon: 'sun', onclick: switchPanel(brightnessPanel) },
3883
+ { tooltip: 'Sharpen', icon: 'sharpen', onclick: switchPanel(sharpenPanel) },
3884
+ { tooltip: 'Contrast', icon: 'contrast', onclick: switchPanel(contrastPanel) },
3885
+ { tooltip: 'Color levels', icon: 'drop', onclick: switchPanel(colorizePanel) },
3886
+ { tooltip: 'Gamma', icon: 'gamma', onclick: switchPanel(gammaPanel) },
3887
+ { tooltip: 'Invert', icon: 'invert', onclick: switchPanel(invertPanel) }
3888
+ //{text: 'More', onclick: switchPanel(filtersPanel)}
3889
+ ]);
3890
+
3891
+ imagePanel = ImagePanel.create({
3892
+ flex: 1,
3893
+ imageSrc: currentState.url
3894
+ });
3895
+
3896
+ sidePanel = Factory.create('Container', {
3897
+ layout: 'flex',
3898
+ direction: 'column',
3899
+ border: '0 1 0 0',
3900
+ padding: 5,
3901
+ spacing: 5,
3902
+ items: [
3903
+ { type: 'button', icon: 'undo', tooltip: 'Undo', name: 'undo', onclick: undo },
3904
+ { type: 'button', icon: 'redo', tooltip: 'Redo', name: 'redo', onclick: redo },
3905
+ { type: 'button', icon: 'zoomin', tooltip: 'Zoom in', onclick: zoomIn },
3906
+ { type: 'button', icon: 'zoomout', tooltip: 'Zoom out', onclick: zoomOut }
3907
+ ]
3908
+ });
3909
+
3910
+ mainViewContainer = Factory.create('Container', {
3911
+ type: 'container',
3912
+ layout: 'flex',
3913
+ direction: 'row',
3914
+ align: 'stretch',
3915
+ flex: 1,
3916
+ items: [sidePanel, imagePanel]
3917
+ });
3918
+
3919
+ panels = [
3920
+ mainPanel,
3921
+ cropPanel,
3922
+ resizePanel,
3923
+ flipRotatePanel,
3924
+ filtersPanel,
3925
+ invertPanel,
3926
+ brightnessPanel,
3927
+ huePanel,
3928
+ saturatePanel,
3929
+ contrastPanel,
3930
+ grayscalePanel,
3931
+ sepiaPanel,
3932
+ colorizePanel,
3933
+ sharpenPanel,
3934
+ embossPanel,
3935
+ gammaPanel,
3936
+ exposurePanel
3937
+ ];
3938
+
3939
+ win = editor.windowManager.open({
3940
+ layout: 'flex',
3941
+ direction: 'column',
3942
+ align: 'stretch',
3943
+ minWidth: Math.min(DOMUtils.DOM.getViewPort().w, 800),
3944
+ minHeight: Math.min(DOMUtils.DOM.getViewPort().h, 650),
3945
+ title: 'Edit image',
3946
+ items: panels.concat([mainViewContainer]),
3947
+ buttons: [
3948
+ { text: 'Save', name: 'save', subtype: 'primary', onclick: save },
3949
+ { text: 'Cancel', onclick: 'close' }
3950
+ ]
3951
+ });
3952
+
3953
+ win.on('close', function () {
3954
+ reject();
3955
+ destroyStates(undoStack.data);
3956
+ undoStack = null;
3957
+ tempState = null;
3958
+ });
3959
+
3960
+ undoStack.add(currentState);
3961
+ updateButtonUndoStates();
3962
+
3963
+ imagePanel.on('load', function () {
3964
+ width = imagePanel.imageSize().w;
3965
+ height = imagePanel.imageSize().h;
3966
+ ratioW = height / width;
3967
+ ratioH = width / height;
3968
+
3969
+ win.find('#w').value(width);
3970
+ win.find('#h').value(height);
3971
+ });
3972
+
3973
+ imagePanel.on('crop', crop);
3974
+ }
3975
+
3976
+ function edit(editor, imageResult) {
3977
+ return new Promise(function (resolve, reject) {
3978
+ return imageResult.toBlob().then(function (blob) {
3979
+ open(editor, createState(blob), resolve, reject);
3980
+ });
3981
+ });
3982
+ }
3983
+
3984
+ //edit('img/dogleft.jpg');
3985
+
3986
+ return {
3987
+ edit: edit
3988
+ };
3989
+ }
3990
+ );
3991
+
3992
+ /**
3993
+ * Actions.js
3994
+ *
3995
+ * Released under LGPL License.
3996
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
3997
+ *
3998
+ * License: http://www.tinymce.com/license
3999
+ * Contributing: http://www.tinymce.com/contributing
4000
+ */
4001
+
4002
+ define(
4003
+ 'tinymce.plugins.imagetools.core.Actions',
4004
+ [
4005
+ 'ephox.imagetools.api.BlobConversions',
4006
+ 'ephox.imagetools.api.ImageTransformations',
4007
+ 'ephox.imagetools.api.ResultConversions',
4008
+ 'ephox.katamari.api.Fun',
4009
+ 'ephox.sand.api.URL',
4010
+ 'global!clearTimeout',
4011
+ 'tinymce.core.util.Delay',
4012
+ 'tinymce.core.util.Promise',
4013
+ 'tinymce.core.util.Tools',
4014
+ 'tinymce.core.util.URI',
4015
+ 'tinymce.plugins.imagetools.api.Settings',
4016
+ 'tinymce.plugins.imagetools.core.ImageSize',
4017
+ 'tinymce.plugins.imagetools.core.Proxy',
4018
+ 'tinymce.plugins.imagetools.ui.Dialog'
4019
+ ],
4020
+ function (BlobConversions, ImageTransformations, ResultConversions, Fun, URL, clearTimeout, Delay, Promise, Tools, URI, Settings, ImageSize, Proxy, Dialog) {
4021
+ var count = 0;
4022
+
4023
+ var isEditableImage = function (editor, img) {
4024
+ var selectorMatched = editor.dom.is(img, 'img:not([data-mce-object],[data-mce-placeholder])');
4025
+
4026
+ return selectorMatched && (isLocalImage(editor, img) || isCorsImage(editor, img) || editor.settings.imagetools_proxy);
4027
+ };
4028
+
4029
+ var displayError = function (editor, error) {
4030
+ editor.notificationManager.open({
4031
+ text: error,
4032
+ type: 'error'
4033
+ });
4034
+ };
4035
+
4036
+ var getSelectedImage = function (editor) {
4037
+ return editor.selection.getNode();
4038
+ };
4039
+
4040
+ var extractFilename = function (editor, url) {
4041
+ var m = url.match(/\/([^\/\?]+)?\.(?:jpeg|jpg|png|gif)(?:\?|$)/i);
4042
+ if (m) {
4043
+ return editor.dom.encode(m[1]);
4044
+ }
4045
+ return null;
4046
+ };
4047
+
4048
+ var createId = function () {
4049
+ return 'imagetools' + count++;
4050
+ };
4051
+
4052
+ var isLocalImage = function (editor, img) {
4053
+ var url = img.src;
4054
+
4055
+ return url.indexOf('data:') === 0 || url.indexOf('blob:') === 0 || new URI(url).host === editor.documentBaseURI.host;
4056
+ };
4057
+
4058
+ var isCorsImage = function (editor, img) {
4059
+ return Tools.inArray(editor.settings.imagetools_cors_hosts, new URI(img.src).host) !== -1;
4060
+ };
4061
+
4062
+ var getApiKey = function (editor) {
4063
+ return editor.settings.api_key || editor.settings.imagetools_api_key;
4064
+ };
4065
+
4066
+ var imageToBlob = function (editor, img) {
4067
+ var src = img.src, apiKey;
4068
+
4069
+ if (isCorsImage(editor, img)) {
4070
+ return Proxy.getUrl(img.src, null);
4071
+ }
4072
+
4073
+ if (!isLocalImage(editor, img)) {
4074
+ src = Settings.getProxyUrl(editor);
4075
+ src += (src.indexOf('?') === -1 ? '?' : '&') + 'url=' + encodeURIComponent(img.src);
4076
+ apiKey = getApiKey(editor);
4077
+ return Proxy.getUrl(src, apiKey);
4078
+ }
4079
+
4080
+ return BlobConversions.imageToBlob(img);
4081
+ };
4082
+
4083
+ var findSelectedBlob = function (editor) {
4084
+ var blobInfo;
4085
+ blobInfo = editor.editorUpload.blobCache.getByUri(getSelectedImage(editor).src);
4086
+ if (blobInfo) {
4087
+ return Promise.resolve(blobInfo.blob());
4088
+ }
4089
+
4090
+ return imageToBlob(editor, getSelectedImage(editor));
4091
+ };
4092
+
4093
+ var startTimedUpload = function (editor, imageUploadTimerState) {
4094
+ var imageUploadTimer = Delay.setEditorTimeout(editor, function () {
4095
+ editor.editorUpload.uploadImagesAuto();
4096
+ }, editor.settings.images_upload_timeout || 30000);
4097
+
4098
+ imageUploadTimerState.set(imageUploadTimer);
4099
+ };
4100
+
4101
+ var cancelTimedUpload = function (imageUploadTimerState) {
4102
+ clearTimeout(imageUploadTimerState.get());
4103
+ };
4104
+
4105
+ var updateSelectedImage = function (editor, ir, uploadImmediately, imageUploadTimerState) {
4106
+ return ir.toBlob().then(function (blob) {
4107
+ var uri, name, blobCache, blobInfo, selectedImage;
4108
+
4109
+ blobCache = editor.editorUpload.blobCache;
4110
+ selectedImage = getSelectedImage(editor);
4111
+ uri = selectedImage.src;
4112
+
4113
+ if (editor.settings.images_reuse_filename) {
4114
+ blobInfo = blobCache.getByUri(uri);
4115
+ if (blobInfo) {
4116
+ uri = blobInfo.uri();
4117
+ name = blobInfo.name();
4118
+ } else {
4119
+ name = extractFilename(editor, uri);
4120
+ }
4121
+ }
4122
+
4123
+ blobInfo = blobCache.create({
4124
+ id: createId(),
4125
+ blob: blob,
4126
+ base64: ir.toBase64(),
4127
+ uri: uri,
4128
+ name: name
4129
+ });
4130
+
4131
+ blobCache.add(blobInfo);
4132
+
4133
+ editor.undoManager.transact(function () {
4134
+ function imageLoadedHandler() {
4135
+ editor.$(selectedImage).off('load', imageLoadedHandler);
4136
+ editor.nodeChanged();
4137
+
4138
+ if (uploadImmediately) {
4139
+ editor.editorUpload.uploadImagesAuto();
4140
+ } else {
4141
+ cancelTimedUpload(imageUploadTimerState);
4142
+ startTimedUpload(editor, imageUploadTimerState);
4143
+ }
4144
+ }
4145
+
4146
+ editor.$(selectedImage).on('load', imageLoadedHandler);
4147
+
4148
+ editor.$(selectedImage).attr({
4149
+ src: blobInfo.blobUri()
4150
+ }).removeAttr('data-mce-src');
4151
+ });
4152
+
4153
+ return blobInfo;
4154
+ });
4155
+ };
4156
+
4157
+ var selectedImageOperation = function (editor, imageUploadTimerState, fn) {
4158
+ return function () {
4159
+ return editor._scanForImages().
4160
+ then(Fun.curry(findSelectedBlob, editor)).
4161
+ then(ResultConversions.blobToImageResult).
4162
+ then(fn).
4163
+ then(function (imageResult) {
4164
+ return updateSelectedImage(editor, imageResult, false, imageUploadTimerState);
4165
+ }, function (error) {
4166
+ displayError(editor, error);
4167
+ });
4168
+ };
4169
+ };
4170
+
4171
+ var rotate = function (editor, imageUploadTimerState, angle) {
4172
+ return function () {
4173
+ return selectedImageOperation(editor, imageUploadTimerState, function (imageResult) {
4174
+ var size = ImageSize.getImageSize(getSelectedImage(editor));
4175
+
4176
+ if (size) {
4177
+ ImageSize.setImageSize(getSelectedImage(editor), {
4178
+ w: size.h,
4179
+ h: size.w
4180
+ });
4181
+ }
4182
+
4183
+ return ImageTransformations.rotate(imageResult, angle);
4184
+ })();
4185
+ };
4186
+ };
4187
+
4188
+ var flip = function (editor, imageUploadTimerState, axis) {
4189
+ return function () {
4190
+ return selectedImageOperation(editor, imageUploadTimerState, function (imageResult) {
4191
+ return ImageTransformations.flip(imageResult, axis);
4192
+ })();
4193
+ };
4194
+ };
4195
+
4196
+ var editImageDialog = function (editor, imageUploadTimerState) {
4197
+ return function () {
4198
+ var img = getSelectedImage(editor), originalSize = ImageSize.getNaturalImageSize(img);
4199
+
4200
+ var handleDialogBlob = function (blob) {
4201
+ return new Promise(function (resolve) {
4202
+ BlobConversions.blobToImage(blob).
4203
+ then(function (newImage) {
4204
+ var newSize = ImageSize.getNaturalImageSize(newImage);
4205
+
4206
+ if (originalSize.w !== newSize.w || originalSize.h !== newSize.h) {
4207
+ if (ImageSize.getImageSize(img)) {
4208
+ ImageSize.setImageSize(img, newSize);
4209
+ }
4210
+ }
4211
+
4212
+ URL.revokeObjectURL(newImage.src);
4213
+ resolve(blob);
4214
+ });
4215
+ });
4216
+ };
4217
+
4218
+ var openDialog = function (editor, imageResult) {
4219
+ return Dialog.edit(editor, imageResult).then(handleDialogBlob).
4220
+ then(ResultConversions.blobToImageResult).
4221
+ then(function (imageResult) {
4222
+ return updateSelectedImage(editor, imageResult, true, imageUploadTimerState);
4223
+ }, function () {
4224
+ // Close dialog
4225
+ });
4226
+ };
4227
+
4228
+ findSelectedBlob(editor).
4229
+ then(ResultConversions.blobToImageResult).
4230
+ then(Fun.curry(openDialog, editor), function (error) {
4231
+ displayError(editor, error);
4232
+ });
4233
+ };
4234
+ };
4235
+
4236
+ return {
4237
+ rotate: rotate,
4238
+ flip: flip,
4239
+ editImageDialog: editImageDialog,
4240
+ isEditableImage: isEditableImage,
4241
+ cancelTimedUpload: cancelTimedUpload
4242
+ };
4243
+ }
4244
+ );
4245
+ /**
4246
+ * Commands.js
4247
+ *
4248
+ * Released under LGPL License.
4249
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
4250
+ *
4251
+ * License: http://www.tinymce.com/license
4252
+ * Contributing: http://www.tinymce.com/contributing
4253
+ */
4254
+
4255
+ define(
4256
+ 'tinymce.plugins.imagetools.api.Commands',
4257
+ [
4258
+ 'tinymce.core.util.Tools',
4259
+ 'tinymce.plugins.imagetools.core.Actions'
4260
+ ],
4261
+ function (Tools, Actions) {
4262
+ var register = function (editor, imageUploadTimerState) {
4263
+ Tools.each({
4264
+ mceImageRotateLeft: Actions.rotate(editor, imageUploadTimerState, -90),
4265
+ mceImageRotateRight: Actions.rotate(editor, imageUploadTimerState, 90),
4266
+ mceImageFlipVertical: Actions.flip(editor, imageUploadTimerState, 'v'),
4267
+ mceImageFlipHorizontal: Actions.flip(editor, imageUploadTimerState, 'h'),
4268
+ mceEditImage: Actions.editImageDialog(editor, imageUploadTimerState)
4269
+ }, function (fn, cmd) {
4270
+ editor.addCommand(cmd, fn);
4271
+ });
4272
+ };
4273
+
4274
+ return {
4275
+ register: register
4276
+ };
4277
+ }
4278
+ );
4279
+
4280
+ /**
4281
+ * Plugin.js
4282
+ *
4283
+ * Released under LGPL License.
4284
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
4285
+ *
4286
+ * License: http://www.tinymce.com/license
4287
+ * Contributing: http://www.tinymce.com/contributing
4288
+ */
4289
+
4290
+ define(
4291
+ 'tinymce.plugins.imagetools.core.UploadSelectedImage',
4292
+ [
4293
+ 'tinymce.plugins.imagetools.core.Actions'
4294
+ ],
4295
+ function (Actions) {
4296
+ var setup = function (editor, imageUploadTimerState, lastSelectedImageState) {
4297
+ editor.on('NodeChange', function (e) {
4298
+ var lastSelectedImage = lastSelectedImageState.get();
4299
+
4300
+ // If the last node we selected was an image
4301
+ // And had a source that doesn't match the current blob url
4302
+ // We need to attempt to upload it
4303
+ if (lastSelectedImage && lastSelectedImage.src !== e.element.src) {
4304
+ Actions.cancelTimedUpload(imageUploadTimerState);
4305
+ editor.editorUpload.uploadImagesAuto();
4306
+ lastSelectedImageState.set(null);
4307
+ }
4308
+
4309
+ // Set up the lastSelectedImage
4310
+ if (Actions.isEditableImage(editor, e.element)) {
4311
+ lastSelectedImageState.set(e.element);
4312
+ }
4313
+ });
4314
+ };
4315
+
4316
+ return {
4317
+ setup: setup
4318
+ };
4319
+ }
4320
+ );
4321
+
4322
+ /**
4323
+ * Buttons.js
4324
+ *
4325
+ * Released under LGPL License.
4326
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
4327
+ *
4328
+ * License: http://www.tinymce.com/license
4329
+ * Contributing: http://www.tinymce.com/contributing
4330
+ */
4331
+
4332
+ define(
4333
+ 'tinymce.plugins.imagetools.ui.Buttons',
4334
+ [
4335
+ ],
4336
+ function () {
4337
+ var register = function (editor) {
4338
+ editor.addButton('rotateleft', {
4339
+ title: 'Rotate counterclockwise',
4340
+ cmd: 'mceImageRotateLeft'
4341
+ });
4342
+
4343
+ editor.addButton('rotateright', {
4344
+ title: 'Rotate clockwise',
4345
+ cmd: 'mceImageRotateRight'
4346
+ });
4347
+
4348
+ editor.addButton('flipv', {
4349
+ title: 'Flip vertically',
4350
+ cmd: 'mceImageFlipVertical'
4351
+ });
4352
+
4353
+ editor.addButton('fliph', {
4354
+ title: 'Flip horizontally',
4355
+ cmd: 'mceImageFlipHorizontal'
4356
+ });
4357
+
4358
+ editor.addButton('editimage', {
4359
+ title: 'Edit image',
4360
+ cmd: 'mceEditImage'
4361
+ });
4362
+
4363
+ editor.addButton('imageoptions', {
4364
+ title: 'Image options',
4365
+ icon: 'options',
4366
+ cmd: 'mceImage'
4367
+ });
4368
+ };
4369
+
4370
+ return {
4371
+ register: register
4372
+ };
4373
+ }
4374
+ );
4375
+
4376
+ /**
4377
+ * ContextToolbar.js
4378
+ *
4379
+ * Released under LGPL License.
4380
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
4381
+ *
4382
+ * License: http://www.tinymce.com/license
4383
+ * Contributing: http://www.tinymce.com/contributing
4384
+ */
4385
+
4386
+ define(
4387
+ 'tinymce.plugins.imagetools.ui.ContextToolbar',
4388
+ [
4389
+ 'ephox.katamari.api.Fun',
4390
+ 'tinymce.plugins.imagetools.api.Settings',
4391
+ 'tinymce.plugins.imagetools.core.Actions'
4392
+ ],
4393
+ function (Fun, Settings, Actions) {
4394
+ var register = function (editor) {
4395
+ editor.addContextToolbar(
4396
+ Fun.curry(Actions.isEditableImage, editor),
4397
+ Settings.getToolbarItems(editor)
4398
+ );
4399
+ };
4400
+
4401
+ return {
4402
+ register: register
4403
+ };
4404
+ }
4405
+ );
4406
+
4407
+ /**
4408
+ * Plugin.js
4409
+ *
4410
+ * Released under LGPL License.
4411
+ * Copyright (c) 1999-2017 Ephox Corp. All rights reserved
4412
+ *
4413
+ * License: http://www.tinymce.com/license
4414
+ * Contributing: http://www.tinymce.com/contributing
4415
+ */
4416
+
4417
+ define(
4418
+ 'tinymce.plugins.imagetools.Plugin',
4419
+ [
4420
+ 'ephox.katamari.api.Cell',
4421
+ 'tinymce.core.PluginManager',
4422
+ 'tinymce.plugins.imagetools.api.Commands',
4423
+ 'tinymce.plugins.imagetools.core.UploadSelectedImage',
4424
+ 'tinymce.plugins.imagetools.ui.Buttons',
4425
+ 'tinymce.plugins.imagetools.ui.ContextToolbar'
4426
+ ],
4427
+ function (Cell, PluginManager, Commands, UploadSelectedImage, Buttons, ContextToolbar) {
4428
+ PluginManager.add('imagetools', function (editor) {
4429
+ var imageUploadTimerState = Cell(0);
4430
+ var lastSelectedImageState = Cell(null);
4431
+
4432
+ Commands.register(editor, imageUploadTimerState);
4433
+ Buttons.register(editor);
4434
+ ContextToolbar.register(editor);
4435
+
4436
+ UploadSelectedImage.setup(editor, imageUploadTimerState, lastSelectedImageState);
4437
+ });
4438
+
4439
+ return function () { };
4440
+ }
4441
+ );
4442
+
4443
+ dem('tinymce.plugins.imagetools.Plugin')();
4444
+ })();