mosaico 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (425) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +8 -0
  3. data/Gemfile +7 -0
  4. data/LICENSE +680 -0
  5. data/README.md +179 -0
  6. data/Rakefile +5 -0
  7. data/app/assets/images/mosaico/logo_transparent.png +0 -0
  8. data/app/assets/javascripts/mosaico/application.js.erb +51 -0
  9. data/app/assets/javascripts/mosaico/plugins/debug.js.erb +10 -0
  10. data/app/assets/javascripts/mosaico/plugins/logo.js.erb +10 -0
  11. data/app/assets/javascripts/mosaico/plugins/preview.js +85 -0
  12. data/app/assets/javascripts/mosaico/plugins/save.js.erb +72 -0
  13. data/app/assets/javascripts/mosaico/plugins/template_path.js.erb +22 -0
  14. data/app/assets/javascripts/mosaico/plugins/translations.js +10 -0
  15. data/app/assets/javascripts/mosaico/utilities.js +25 -0
  16. data/app/assets/stylesheets/mosaico/application.css +6 -0
  17. data/app/controllers/mosaico/application_controller.rb +17 -0
  18. data/app/controllers/mosaico/images_controller.rb +142 -0
  19. data/app/controllers/mosaico/projects_controller.rb +31 -0
  20. data/app/controllers/mosaico/templates_controller.rb +8 -0
  21. data/app/helpers/mosaico/application_helper.rb +7 -0
  22. data/app/models/mosaico/image.rb +9 -0
  23. data/app/models/mosaico/placeholder_image.rb +9 -0
  24. data/app/models/mosaico/project.rb +13 -0
  25. data/app/models/mosaico/uploaded_image.rb +26 -0
  26. data/app/views/layouts/mosaico/application.html.erb +13 -0
  27. data/app/views/mosaico/projects/new.html.erb +1 -0
  28. data/app/views/mosaico/projects/show.html.erb +1 -0
  29. data/app/views/mosaico/shared/_metadata.html.erb +12 -0
  30. data/config/routes.rb +12 -0
  31. data/db/migrate/20170817202255_add_images.rb +14 -0
  32. data/db/migrate/20170824233755_add_projects.rb +11 -0
  33. data/lib/mosaico.rb +100 -0
  34. data/lib/mosaico/engine.rb +72 -0
  35. data/lib/mosaico/local_backend.rb +23 -0
  36. data/lib/mosaico/local_image_backend.rb +7 -0
  37. data/lib/mosaico/local_placeholder_backend.rb +7 -0
  38. data/lib/mosaico/placeholder.png +0 -0
  39. data/lib/mosaico/template.rb +89 -0
  40. data/lib/mosaico/versafix_template.rb +43 -0
  41. data/lib/mosaico/version.rb +4 -0
  42. data/lib/tasks/makeThumbs.js.erb +57 -0
  43. data/lib/tasks/thumbs.rake +35 -0
  44. data/mosaico.gemspec +22 -0
  45. data/screenshot.png +0 -0
  46. data/vendor/assets/fonts/LiberationSans-Regular.ttf +0 -0
  47. data/vendor/assets/mosaico-0.16.0/mosaico/.jsbeautifyrc +6 -0
  48. data/vendor/assets/mosaico-0.16.0/mosaico/.jshintrc +8 -0
  49. data/vendor/assets/mosaico-0.16.0/mosaico/.travis.yml +6 -0
  50. data/vendor/assets/mosaico-0.16.0/mosaico/CONTRIBUTING.md +37 -0
  51. data/vendor/assets/mosaico-0.16.0/mosaico/Dockerfile +21 -0
  52. data/vendor/assets/mosaico-0.16.0/mosaico/Gruntfile.js +241 -0
  53. data/vendor/assets/mosaico-0.16.0/mosaico/LICENSE +680 -0
  54. data/vendor/assets/mosaico-0.16.0/mosaico/NOTICE.txt +87 -0
  55. data/vendor/assets/mosaico-0.16.0/mosaico/README.md +73 -0
  56. data/vendor/assets/mosaico-0.16.0/mosaico/backend/README.txt +23 -0
  57. data/vendor/assets/mosaico-0.16.0/mosaico/backend/main.js +162 -0
  58. data/vendor/assets/mosaico-0.16.0/mosaico/bower.json +76 -0
  59. data/vendor/assets/mosaico-0.16.0/mosaico/build/mosaico-material.css +7425 -0
  60. data/vendor/assets/mosaico-0.16.0/mosaico/build/mosaico.css +7133 -0
  61. data/vendor/assets/mosaico-0.16.0/mosaico/build/mosaico.debug.js +1517 -0
  62. data/vendor/assets/mosaico-0.16.0/mosaico/build/mosaico.js +12828 -0
  63. data/vendor/assets/mosaico-0.16.0/mosaico/build/templates.js +15 -0
  64. data/vendor/assets/mosaico-0.16.0/mosaico/dist/fa/fonts/fontawesome-webfont.eot +0 -0
  65. data/vendor/assets/mosaico-0.16.0/mosaico/dist/fa/fonts/fontawesome-webfont.svg +685 -0
  66. data/vendor/assets/mosaico-0.16.0/mosaico/dist/fa/fonts/fontawesome-webfont.ttf +0 -0
  67. data/vendor/assets/mosaico-0.16.0/mosaico/dist/fa/fonts/fontawesome-webfont.woff +0 -0
  68. data/vendor/assets/mosaico-0.16.0/mosaico/dist/fa/fonts/fontawesome-webfont.woff2 +0 -0
  69. data/vendor/assets/mosaico-0.16.0/mosaico/dist/img/byvoxmail.png +0 -0
  70. data/vendor/assets/mosaico-0.16.0/mosaico/dist/img/mosaico-badge.gif +0 -0
  71. data/vendor/assets/mosaico-0.16.0/mosaico/dist/img/mosaico-v.gif +0 -0
  72. data/vendor/assets/mosaico-0.16.0/mosaico/dist/img/mosaico32.png +0 -0
  73. data/vendor/assets/mosaico-0.16.0/mosaico/dist/img/mosaicologo.png +0 -0
  74. data/vendor/assets/mosaico-0.16.0/mosaico/dist/img/screenshot-orig.png +0 -0
  75. data/vendor/assets/mosaico-0.16.0/mosaico/dist/img/screenshot.png +0 -0
  76. data/vendor/assets/mosaico-0.16.0/mosaico/dist/lang/README.md +26 -0
  77. data/vendor/assets/mosaico-0.16.0/mosaico/dist/lang/mosaico-de.json +88 -0
  78. data/vendor/assets/mosaico-0.16.0/mosaico/dist/lang/mosaico-en.json +88 -0
  79. data/vendor/assets/mosaico-0.16.0/mosaico/dist/lang/mosaico-es.json +88 -0
  80. data/vendor/assets/mosaico-0.16.0/mosaico/dist/lang/mosaico-fr.json +88 -0
  81. data/vendor/assets/mosaico-0.16.0/mosaico/dist/lang/mosaico-it.json +88 -0
  82. data/vendor/assets/mosaico-0.16.0/mosaico/dist/lang/mosaico-nl.json +88 -0
  83. data/vendor/assets/mosaico-0.16.0/mosaico/dist/lang/mosaico-sv.json +88 -0
  84. data/vendor/assets/mosaico-0.16.0/mosaico/dist/mosaico-material.min.css +5 -0
  85. data/vendor/assets/mosaico-0.16.0/mosaico/dist/mosaico-material.min.css.map +1 -0
  86. data/vendor/assets/mosaico-0.16.0/mosaico/dist/mosaico.min.css +5 -0
  87. data/vendor/assets/mosaico-0.16.0/mosaico/dist/mosaico.min.css.map +1 -0
  88. data/vendor/assets/mosaico-0.16.0/mosaico/dist/mosaico.min.js +1517 -0
  89. data/vendor/assets/mosaico-0.16.0/mosaico/dist/mosaico.min.js.map +147 -0
  90. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/canvas-to-blob.min.js +2 -0
  91. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery-ui.min.css +7 -0
  92. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery-ui.min.js +13 -0
  93. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery.fileupload-image.js +324 -0
  94. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery.fileupload-process.js +175 -0
  95. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery.fileupload-validate.js +122 -0
  96. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery.fileupload.js +1482 -0
  97. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery.iframe-transport.js +217 -0
  98. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery.min.js +5 -0
  99. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery.min.map +1 -0
  100. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/jquery.ui.touch-punch.min.js +11 -0
  101. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/knockout-jqueryui.min.js +1 -0
  102. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/knockout.js +123 -0
  103. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/load-image.all.min.js +2 -0
  104. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/notoregular/NotoSans-Regular-webfont.eot +0 -0
  105. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/notoregular/NotoSans-Regular-webfont.ttf +0 -0
  106. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/notoregular/NotoSans-Regular-webfont.woff +0 -0
  107. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/notoregular/stylesheet.css +9 -0
  108. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/advlist/plugin.js +101 -0
  109. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/advlist/plugin.min.js +1 -0
  110. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/anchor/plugin.js +55 -0
  111. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/anchor/plugin.min.js +1 -0
  112. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/autolink/plugin.js +204 -0
  113. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/autolink/plugin.min.js +1 -0
  114. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/autoresize/plugin.js +162 -0
  115. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/autoresize/plugin.min.js +1 -0
  116. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/autosave/plugin.js +165 -0
  117. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/autosave/plugin.min.js +1 -0
  118. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/bbcode/plugin.js +123 -0
  119. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/bbcode/plugin.min.js +1 -0
  120. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/charmap/plugin.js +462 -0
  121. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/charmap/plugin.min.js +1 -0
  122. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/code/plugin.js +60 -0
  123. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/code/plugin.min.js +1 -0
  124. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/codesample/css/prism.css +138 -0
  125. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/codesample/plugin.js +1319 -0
  126. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/codesample/plugin.min.js +1 -0
  127. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/colorpicker/plugin.js +112 -0
  128. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/colorpicker/plugin.min.js +1 -0
  129. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/contextmenu/plugin.js +100 -0
  130. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/contextmenu/plugin.min.js +1 -0
  131. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/directionality/plugin.js +64 -0
  132. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/directionality/plugin.min.js +1 -0
  133. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-cool.gif +0 -0
  134. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-cry.gif +0 -0
  135. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-embarassed.gif +0 -0
  136. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-foot-in-mouth.gif +0 -0
  137. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-frown.gif +0 -0
  138. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-innocent.gif +0 -0
  139. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-kiss.gif +0 -0
  140. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-laughing.gif +0 -0
  141. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-money-mouth.gif +0 -0
  142. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-sealed.gif +0 -0
  143. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-smile.gif +0 -0
  144. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-surprised.gif +0 -0
  145. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-tongue-out.gif +0 -0
  146. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-undecided.gif +0 -0
  147. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-wink.gif +0 -0
  148. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/img/smiley-yell.gif +0 -0
  149. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/plugin.js +65 -0
  150. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/emoticons/plugin.min.js +1 -0
  151. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/fullpage/plugin.js +490 -0
  152. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/fullpage/plugin.min.js +1 -0
  153. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/fullscreen/plugin.js +154 -0
  154. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/fullscreen/plugin.min.js +1 -0
  155. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/hr/plugin.js +30 -0
  156. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/hr/plugin.min.js +1 -0
  157. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/image/plugin.js +630 -0
  158. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/image/plugin.min.js +1 -0
  159. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/imagetools/plugin.js +2944 -0
  160. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/imagetools/plugin.min.js +1 -0
  161. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/importcss/plugin.js +273 -0
  162. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/importcss/plugin.min.js +1 -0
  163. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/insertdatetime/plugin.js +121 -0
  164. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/insertdatetime/plugin.min.js +1 -0
  165. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/layer/plugin.js +225 -0
  166. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/layer/plugin.min.js +1 -0
  167. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/legacyoutput/plugin.js +208 -0
  168. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/legacyoutput/plugin.min.js +1 -0
  169. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/link/plugin.js +403 -0
  170. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/link/plugin.min.js +1 -0
  171. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/lists/plugin.js +965 -0
  172. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/lists/plugin.min.js +1 -0
  173. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/media/moxieplayer.swf +0 -0
  174. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/media/plugin.js +879 -0
  175. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/media/plugin.min.js +1 -0
  176. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/nonbreaking/plugin.js +53 -0
  177. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/nonbreaking/plugin.min.js +1 -0
  178. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/noneditable/plugin.js +101 -0
  179. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/noneditable/plugin.min.js +1 -0
  180. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/pagebreak/plugin.js +88 -0
  181. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/pagebreak/plugin.min.js +1 -0
  182. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/paste/plugin.js +1844 -0
  183. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/paste/plugin.min.js +1 -0
  184. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/preview/plugin.js +101 -0
  185. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/preview/plugin.min.js +1 -0
  186. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/print/plugin.js +32 -0
  187. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/print/plugin.min.js +1 -0
  188. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/save/plugin.js +98 -0
  189. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/save/plugin.min.js +1 -0
  190. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/searchreplace/plugin.js +609 -0
  191. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/searchreplace/plugin.min.js +1 -0
  192. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/spellchecker/plugin.js +1031 -0
  193. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/spellchecker/plugin.min.js +1 -0
  194. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/tabfocus/plugin.js +120 -0
  195. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/tabfocus/plugin.min.js +1 -0
  196. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/table/plugin.js +4400 -0
  197. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/table/plugin.min.js +2 -0
  198. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/template/plugin.js +276 -0
  199. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/template/plugin.min.js +1 -0
  200. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/textcolor/plugin.js +297 -0
  201. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/textcolor/plugin.min.js +1 -0
  202. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/textpattern/plugin.js +268 -0
  203. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/textpattern/plugin.min.js +1 -0
  204. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/visualblocks/css/visualblocks.css +135 -0
  205. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/visualblocks/plugin.js +86 -0
  206. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/visualblocks/plugin.min.js +1 -0
  207. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/visualchars/plugin.js +123 -0
  208. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/visualchars/plugin.min.js +1 -0
  209. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/wordcount/plugin.js +69 -0
  210. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/plugins/wordcount/plugin.min.js +1 -0
  211. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/Variables.less +196 -0
  212. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/content.inline.min.css +1 -0
  213. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/content.min.css +1 -0
  214. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/readme.md +1 -0
  215. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce-small.eot +0 -0
  216. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce-small.json +1277 -0
  217. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce-small.svg +63 -0
  218. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce-small.ttf +0 -0
  219. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce-small.woff +0 -0
  220. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce.eot +0 -0
  221. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce.json +1972 -0
  222. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce.svg +98 -0
  223. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce.ttf +0 -0
  224. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/fonts/tinymce.woff +0 -0
  225. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/img/anchor.gif +0 -0
  226. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/img/loader.gif +0 -0
  227. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/img/object.gif +0 -0
  228. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/img/trans.gif +0 -0
  229. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/skin.ie7.min.css +1 -0
  230. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/skin.json +79 -0
  231. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/gray-flat/skin.min.css +1 -0
  232. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/content.inline.min.css +1 -0
  233. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/content.min.css +1 -0
  234. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/fonts/tinymce-small.eot +0 -0
  235. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/fonts/tinymce-small.svg +63 -0
  236. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/fonts/tinymce-small.ttf +0 -0
  237. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/fonts/tinymce-small.woff +0 -0
  238. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/fonts/tinymce.eot +0 -0
  239. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/fonts/tinymce.svg +129 -0
  240. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/fonts/tinymce.ttf +0 -0
  241. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/fonts/tinymce.woff +0 -0
  242. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/img/anchor.gif +0 -0
  243. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/img/loader.gif +0 -0
  244. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/img/object.gif +0 -0
  245. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/img/trans.gif +0 -0
  246. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/skin.ie7.min.css +1 -0
  247. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/skins/lightgray/skin.min.css +1 -0
  248. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/themes/inlite/theme.js +1828 -0
  249. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/themes/inlite/theme.min.js +1 -0
  250. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/themes/modern/theme.js +934 -0
  251. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/themes/modern/theme.min.js +1 -0
  252. data/vendor/assets/mosaico-0.16.0/mosaico/dist/vendor/tinymce.min.js +14 -0
  253. data/vendor/assets/mosaico-0.16.0/mosaico/editor.html +63 -0
  254. data/vendor/assets/mosaico-0.16.0/mosaico/favicon.ico +0 -0
  255. data/vendor/assets/mosaico-0.16.0/mosaico/index.html +368 -0
  256. data/vendor/assets/mosaico-0.16.0/mosaico/package.json +92 -0
  257. data/vendor/assets/mosaico-0.16.0/mosaico/res/img/byvoxmail.png +0 -0
  258. data/vendor/assets/mosaico-0.16.0/mosaico/res/img/mosaico-badge.gif +0 -0
  259. data/vendor/assets/mosaico-0.16.0/mosaico/res/img/mosaico-v.gif +0 -0
  260. data/vendor/assets/mosaico-0.16.0/mosaico/res/img/mosaico32.png +0 -0
  261. data/vendor/assets/mosaico-0.16.0/mosaico/res/img/mosaicologo.png +0 -0
  262. data/vendor/assets/mosaico-0.16.0/mosaico/res/img/screenshot-orig.png +0 -0
  263. data/vendor/assets/mosaico-0.16.0/mosaico/res/img/screenshot.png +0 -0
  264. data/vendor/assets/mosaico-0.16.0/mosaico/res/lang/README.md +26 -0
  265. data/vendor/assets/mosaico-0.16.0/mosaico/res/lang/mosaico-de.json +88 -0
  266. data/vendor/assets/mosaico-0.16.0/mosaico/res/lang/mosaico-en.json +88 -0
  267. data/vendor/assets/mosaico-0.16.0/mosaico/res/lang/mosaico-es.json +88 -0
  268. data/vendor/assets/mosaico-0.16.0/mosaico/res/lang/mosaico-fr.json +88 -0
  269. data/vendor/assets/mosaico-0.16.0/mosaico/res/lang/mosaico-it.json +88 -0
  270. data/vendor/assets/mosaico-0.16.0/mosaico/res/lang/mosaico-nl.json +88 -0
  271. data/vendor/assets/mosaico-0.16.0/mosaico/res/lang/mosaico-sv.json +88 -0
  272. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/Variables.less +196 -0
  273. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/content.inline.min.css +1 -0
  274. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/content.min.css +1 -0
  275. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/readme.md +1 -0
  276. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce-small.eot +0 -0
  277. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce-small.json +1277 -0
  278. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce-small.svg +63 -0
  279. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce-small.ttf +0 -0
  280. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce-small.woff +0 -0
  281. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce.eot +0 -0
  282. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce.json +1972 -0
  283. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce.svg +98 -0
  284. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce.ttf +0 -0
  285. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/fonts/tinymce.woff +0 -0
  286. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/img/anchor.gif +0 -0
  287. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/img/loader.gif +0 -0
  288. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/img/object.gif +0 -0
  289. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/img/trans.gif +0 -0
  290. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/skin.ie7.min.css +1 -0
  291. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/skin.json +79 -0
  292. data/vendor/assets/mosaico-0.16.0/mosaico/res/vendor/skins/gray-flat/skin.min.css +1 -0
  293. data/vendor/assets/mosaico-0.16.0/mosaico/server-config.js +12 -0
  294. data/vendor/assets/mosaico-0.16.0/mosaico/spec/converter-spec.js +115 -0
  295. data/vendor/assets/mosaico-0.16.0/mosaico/spec/data/template-versafix-1.model.json +137 -0
  296. data/vendor/assets/mosaico-0.16.0/mosaico/spec/declarations-spec.js +282 -0
  297. data/vendor/assets/mosaico-0.16.0/mosaico/spec/mensch-spec.js +114 -0
  298. data/vendor/assets/mosaico-0.16.0/mosaico/spec/model-spec.js +88 -0
  299. data/vendor/assets/mosaico-0.16.0/mosaico/spec/stylesheet-spec.js +177 -0
  300. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/app_standalone.less +7 -0
  301. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/app_standalone_material.less +350 -0
  302. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/safarihack.css +17 -0
  303. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/style_elements.less +497 -0
  304. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/style_elements_jquery.less +344 -0
  305. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/style_elements_mixins.less +406 -0
  306. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/style_elements_moxie.less +130 -0
  307. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/style_mosaico.less +529 -0
  308. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/style_mosaico_content.less +391 -0
  309. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/style_mosaico_tools.less +1043 -0
  310. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/style_reset.less +45 -0
  311. data/vendor/assets/mosaico-0.16.0/mosaico/src/css/style_variables.less +156 -0
  312. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/app.js +167 -0
  313. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/bind-iframe.js +64 -0
  314. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/blocks.js +118 -0
  315. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/choose-template.js +7 -0
  316. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/colorpicker.js +58 -0
  317. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/csstext.js +16 -0
  318. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/droppable.js +87 -0
  319. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/eventable.js +33 -0
  320. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/extender-pagination.js +60 -0
  321. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/extsortables.js +103 -0
  322. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/fileupload.js +373 -0
  323. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/if-subs.js +110 -0
  324. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/jqueryui-spinner.js +31 -0
  325. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/jqueryui-tabs.js +17 -0
  326. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/script-template.js +30 -0
  327. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/scrollfix.js +48 -0
  328. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/scrollintoview.js +83 -0
  329. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/string-template.js +76 -0
  330. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/tooltips.js +36 -0
  331. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/validated-value.js +40 -0
  332. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/virtuals.js +102 -0
  333. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/bindings/wysiwygs.js +304 -0
  334. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/checkmodel.js +114 -0
  335. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/declarations.js +279 -0
  336. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/domutils.js +93 -0
  337. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/editor.js +411 -0
  338. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/main.js +42 -0
  339. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/model.js +536 -0
  340. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/parser.js +485 -0
  341. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/stylesheet.js +205 -0
  342. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/utils.js +156 -0
  343. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/converter/wrapper.js +308 -0
  344. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/ext/color.js +53 -0
  345. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/ext/inliner.js +35 -0
  346. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/ext/localstorage.js +100 -0
  347. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/ko-bindings.js +22 -0
  348. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/template-loader.js +446 -0
  349. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/timed-call.js +31 -0
  350. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/undomanager/undomain.js +49 -0
  351. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/undomanager/undoserializer.js +120 -0
  352. data/vendor/assets/mosaico-0.16.0/mosaico/src/js/viewmodel.js +595 -0
  353. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/array.tmpl.html +1 -0
  354. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/block-show.tmpl.html +1 -0
  355. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/block-wysiwyg.tmpl.html +18 -0
  356. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/blocks-show.tmpl.html +1 -0
  357. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/blocks-wysiwyg.tmpl.html +2 -0
  358. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/customstyle.tmpl.html +3 -0
  359. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/empty.tmpl.html +0 -0
  360. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/error.tmpl.html +1 -0
  361. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/gallery-images.tmpl.html +16 -0
  362. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/img-wysiwyg.tmpl.html +43 -0
  363. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/main.tmpl.html +102 -0
  364. data/vendor/assets/mosaico-0.16.0/mosaico/src/tmpl/toolbox.tmpl.html +111 -0
  365. data/vendor/assets/mosaico-0.16.0/mosaico/tasks/combineKOTemplates.js +24 -0
  366. data/vendor/assets/mosaico-0.16.0/mosaico/tasks/lib/phantom-thumbnailer-editor.js +168 -0
  367. data/vendor/assets/mosaico-0.16.0/mosaico/tasks/makeThumbs.js +79 -0
  368. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tedc15/README.md +1 -0
  369. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tedc15/edres/_full.png +0 -0
  370. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tedc15/edres/footerBlock.png +0 -0
  371. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tedc15/edres/headerBlock.png +0 -0
  372. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tedc15/edres/heroBlock.png +0 -0
  373. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tedc15/edres/socialBlock.png +0 -0
  374. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tedc15/edres/threetwoBlock.png +0 -0
  375. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tedc15/edres/twoColumnBlock.png +0 -0
  376. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tedc15/template-tedc15.html +567 -0
  377. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/edres/HeaderAndText.png +0 -0
  378. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/edres/_full.png +0 -0
  379. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/edres/fixedlist.png +0 -0
  380. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/mosaico-tutorial.md +335 -0
  381. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/mosaico-tutorial.pdf +0 -0
  382. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/screenshot_384.jpg +0 -0
  383. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/screenshot_385.jpg +0 -0
  384. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/screenshot_386.jpg +0 -0
  385. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/screenshot_387.jpg +0 -0
  386. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/screenshot_407.jpg +0 -0
  387. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/screenshot_408.jpg +0 -0
  388. data/vendor/assets/mosaico-0.16.0/mosaico/templates/tutorial/template-tutorial.html +68 -0
  389. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/_full.png +0 -0
  390. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/buttonBlock.png +0 -0
  391. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/doubleArticleBlock.png +0 -0
  392. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/doubleImageBlock.png +0 -0
  393. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/hrBlock.png +0 -0
  394. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/imageBlock.png +0 -0
  395. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/logoBlock.png +0 -0
  396. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/sideArticleBlock.png +0 -0
  397. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/singleArticleBlock.png +0 -0
  398. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/socialBlock.png +0 -0
  399. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/spacerBlock.png +0 -0
  400. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/textBlock.png +0 -0
  401. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/titleBlock.png +0 -0
  402. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/tripleArticleBlock.png +0 -0
  403. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/edres/tripleImageBlock.png +0 -0
  404. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/facebook_bw_ok.png +0 -0
  405. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/facebook_ok.png +0 -0
  406. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/flickr_bw_ok.png +0 -0
  407. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/flickr_ok.png +0 -0
  408. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/google+_bw_ok.png +0 -0
  409. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/google+_ok.png +0 -0
  410. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/instagram_bw_ok.png +0 -0
  411. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/instagram_ok.png +0 -0
  412. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/linkedin_bw_ok.png +0 -0
  413. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/linkedin_ok.png +0 -0
  414. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/twitter_bw_ok.png +0 -0
  415. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/twitter_ok.png +0 -0
  416. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/vimeo_bw_ok.png +0 -0
  417. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/vimeo_ok.png +0 -0
  418. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/web_bw_ok.png +0 -0
  419. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/web_ok.png +0 -0
  420. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/youtube_bw_ok.png +0 -0
  421. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/social_def/youtube_ok.png +0 -0
  422. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/img/sponsor.gif +0 -0
  423. data/vendor/assets/mosaico-0.16.0/mosaico/templates/versafix-1/template-versafix-1.html +1531 -0
  424. data/vendor/assets/mosaico-0.16.0/mosaico/uploads/README.md +1 -0
  425. metadata +536 -0
@@ -0,0 +1 @@
1
+ tinymce.PluginManager.add("image",function(e){function t(e,t){function n(e,n){r.parentNode&&r.parentNode.removeChild(r),t({width:e,height:n})}var r=document.createElement("img");r.onload=function(){n(Math.max(r.width,r.clientWidth),Math.max(r.height,r.clientHeight))},r.onerror=function(){n()};var i=r.style;i.visibility="hidden",i.position="fixed",i.bottom=i.left=0,i.width=i.height="auto",document.body.appendChild(r),r.src=e}function n(e,t,n){function r(e,n){return n=n||[],tinymce.each(e,function(e){var i={text:e.text||e.title};e.menu?i.menu=r(e.menu):(i.value=e.value,t(i)),n.push(i)}),n}return r(e,n||[])}function r(t){return function(){var n=e.settings.image_list;"string"==typeof n?tinymce.util.XHR.send({url:n,success:function(e){t(tinymce.util.JSON.parse(e))}}):"function"==typeof n?n(t):t(n)}}function i(r){function i(){var e,t,n,r;e=d.find("#width")[0],t=d.find("#height")[0],e&&t&&(n=e.value(),r=t.value(),d.find("#constrain")[0].checked()&&p&&m&&n&&r&&(p!=n?(r=Math.round(n/p*r),isNaN(r)||t.value(r)):(n=Math.round(r/m*n),isNaN(n)||e.value(n))),p=n,m=r)}function o(){function t(t){function n(){t.onload=t.onerror=null,e.selection&&(e.selection.select(t),e.nodeChanged())}t.onload=function(){y.width||y.height||!C||b.setAttribs(t,{width:t.clientWidth,height:t.clientHeight}),n()},t.onerror=n}var n,r;c(),i(),y=tinymce.extend(y,d.toJSON()),y.alt||(y.alt=""),y.title||(y.title=""),""===y.width&&(y.width=null),""===y.height&&(y.height=null),y.style||(y.style=null),y={src:y.src,alt:y.alt,title:y.title,width:y.width,height:y.height,style:y.style,caption:y.caption,class:y.class},e.undoManager.transact(function(){function i(t){return e.schema.getTextBlockElements()[t.nodeName]}if(!y.src)return void(f&&(b.remove(f),e.focus(),e.nodeChanged()));if(""===y.title&&(y.title=null),f?b.setAttribs(f,y):(y.id="__mcenew",e.focus(),e.selection.setContent(b.createHTML("img",y)),f=b.get("__mcenew"),b.setAttrib(f,"id",null)),e.editorUpload.uploadImagesAuto(),y.caption===!1&&b.is(f.parentNode,"figure.image")&&(n=f.parentNode,b.insertAfter(f,n),b.remove(n)),y.caption!==!0)t(f);else if(!b.is(f.parentNode,"figure.image")){r=f,f=f.cloneNode(!0),n=b.create("figure",{class:"image"}),n.appendChild(f),n.appendChild(b.create("figcaption",{contentEditable:!0},"Caption")),n.contentEditable=!1;var o=b.getParent(r,i);o?b.split(o,r,n):b.replace(n,r),e.selection.select(n)}})}function a(e){return e&&(e=e.replace(/px$/,"")),e}function s(n){var r,i,o,a=n.meta||{};g&&g.value(e.convertURL(this.value(),"src")),tinymce.each(a,function(e,t){d.find("#"+t).value(e)}),a.width||a.height||(r=e.convertURL(this.value(),"src"),i=e.settings.image_prepend_url,o=new RegExp("^(?:[a-z]+:)?//","i"),i&&!o.test(r)&&r.substring(0,i.length)!==i&&(r=i+r),this.value(r),t(e.documentBaseURI.toAbsolute(this.value()),function(e){e.width&&e.height&&C&&(p=e.width,m=e.height,d.find("#width").value(p),d.find("#height").value(m))}))}function l(e){if(e.margin){var t=e.margin.split(" ");switch(t.length){case 1:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[0],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[0];break;case 2:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[0],e["margin-left"]=e["margin-left"]||t[1];break;case 3:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[1];break;case 4:e["margin-top"]=e["margin-top"]||t[0],e["margin-right"]=e["margin-right"]||t[1],e["margin-bottom"]=e["margin-bottom"]||t[2],e["margin-left"]=e["margin-left"]||t[3]}delete e.margin}return e}function c(){function t(e){return e.length>0&&/^[0-9]+$/.test(e)&&(e+="px"),e}if(e.settings.image_advtab){var n=d.toJSON(),r=b.parseStyle(n.style);r=l(r),n.vspace&&(r["margin-top"]=r["margin-bottom"]=t(n.vspace)),n.hspace&&(r["margin-left"]=r["margin-right"]=t(n.hspace)),n.border&&(r["border-width"]=t(n.border)),d.find("#style").value(b.serializeStyle(b.parseStyle(b.serializeStyle(r))))}}function u(){if(e.settings.image_advtab){var t=d.toJSON(),n=b.parseStyle(t.style);d.find("#vspace").value(""),d.find("#hspace").value(""),n=l(n),(n["margin-top"]&&n["margin-bottom"]||n["margin-right"]&&n["margin-left"])&&(n["margin-top"]===n["margin-bottom"]?d.find("#vspace").value(a(n["margin-top"])):d.find("#vspace").value(""),n["margin-right"]===n["margin-left"]?d.find("#hspace").value(a(n["margin-right"])):d.find("#hspace").value("")),n["border-width"]&&d.find("#border").value(a(n["border-width"])),d.find("#style").value(b.serializeStyle(b.parseStyle(b.serializeStyle(n))))}}var d,f,h,p,m,g,v,y={},b=e.dom,C=e.settings.image_dimensions!==!1;f=e.selection.getNode(),h=b.getParent(f,"figure.image"),h&&(f=b.select("img",h)[0]),f&&("IMG"!=f.nodeName||f.getAttribute("data-mce-object")||f.getAttribute("data-mce-placeholder"))&&(f=null),f&&(p=b.getAttrib(f,"width"),m=b.getAttrib(f,"height"),y={src:b.getAttrib(f,"src"),alt:b.getAttrib(f,"alt"),title:b.getAttrib(f,"title"),class:b.getAttrib(f,"class"),width:p,height:m,caption:!!h}),r&&(g={type:"listbox",label:"Image list",values:n(r,function(t){t.value=e.convertURL(t.value||t.url,"src")},[{text:"None",value:""}]),value:y.src&&e.convertURL(y.src,"src"),onselect:function(e){var t=d.find("#alt");(!t.value()||e.lastControl&&t.value()==e.lastControl.text())&&t.value(e.control.text()),d.find("#src").value(e.control.value()).fire("change")},onPostRender:function(){g=this}}),e.settings.image_class_list&&(v={name:"class",type:"listbox",label:"Class",values:n(e.settings.image_class_list,function(t){t.value&&(t.textStyle=function(){return e.formatter.getCssText({inline:"img",classes:[t.value]})})})});var x=[{name:"src",type:"filepicker",filetype:"image",label:"Source",autofocus:!0,onchange:s},g];e.settings.image_description!==!1&&x.push({name:"alt",type:"textbox",label:"Image description"}),e.settings.image_title&&x.push({name:"title",type:"textbox",label:"Image Title"}),C&&x.push({type:"container",label:"Dimensions",layout:"flex",direction:"row",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:5,size:3,onchange:i,ariaLabel:"Width"},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:5,size:3,onchange:i,ariaLabel:"Height"},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}),x.push(v),e.settings.image_caption&&tinymce.Env.ceFalse&&x.push({name:"caption",type:"checkbox",label:"Caption"}),e.settings.image_advtab?(f&&(f.style.marginLeft&&f.style.marginRight&&f.style.marginLeft===f.style.marginRight&&(y.hspace=a(f.style.marginLeft)),f.style.marginTop&&f.style.marginBottom&&f.style.marginTop===f.style.marginBottom&&(y.vspace=a(f.style.marginTop)),f.style.borderWidth&&(y.border=a(f.style.borderWidth)),y.style=e.dom.serializeStyle(e.dom.parseStyle(e.dom.getAttrib(f,"style")))),d=e.windowManager.open({title:"Insert/edit image",data:y,bodyType:"tabpanel",body:[{title:"General",type:"form",items:x},{title:"Advanced",type:"form",pack:"start",items:[{label:"Style",name:"style",type:"textbox",onchange:u},{type:"form",layout:"grid",packV:"start",columns:2,padding:0,alignH:["left","right"],defaults:{type:"textbox",maxWidth:50,onchange:c},items:[{label:"Vertical space",name:"vspace"},{label:"Horizontal space",name:"hspace"},{label:"Border",name:"border"}]}]}],onSubmit:o})):d=e.windowManager.open({title:"Insert/edit image",data:y,body:x,onSubmit:o})}e.on("preInit",function(){function t(e){var t=e.attr("class");return t&&/\bimage\b/.test(t)}function n(e){return function(n){function r(t){t.attr("contenteditable",e?"true":null)}for(var i,o=n.length;o--;)i=n[o],t(i)&&(i.attr("contenteditable",e?"false":null),tinymce.each(i.getAll("figcaption"),r))}}e.parser.addNodeFilter("figure",n(!0)),e.serializer.addNodeFilter("figure",n(!1))}),e.addButton("image",{icon:"image",tooltip:"Insert/edit image",onclick:r(i),stateSelector:"img:not([data-mce-object],[data-mce-placeholder]),figure.image"}),e.addMenuItem("image",{icon:"image",text:"Insert/edit image",onclick:r(i),context:"insert",prependToContext:!0}),e.addCommand("mceImage",r(i))});
@@ -0,0 +1,2944 @@
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.push(dem(ids[i]));
61
+ callback.apply(null, callback);
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 minificiation when using a lot of global references
80
+ var defineGlobal = function (id, ref) {
81
+ define(id, [], function () { return ref; });
82
+ };
83
+ /*jsc
84
+ ["tinymce/imagetoolsplugin/Plugin","global!tinymce.PluginManager","global!tinymce.Env","global!tinymce.util.Promise","global!tinymce.util.URI","global!tinymce.util.Tools","global!tinymce.util.Delay","ephox/imagetools/api/ImageTransformations","ephox/imagetools/api/BlobConversions","tinymce/imagetoolsplugin/Dialog","tinymce/imagetoolsplugin/ImageSize","tinymce/imagetoolsplugin/Proxy","ephox/imagetools/transformations/Filters","ephox/imagetools/transformations/ImageTools","ephox/imagetools/util/Conversions","global!tinymce.dom.DOMUtils","global!tinymce.ui.Factory","global!tinymce.ui.Form","global!tinymce.ui.Container","tinymce/imagetoolsplugin/ImagePanel","tinymce/imagetoolsplugin/UndoStack","tinymce/imagetoolsplugin/Utils","ephox/imagetools/util/Canvas","ephox/imagetools/util/ImageSize","ephox/imagetools/util/Promise","ephox/imagetools/util/Mime","ephox/imagetools/transformations/ColorMatrix","ephox/imagetools/transformations/ImageResizerCanvas","global!tinymce.ui.Control","global!tinymce.ui.DragHelper","global!tinymce.geom.Rect","tinymce/imagetoolsplugin/CropRect","global!tinymce.dom.DomQuery","global!tinymce.util.Observable","global!tinymce.util.VK"]
85
+ jsc*/
86
+ defineGlobal("global!tinymce.PluginManager", tinymce.PluginManager);
87
+ defineGlobal("global!tinymce.Env", tinymce.Env);
88
+ defineGlobal("global!tinymce.util.Promise", tinymce.util.Promise);
89
+ defineGlobal("global!tinymce.util.URI", tinymce.util.URI);
90
+ defineGlobal("global!tinymce.util.Tools", tinymce.util.Tools);
91
+ defineGlobal("global!tinymce.util.Delay", tinymce.util.Delay);
92
+ /**
93
+ * Canvas.js
94
+ *
95
+ * Released under LGPL License.
96
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
97
+ *
98
+ * License: http://www.tinymce.com/license
99
+ * Contributing: http://www.tinymce.com/contributing
100
+ */
101
+
102
+ /**
103
+ * Contains various canvas functions.
104
+ */
105
+ define("ephox/imagetools/util/Canvas", [], function() {
106
+ function create(width, height) {
107
+ return resize(document.createElement('canvas'), width, height);
108
+ }
109
+
110
+ function get2dContext(canvas) {
111
+ return canvas.getContext("2d");
112
+ }
113
+
114
+ function get3dContext(canvas) {
115
+ var gl = null;
116
+ try {
117
+ gl = canvas.getContext("webgl") || canvas.getContext("experimental-webgl");
118
+ }
119
+ catch(e) {}
120
+
121
+ if (!gl) { // it seems that sometimes it doesn't throw exception, but still fails to get context
122
+ gl = null;
123
+ }
124
+ return gl;
125
+ }
126
+
127
+ function resize(canvas, width, height) {
128
+ canvas.width = width;
129
+ canvas.height = height;
130
+
131
+ return canvas;
132
+ }
133
+
134
+ return {
135
+ create: create,
136
+ resize: resize,
137
+ get2dContext: get2dContext,
138
+ get3dContext: get3dContext
139
+ };
140
+ });
141
+ /**
142
+ * ImageSize.js
143
+ *
144
+ * Released under LGPL License.
145
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
146
+ *
147
+ * License: http://www.tinymce.com/license
148
+ * Contributing: http://www.tinymce.com/contributing
149
+ */
150
+
151
+ /**
152
+ * Returns the size of images.
153
+ */
154
+ define("ephox/imagetools/util/ImageSize", [], function() {
155
+ function getWidth(image) {
156
+ return image.naturalWidth || image.width;
157
+ }
158
+
159
+ function getHeight(image) {
160
+ return image.naturalHeight || image.height;
161
+ }
162
+
163
+ return {
164
+ getWidth: getWidth,
165
+ getHeight: getHeight
166
+ };
167
+ });
168
+ /**
169
+ * Promise.js
170
+ *
171
+ * Released under LGPL License.
172
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
173
+ *
174
+ * Promise polyfill under MIT license: https://github.com/taylorhakes/promise-polyfill
175
+ *
176
+ * License: http://www.tinymce.com/license
177
+ * Contributing: http://www.tinymce.com/contributing
178
+ */
179
+
180
+ /* eslint-disable */
181
+ /* jshint ignore:start */
182
+
183
+ /**
184
+ * Modifed to be a feature fill and wrapped as tinymce module.
185
+ */
186
+ define("ephox/imagetools/util/Promise", [], function() {
187
+ if (window.Promise) {
188
+ return window.Promise;
189
+ }
190
+
191
+ // Use polyfill for setImmediate for performance gains
192
+ var asap = Promise.immediateFn || (typeof setImmediate === 'function' && setImmediate) ||
193
+ function(fn) { setTimeout(fn, 1); };
194
+
195
+ // Polyfill for Function.prototype.bind
196
+ function bind(fn, thisArg) {
197
+ return function() {
198
+ fn.apply(thisArg, arguments);
199
+ };
200
+ }
201
+
202
+ var isArray = Array.isArray || function(value) { return Object.prototype.toString.call(value) === "[object Array]"; };
203
+
204
+ function Promise(fn) {
205
+ if (typeof this !== 'object') throw new TypeError('Promises must be constructed via new');
206
+ if (typeof fn !== 'function') throw new TypeError('not a function');
207
+ this._state = null;
208
+ this._value = null;
209
+ this._deferreds = [];
210
+
211
+ doResolve(fn, bind(resolve, this), bind(reject, this));
212
+ }
213
+
214
+ function handle(deferred) {
215
+ var me = this;
216
+ if (this._state === null) {
217
+ this._deferreds.push(deferred);
218
+ return;
219
+ }
220
+ asap(function() {
221
+ var cb = me._state ? deferred.onFulfilled : deferred.onRejected;
222
+ if (cb === null) {
223
+ (me._state ? deferred.resolve : deferred.reject)(me._value);
224
+ return;
225
+ }
226
+ var ret;
227
+ try {
228
+ ret = cb(me._value);
229
+ }
230
+ catch (e) {
231
+ deferred.reject(e);
232
+ return;
233
+ }
234
+ deferred.resolve(ret);
235
+ });
236
+ }
237
+
238
+ function resolve(newValue) {
239
+ try { //Promise Resolution Procedure: https://github.com/promises-aplus/promises-spec#the-promise-resolution-procedure
240
+ if (newValue === this) throw new TypeError('A promise cannot be resolved with itself.');
241
+ if (newValue && (typeof newValue === 'object' || typeof newValue === 'function')) {
242
+ var then = newValue.then;
243
+ if (typeof then === 'function') {
244
+ doResolve(bind(then, newValue), bind(resolve, this), bind(reject, this));
245
+ return;
246
+ }
247
+ }
248
+ this._state = true;
249
+ this._value = newValue;
250
+ finale.call(this);
251
+ } catch (e) { reject.call(this, e); }
252
+ }
253
+
254
+ function reject(newValue) {
255
+ this._state = false;
256
+ this._value = newValue;
257
+ finale.call(this);
258
+ }
259
+
260
+ function finale() {
261
+ for (var i = 0, len = this._deferreds.length; i < len; i++) {
262
+ handle.call(this, this._deferreds[i]);
263
+ }
264
+ this._deferreds = null;
265
+ }
266
+
267
+ function Handler(onFulfilled, onRejected, resolve, reject){
268
+ this.onFulfilled = typeof onFulfilled === 'function' ? onFulfilled : null;
269
+ this.onRejected = typeof onRejected === 'function' ? onRejected : null;
270
+ this.resolve = resolve;
271
+ this.reject = reject;
272
+ }
273
+
274
+ /**
275
+ * Take a potentially misbehaving resolver function and make sure
276
+ * onFulfilled and onRejected are only called once.
277
+ *
278
+ * Makes no guarantees about asynchrony.
279
+ */
280
+ function doResolve(fn, onFulfilled, onRejected) {
281
+ var done = false;
282
+ try {
283
+ fn(function (value) {
284
+ if (done) return;
285
+ done = true;
286
+ onFulfilled(value);
287
+ }, function (reason) {
288
+ if (done) return;
289
+ done = true;
290
+ onRejected(reason);
291
+ });
292
+ } catch (ex) {
293
+ if (done) return;
294
+ done = true;
295
+ onRejected(ex);
296
+ }
297
+ }
298
+
299
+ Promise.prototype['catch'] = function (onRejected) {
300
+ return this.then(null, onRejected);
301
+ };
302
+
303
+ Promise.prototype.then = function(onFulfilled, onRejected) {
304
+ var me = this;
305
+ return new Promise(function(resolve, reject) {
306
+ handle.call(me, new Handler(onFulfilled, onRejected, resolve, reject));
307
+ });
308
+ };
309
+
310
+ Promise.all = function () {
311
+ var args = Array.prototype.slice.call(arguments.length === 1 && isArray(arguments[0]) ? arguments[0] : arguments);
312
+
313
+ return new Promise(function (resolve, reject) {
314
+ if (args.length === 0) return resolve([]);
315
+ var remaining = args.length;
316
+ function res(i, val) {
317
+ try {
318
+ if (val && (typeof val === 'object' || typeof val === 'function')) {
319
+ var then = val.then;
320
+ if (typeof then === 'function') {
321
+ then.call(val, function (val) { res(i, val); }, reject);
322
+ return;
323
+ }
324
+ }
325
+ args[i] = val;
326
+ if (--remaining === 0) {
327
+ resolve(args);
328
+ }
329
+ } catch (ex) {
330
+ reject(ex);
331
+ }
332
+ }
333
+ for (var i = 0; i < args.length; i++) {
334
+ res(i, args[i]);
335
+ }
336
+ });
337
+ };
338
+
339
+ Promise.resolve = function (value) {
340
+ if (value && typeof value === 'object' && value.constructor === Promise) {
341
+ return value;
342
+ }
343
+
344
+ return new Promise(function (resolve) {
345
+ resolve(value);
346
+ });
347
+ };
348
+
349
+ Promise.reject = function (value) {
350
+ return new Promise(function (resolve, reject) {
351
+ reject(value);
352
+ });
353
+ };
354
+
355
+ Promise.race = function (values) {
356
+ return new Promise(function (resolve, reject) {
357
+ for(var i = 0, len = values.length; i < len; i++) {
358
+ values[i].then(resolve, reject);
359
+ }
360
+ });
361
+ };
362
+
363
+ return Promise;
364
+ });
365
+
366
+ /* jshint ignore:end */
367
+ /* eslint-enable */
368
+ /**
369
+ * Mime.js
370
+ *
371
+ * Released under LGPL License.
372
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
373
+ *
374
+ * License: http://www.tinymce.com/license
375
+ * Contributing: http://www.tinymce.com/contributing
376
+ */
377
+
378
+ /**
379
+ * Returns mime types for uris.
380
+ */
381
+ define("ephox/imagetools/util/Mime", [], function() {
382
+ function getUriPathName(uri) {
383
+ var a = document.createElement('a');
384
+
385
+ a.href = uri;
386
+
387
+ return a.pathname;
388
+ }
389
+
390
+ function guessMimeType(uri) {
391
+ var parts = getUriPathName(uri).split('.'),
392
+ ext = parts[parts.length - 1],
393
+ mimes = {
394
+ 'jpg': 'image/jpeg',
395
+ 'jpeg': 'image/jpeg',
396
+ 'png': 'image/png'
397
+ };
398
+
399
+ if (ext) {
400
+ ext = ext.toLowerCase();
401
+ }
402
+
403
+ return mimes[ext];
404
+ }
405
+
406
+ return {
407
+ guessMimeType: guessMimeType
408
+ };
409
+ });
410
+ /**
411
+ * Conversions.js
412
+ *
413
+ * Released under LGPL License.
414
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
415
+ *
416
+ * License: http://www.tinymce.com/license
417
+ * Contributing: http://www.tinymce.com/contributing
418
+ */
419
+
420
+ /**
421
+ * Converts blob/uris/images back and forth.
422
+ */
423
+ define("ephox/imagetools/util/Conversions", [
424
+ "ephox/imagetools/util/Promise",
425
+ "ephox/imagetools/util/Canvas",
426
+ "ephox/imagetools/util/Mime",
427
+ "ephox/imagetools/util/ImageSize"
428
+ ], function(Promise, Canvas, Mime, ImageSize) {
429
+ function loadImage(image) {
430
+ return new Promise(function(resolve) {
431
+ function loaded() {
432
+ image.removeEventListener('load', loaded);
433
+ resolve(image);
434
+ }
435
+
436
+ if (image.complete) {
437
+ resolve(image);
438
+ } else {
439
+ image.addEventListener('load', loaded);
440
+ }
441
+ });
442
+ }
443
+
444
+ function imageToCanvas(image) {
445
+ return loadImage(image).then(function(image) {
446
+ var context, canvas;
447
+
448
+ canvas = Canvas.create(ImageSize.getWidth(image), ImageSize.getHeight(image));
449
+ context = Canvas.get2dContext(canvas);
450
+ context.drawImage(image, 0, 0);
451
+
452
+ return canvas;
453
+ });
454
+ }
455
+
456
+ function imageToBlob(image) {
457
+ return loadImage(image).then(function(image) {
458
+ var src = image.src;
459
+
460
+ if (src.indexOf('blob:') === 0) {
461
+ return blobUriToBlob(src);
462
+ }
463
+
464
+ if (src.indexOf('data:') === 0) {
465
+ return dataUriToBlob(src);
466
+ }
467
+
468
+ return imageToCanvas(image).then(function(canvas) {
469
+ return dataUriToBlob(canvas.toDataURL(Mime.guessMimeType(src)));
470
+ });
471
+ });
472
+ }
473
+
474
+ function blobToImage(blob) {
475
+ return new Promise(function(resolve) {
476
+ var image = new Image();
477
+
478
+ function loaded() {
479
+ image.removeEventListener('load', loaded);
480
+ resolve(image);
481
+ }
482
+
483
+ image.addEventListener('load', loaded);
484
+ image.src = URL.createObjectURL(blob);
485
+
486
+ if (image.complete) {
487
+ loaded();
488
+ }
489
+ });
490
+ }
491
+
492
+ function blobUriToBlob(url) {
493
+ return new Promise(function(resolve) {
494
+ var xhr = new XMLHttpRequest();
495
+
496
+ xhr.open('GET', url, true);
497
+ xhr.responseType = 'blob';
498
+
499
+ xhr.onload = function() {
500
+ if (this.status == 200) {
501
+ resolve(this.response);
502
+ }
503
+ };
504
+
505
+ xhr.send();
506
+ });
507
+ }
508
+
509
+ function dataUriToBlob(uri) {
510
+ return new Promise(function(resolve) {
511
+ var str, arr, i, matches, type, blobBuilder;
512
+
513
+ uri = uri.split(',');
514
+
515
+ matches = /data:([^;]+)/.exec(uri[0]);
516
+ if (matches) {
517
+ type = matches[1];
518
+ }
519
+
520
+ str = atob(uri[1]);
521
+
522
+ if (window.WebKitBlobBuilder) {
523
+ /*globals WebKitBlobBuilder:false */
524
+ blobBuilder = new WebKitBlobBuilder();
525
+
526
+ arr = new ArrayBuffer(str.length);
527
+ for (i = 0; i < arr.length; i++) {
528
+ arr[i] = str.charCodeAt(i);
529
+ }
530
+
531
+ blobBuilder.append(arr);
532
+
533
+ resolve(blobBuilder.getBlob(type));
534
+ return;
535
+ }
536
+
537
+ arr = new Uint8Array(str.length);
538
+
539
+ for (i = 0; i < arr.length; i++) {
540
+ arr[i] = str.charCodeAt(i);
541
+ }
542
+
543
+ resolve(new Blob([arr], {type: type}));
544
+ });
545
+ }
546
+
547
+ function uriToBlob(url) {
548
+ if (url.indexOf('blob:') === 0) {
549
+ return blobUriToBlob(url);
550
+ }
551
+
552
+ if (url.indexOf('data:') === 0) {
553
+ return dataUriToBlob(url);
554
+ }
555
+
556
+ return null;
557
+ }
558
+
559
+ function canvasToBlob(canvas, type) {
560
+ return dataUriToBlob(canvas.toDataURL(type));
561
+ }
562
+
563
+ function blobToDataUri(blob) {
564
+ return new Promise(function(resolve) {
565
+ var reader = new FileReader();
566
+
567
+ reader.onloadend = function() {
568
+ resolve(reader.result);
569
+ };
570
+
571
+ reader.readAsDataURL(blob);
572
+ });
573
+ }
574
+
575
+ function blobToBase64(blob) {
576
+ return blobToDataUri(blob).then(function(dataUri) {
577
+ return dataUri.split(',')[1];
578
+ });
579
+ }
580
+
581
+ function revokeImageUrl(image) {
582
+ URL.revokeObjectURL(image.src);
583
+ }
584
+
585
+ return {
586
+ // used outside
587
+ blobToImage: blobToImage,
588
+ // used outside
589
+ imageToBlob: imageToBlob,
590
+ // used outside
591
+ blobToDataUri: blobToDataUri,
592
+ // used outside
593
+ blobToBase64: blobToBase64,
594
+
595
+ // helper method
596
+ imageToCanvas: imageToCanvas,
597
+
598
+ // helper method
599
+ canvasToBlob: canvasToBlob,
600
+
601
+ // helper method
602
+ revokeImageUrl: revokeImageUrl,
603
+
604
+ // helper method
605
+ uriToBlob: uriToBlob
606
+
607
+ };
608
+ });
609
+ /**
610
+ * ImageTools.js
611
+ *
612
+ * Released under LGPL License.
613
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
614
+ *
615
+ * License: http://www.tinymce.com/license
616
+ * Contributing: http://www.tinymce.com/contributing
617
+ *
618
+ * Some of the matrix calculations and constants are from the EaselJS library released under MIT:
619
+ * https://github.com/CreateJS/EaselJS/blob/master/src/easeljs/filters/ColorMatrix.js
620
+ */
621
+
622
+ /**
623
+ * Various operations for color matrices.
624
+ */
625
+ define("ephox/imagetools/transformations/ColorMatrix", [], function() {
626
+ function clamp(value, min, max) {
627
+ value = parseFloat(value);
628
+
629
+ if (value > max) {
630
+ value = max;
631
+ } else if (value < min) {
632
+ value = min;
633
+ }
634
+
635
+ return value;
636
+ }
637
+
638
+ function identity() {
639
+ return [
640
+ 1, 0, 0, 0, 0,
641
+ 0, 1, 0, 0, 0,
642
+ 0, 0, 1, 0, 0,
643
+ 0, 0, 0, 1, 0,
644
+ 0, 0, 0, 0, 1
645
+ ];
646
+ }
647
+
648
+ var DELTA_INDEX = [
649
+ 0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11,
650
+ 0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
651
+ 0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
652
+ 0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68,
653
+ 0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
654
+ 1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
655
+ 1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25,
656
+ 2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8,
657
+ 4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0,
658
+ 7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8,
659
+ 10.0
660
+ ];
661
+
662
+ function multiply(matrix1, matrix2) {
663
+ var i, j, k, val, col = [], out = new Array(10);
664
+
665
+ for (i = 0; i < 5; i++) {
666
+ for (j = 0; j < 5; j++) {
667
+ col[j] = matrix2[j + i * 5];
668
+ }
669
+
670
+ for (j = 0; j < 5; j++) {
671
+ val = 0;
672
+
673
+ for (k = 0; k < 5; k++) {
674
+ val += matrix1[j + k * 5] * col[k];
675
+ }
676
+
677
+ out[j + i * 5] = val;
678
+ }
679
+ }
680
+
681
+ return out;
682
+ }
683
+
684
+ function adjust(matrix, adjustValue) {
685
+ adjustValue = clamp(adjustValue, 0, 1);
686
+
687
+ return matrix.map(function(value, index) {
688
+ if (index % 6 === 0) {
689
+ value = 1.0 - ((1 - value) * adjustValue);
690
+ } else {
691
+ value *= adjustValue;
692
+ }
693
+
694
+ return clamp(value, 0, 1);
695
+ });
696
+ }
697
+
698
+ function adjustContrast(matrix, value) {
699
+ var x;
700
+
701
+ value = clamp(value, -1, 1);
702
+ value *= 100;
703
+
704
+ if (value < 0) {
705
+ x = 127 + value / 100 * 127;
706
+ } else {
707
+ x = value % 1;
708
+
709
+ if (x === 0) {
710
+ x = DELTA_INDEX[value];
711
+ } else {
712
+ // use linear interpolation for more granularity.
713
+ x = DELTA_INDEX[(Math.floor(value))] * (1 - x) + DELTA_INDEX[(Math.floor(value)) + 1] * x;
714
+ }
715
+
716
+ x = x * 127 + 127;
717
+ }
718
+
719
+ return multiply(matrix, [
720
+ x / 127, 0, 0, 0, 0.5 * (127 - x),
721
+ 0, x / 127, 0, 0, 0.5 * (127 - x),
722
+ 0, 0, x / 127, 0, 0.5 * (127 - x),
723
+ 0, 0, 0, 1, 0,
724
+ 0, 0, 0, 0, 1
725
+ ]);
726
+ }
727
+
728
+ function adjustSaturation(matrix, value) {
729
+ var x, lumR, lumG, lumB;
730
+
731
+ value = clamp(value, -1, 1);
732
+ x = 1 + ((value > 0) ? 3 * value : value);
733
+ lumR = 0.3086;
734
+ lumG = 0.6094;
735
+ lumB = 0.0820;
736
+
737
+ return multiply(matrix, [
738
+ lumR * (1 - x) + x, lumG * (1 - x), lumB * (1 - x), 0, 0,
739
+ lumR * (1 - x), lumG * (1 - x) + x, lumB * (1 - x), 0, 0,
740
+ lumR * (1 - x), lumG * (1 - x), lumB * (1 - x) + x, 0, 0,
741
+ 0, 0, 0, 1, 0,
742
+ 0, 0, 0, 0, 1
743
+ ]);
744
+ }
745
+
746
+ function adjustHue(matrix, angle) {
747
+ var cosVal, sinVal, lumR, lumG, lumB;
748
+
749
+ angle = clamp(angle, -180, 180) / 180 * Math.PI;
750
+ cosVal = Math.cos(angle);
751
+ sinVal = Math.sin(angle);
752
+ lumR = 0.213;
753
+ lumG = 0.715;
754
+ lumB = 0.072;
755
+
756
+ return multiply(matrix, [
757
+ lumR + cosVal * (1 - lumR) + sinVal * (-lumR), lumG + cosVal * (-lumG) + sinVal * (-lumG),
758
+ lumB + cosVal * (-lumB) + sinVal * (1 - lumB), 0, 0,
759
+ lumR + cosVal * (-lumR) + sinVal * (0.143), lumG + cosVal * (1 - lumG) + sinVal * (0.140),
760
+ lumB + cosVal * (-lumB) + sinVal * (-0.283), 0, 0,
761
+ lumR + cosVal * (-lumR) + sinVal * (-(1 - lumR)), lumG + cosVal * (-lumG) + sinVal * (lumG),
762
+ lumB + cosVal * (1 - lumB) + sinVal * (lumB), 0, 0,
763
+ 0, 0, 0, 1, 0,
764
+ 0, 0, 0, 0, 1
765
+ ]);
766
+ }
767
+
768
+ function adjustBrightness(matrix, value) {
769
+ value = clamp(255 * value, -255, 255);
770
+
771
+ return multiply(matrix, [
772
+ 1, 0, 0, 0, value,
773
+ 0, 1, 0, 0, value,
774
+ 0, 0, 1, 0, value,
775
+ 0, 0, 0, 1, 0,
776
+ 0, 0, 0, 0, 1
777
+ ]);
778
+ }
779
+
780
+ function adjustColors(matrix, adjustR, adjustG, adjustB) {
781
+ adjustR = clamp(adjustR, 0, 2);
782
+ adjustG = clamp(adjustG, 0, 2);
783
+ adjustB = clamp(adjustB, 0, 2);
784
+
785
+ return multiply(matrix, [
786
+ adjustR, 0, 0, 0, 0,
787
+ 0, adjustG, 0, 0, 0,
788
+ 0, 0, adjustB, 0, 0,
789
+ 0, 0, 0, 1, 0,
790
+ 0, 0, 0, 0, 1
791
+ ]);
792
+ }
793
+
794
+ function adjustSepia(matrix, value) {
795
+ value = clamp(value, 0, 1);
796
+
797
+ return multiply(matrix, adjust([
798
+ 0.393, 0.769, 0.189, 0, 0,
799
+ 0.349, 0.686, 0.168, 0, 0,
800
+ 0.272, 0.534, 0.131, 0, 0,
801
+ 0, 0, 0, 1, 0,
802
+ 0, 0, 0, 0, 1
803
+ ], value));
804
+ }
805
+
806
+ function adjustGrayscale(matrix, value) {
807
+ value = clamp(value, 0, 1);
808
+
809
+ return multiply(matrix, adjust([
810
+ 0.33, 0.34, 0.33, 0, 0,
811
+ 0.33, 0.34, 0.33, 0, 0,
812
+ 0.33, 0.34, 0.33, 0, 0,
813
+ 0, 0, 0, 1, 0,
814
+ 0, 0, 0, 0, 1
815
+ ], value));
816
+ }
817
+
818
+ return {
819
+ identity: identity,
820
+ adjust: adjust,
821
+ multiply: multiply,
822
+ adjustContrast: adjustContrast,
823
+ adjustBrightness: adjustBrightness,
824
+ adjustSaturation: adjustSaturation,
825
+ adjustHue: adjustHue,
826
+ adjustColors: adjustColors,
827
+ adjustSepia: adjustSepia,
828
+ adjustGrayscale: adjustGrayscale
829
+ };
830
+ });
831
+ /**
832
+ * Filters.js
833
+ *
834
+ * Released under LGPL License.
835
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
836
+ *
837
+ * License: http://www.tinymce.com/license
838
+ * Contributing: http://www.tinymce.com/contributing
839
+ */
840
+
841
+ /**
842
+ * Applies various filters to blobs.
843
+ */
844
+ define("ephox/imagetools/transformations/Filters", [
845
+ "ephox/imagetools/util/Canvas",
846
+ "ephox/imagetools/util/ImageSize",
847
+ "ephox/imagetools/util/Conversions",
848
+ "ephox/imagetools/transformations/ColorMatrix"
849
+ ], function(Canvas, ImageSize, Conversions, ColorMatrix) {
850
+ var revokeImageUrl = Conversions.revokeImageUrl;
851
+
852
+ function colorFilter(blob, matrix) {
853
+ return Conversions.blobToImage(blob).then(function(image) {
854
+ var canvas = Canvas.create(ImageSize.getWidth(image), ImageSize.getHeight(image)),
855
+ context = Canvas.get2dContext(canvas),
856
+ pixels;
857
+
858
+ function applyMatrix(pixels, m) {
859
+ var d = pixels.data, r, g, b, a, i,
860
+ m0 = m[0], m1 = m[1], m2 = m[2], m3 = m[3], m4 = m[4],
861
+ m5 = m[5], m6 = m[6], m7 = m[7], m8 = m[8], m9 = m[9],
862
+ m10 = m[10], m11 = m[11], m12 = m[12], m13 = m[13], m14 = m[14],
863
+ m15 = m[15], m16 = m[16], m17 = m[17], m18 = m[18], m19 = m[19];
864
+
865
+ for (i = 0; i < d.length; i += 4) {
866
+ r = d[i];
867
+ g = d[i + 1];
868
+ b = d[i + 2];
869
+ a = d[i + 3];
870
+
871
+ d[i] = r * m0 + g * m1 + b * m2 + a * m3 + m4;
872
+ d[i + 1] = r * m5 + g * m6 + b * m7 + a * m8 + m9;
873
+ d[i + 2] = r * m10 + g * m11 + b * m12 + a * m13 + m14;
874
+ d[i + 3] = r * m15 + g * m16 + b * m17 + a * m18 + m19;
875
+ }
876
+
877
+ return pixels;
878
+ }
879
+
880
+ context.drawImage(image, 0, 0);
881
+ revokeImageUrl(image);
882
+ pixels = applyMatrix(context.getImageData(0, 0, canvas.width, canvas.height), matrix);
883
+ context.putImageData(pixels, 0, 0);
884
+
885
+ return Conversions.canvasToBlob(canvas);
886
+ });
887
+ }
888
+
889
+ function convoluteFilter(blob, matrix) {
890
+ return Conversions.blobToImage(blob).then(function(image) {
891
+ var canvas = Canvas.create(ImageSize.getWidth(image), ImageSize.getHeight(image)),
892
+ context = Canvas.get2dContext(canvas),
893
+ pixelsIn, pixelsOut;
894
+
895
+ function applyMatrix(pixelsIn, pixelsOut, matrix) {
896
+ var rgba, drgba, side, halfSide, x, y, r, g, b,
897
+ cx, cy, scx, scy, offset, wt, w, h;
898
+
899
+ function clamp(value, min, max) {
900
+ if (value > max) {
901
+ value = max;
902
+ } else if (value < min) {
903
+ value = min;
904
+ }
905
+
906
+ return value;
907
+ }
908
+
909
+ // Calc side and half side of matrix
910
+ side = Math.round(Math.sqrt(matrix.length));
911
+ halfSide = Math.floor(side / 2);
912
+ rgba = pixelsIn.data;
913
+ drgba = pixelsOut.data;
914
+ w = pixelsIn.width;
915
+ h = pixelsIn.height;
916
+
917
+ // Apply convolution matrix to pixels
918
+ for (y = 0; y < h; y++) {
919
+ for (x = 0; x < w; x++) {
920
+ r = g = b = 0;
921
+
922
+ for (cy = 0; cy < side; cy++) {
923
+ for (cx = 0; cx < side; cx++) {
924
+ // Calc relative x, y based on matrix
925
+ scx = clamp(x + cx - halfSide, 0, w - 1);
926
+ scy = clamp(y + cy - halfSide, 0, h - 1);
927
+
928
+ // Calc r, g, b
929
+ offset = (scy * w + scx) * 4;
930
+ wt = matrix[cy * side + cx];
931
+ r += rgba[offset] * wt;
932
+ g += rgba[offset + 1] * wt;
933
+ b += rgba[offset + 2] * wt;
934
+ }
935
+ }
936
+
937
+ // Set new RGB to destination buffer
938
+ offset = (y * w + x) * 4;
939
+ drgba[offset] = clamp(r, 0, 255);
940
+ drgba[offset + 1] = clamp(g, 0, 255);
941
+ drgba[offset + 2] = clamp(b, 0, 255);
942
+ }
943
+ }
944
+
945
+ return pixelsOut;
946
+ }
947
+
948
+ context.drawImage(image, 0, 0);
949
+ revokeImageUrl(image);
950
+ pixelsIn = context.getImageData(0, 0, canvas.width, canvas.height);
951
+ pixelsOut = context.getImageData(0, 0, canvas.width, canvas.height);
952
+ pixelsOut = applyMatrix(pixelsIn, pixelsOut, matrix);
953
+ context.putImageData(pixelsOut, 0, 0);
954
+
955
+ return Conversions.canvasToBlob(canvas);
956
+ });
957
+ }
958
+
959
+ function functionColorFilter(colorFn) {
960
+ return function(blob, value) {
961
+ return Conversions.blobToImage(blob).then(function(image) {
962
+ var canvas = Canvas.create(ImageSize.getWidth(image), ImageSize.getHeight(image)),
963
+ context = Canvas.get2dContext(canvas),
964
+ pixels, i, lookup = new Array(256);
965
+
966
+ function applyLookup(pixels, lookup) {
967
+ var d = pixels.data, i;
968
+
969
+ for (i = 0; i < d.length; i += 4) {
970
+ d[i] = lookup[d[i]];
971
+ d[i + 1] = lookup[d[i + 1]];
972
+ d[i + 2] = lookup[d[i + 2]];
973
+ }
974
+
975
+ return pixels;
976
+ }
977
+
978
+ for (i = 0; i < lookup.length; i++) {
979
+ lookup[i] = colorFn(i, value);
980
+ }
981
+
982
+ context.drawImage(image, 0, 0);
983
+ revokeImageUrl(image);
984
+ pixels = applyLookup(context.getImageData(0, 0, canvas.width, canvas.height), lookup);
985
+ context.putImageData(pixels, 0, 0);
986
+
987
+ return Conversions.canvasToBlob(canvas);
988
+ });
989
+ };
990
+ }
991
+
992
+ function complexAdjustableColorFilter(matrixAdjustFn) {
993
+ return function(blob, adjust) {
994
+ return colorFilter(blob, matrixAdjustFn(ColorMatrix.identity(), adjust));
995
+ };
996
+ }
997
+
998
+ function basicColorFilter(matrix) {
999
+ return function(blob) {
1000
+ return colorFilter(blob, matrix);
1001
+ };
1002
+ }
1003
+
1004
+ function basicConvolutionFilter(kernel) {
1005
+ return function(blob) {
1006
+ return convoluteFilter(blob, kernel);
1007
+ };
1008
+ }
1009
+
1010
+ return {
1011
+ invert: basicColorFilter([
1012
+ -1, 0, 0, 0, 255,
1013
+ 0, -1, 0, 0, 255,
1014
+ 0, 0, -1, 0, 255,
1015
+ 0, 0, 0, 1, 0
1016
+ ]),
1017
+
1018
+ brightness: complexAdjustableColorFilter(ColorMatrix.adjustBrightness),
1019
+ hue: complexAdjustableColorFilter(ColorMatrix.adjustHue),
1020
+ saturate: complexAdjustableColorFilter(ColorMatrix.adjustSaturation),
1021
+ contrast: complexAdjustableColorFilter(ColorMatrix.adjustContrast),
1022
+ grayscale: complexAdjustableColorFilter(ColorMatrix.adjustGrayscale),
1023
+ sepia: complexAdjustableColorFilter(ColorMatrix.adjustSepia),
1024
+ colorize: function(blob, adjustR, adjustG, adjustB) {
1025
+ return colorFilter(blob, ColorMatrix.adjustColors(ColorMatrix.identity(), adjustR, adjustG, adjustB));
1026
+ },
1027
+
1028
+ sharpen: basicConvolutionFilter([
1029
+ 0, -1, 0,
1030
+ -1, 5, -1,
1031
+ 0, -1, 0
1032
+ ]),
1033
+
1034
+ emboss: basicConvolutionFilter([
1035
+ -2, -1, 0,
1036
+ -1, 1, 1,
1037
+ 0, 1, 2
1038
+ ]),
1039
+
1040
+ gamma: functionColorFilter(function(color, value) {
1041
+ return Math.pow(color / 255, 1 - value) * 255;
1042
+ }),
1043
+
1044
+ exposure: functionColorFilter(function(color, value) {
1045
+ return 255 * (1 - Math.exp(-(color / 255) * value));
1046
+ }),
1047
+
1048
+ colorFilter: colorFilter,
1049
+ convoluteFilter: convoluteFilter
1050
+ };
1051
+ });
1052
+ /**
1053
+ * ImageResizerCanvas.js
1054
+ *
1055
+ * Released under LGPL License.
1056
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
1057
+ *
1058
+ * License: http://www.tinymce.com/license
1059
+ * Contributing: http://www.tinymce.com/contributing
1060
+ */
1061
+
1062
+ /**
1063
+ * Resizes image/canvas using canvas
1064
+ */
1065
+ define("ephox/imagetools/transformations/ImageResizerCanvas", [
1066
+ "ephox/imagetools/util/Promise",
1067
+ "ephox/imagetools/util/Conversions",
1068
+ "ephox/imagetools/util/Canvas",
1069
+ "ephox/imagetools/util/ImageSize"
1070
+ ], function(Promise, Conversions, Canvas, ImageSize) {
1071
+
1072
+ /**
1073
+ * @method scale
1074
+ * @static
1075
+ * @param image {Image|Canvas}
1076
+ * @param dW {Number} Width that the image should be scaled to
1077
+ * @param dH {Number} Height that the image should be scaled to
1078
+ * @returns {Promise}
1079
+ */
1080
+ function scale(image, dW, dH) {
1081
+ var sW = ImageSize.getWidth(image);
1082
+ var sH = ImageSize.getHeight(image);
1083
+ var wRatio = dW / sW;
1084
+ var hRatio = dH / sH;
1085
+ var scaleCapped = false;
1086
+
1087
+ if (wRatio < 0.5 || wRatio > 2) {
1088
+ wRatio = wRatio < 0.5 ? 0.5 : 2;
1089
+ scaleCapped = true;
1090
+ }
1091
+ if (hRatio < 0.5 || hRatio > 2) {
1092
+ hRatio = hRatio < 0.5 ? 0.5 : 2;
1093
+ scaleCapped = true;
1094
+ }
1095
+
1096
+ var scaled = _scale(image, wRatio, hRatio);
1097
+
1098
+ return !scaleCapped ? scaled : scaled.then(function (tCanvas) {
1099
+ return scale(tCanvas, dW, dH);
1100
+ });
1101
+ }
1102
+
1103
+
1104
+ function _scale(image, wRatio, hRatio) {
1105
+ return new Promise(function(resolve) {
1106
+ var sW = ImageSize.getWidth(image);
1107
+ var sH = ImageSize.getHeight(image);
1108
+ var dW = Math.floor(sW * wRatio);
1109
+ var dH = Math.floor(sH * hRatio);
1110
+ var canvas = Canvas.create(dW, dH);
1111
+ var context = Canvas.get2dContext(canvas);
1112
+
1113
+ context.drawImage(image, 0, 0, sW, sH, 0, 0, dW, dH);
1114
+
1115
+ resolve(canvas);
1116
+ });
1117
+ }
1118
+
1119
+ return {
1120
+ scale: scale
1121
+ };
1122
+
1123
+ });
1124
+
1125
+ /**
1126
+ * ImageTools.js
1127
+ *
1128
+ * Released under LGPL License.
1129
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
1130
+ *
1131
+ * License: http://www.tinymce.com/license
1132
+ * Contributing: http://www.tinymce.com/contributing
1133
+ */
1134
+
1135
+ /**
1136
+ * Modifies image blobs.
1137
+ */
1138
+ define("ephox/imagetools/transformations/ImageTools", [
1139
+ "ephox/imagetools/util/Conversions",
1140
+ "ephox/imagetools/util/Canvas",
1141
+ "ephox/imagetools/util/ImageSize",
1142
+ "ephox/imagetools/transformations/ImageResizerCanvas"
1143
+ ], function(Conversions, Canvas, ImageSize, ImageResizerCanvas) {
1144
+ var revokeImageUrl = Conversions.revokeImageUrl;
1145
+
1146
+ function rotate(blob, angle) {
1147
+ return Conversions.blobToImage(blob).then(function(image) {
1148
+ var canvas = Canvas.create(ImageSize.getWidth(image), ImageSize.getHeight(image)),
1149
+ context = Canvas.get2dContext(canvas),
1150
+ translateX = 0, translateY = 0;
1151
+
1152
+ angle = angle < 0 ? 360 + angle : angle;
1153
+
1154
+ if (angle == 90 || angle == 270) {
1155
+ Canvas.resize(canvas, canvas.height, canvas.width);
1156
+ }
1157
+
1158
+ if (angle == 90 || angle == 180) {
1159
+ translateX = canvas.width;
1160
+ }
1161
+
1162
+ if (angle == 270 || angle == 180) {
1163
+ translateY = canvas.height;
1164
+ }
1165
+
1166
+ context.translate(translateX, translateY);
1167
+ context.rotate(angle * Math.PI / 180);
1168
+ context.drawImage(image, 0, 0);
1169
+ revokeImageUrl(image);
1170
+
1171
+ return Conversions.canvasToBlob(canvas, blob.type);
1172
+ });
1173
+ }
1174
+
1175
+ function flip(blob, axis) {
1176
+ return Conversions.blobToImage(blob).then(function(image) {
1177
+ var canvas = Canvas.create(ImageSize.getWidth(image), ImageSize.getHeight(image)),
1178
+ context = Canvas.get2dContext(canvas);
1179
+
1180
+ if (axis == 'v') {
1181
+ context.scale(1, -1);
1182
+ context.drawImage(image, 0, -canvas.height);
1183
+ } else {
1184
+ context.scale(-1, 1);
1185
+ context.drawImage(image, -canvas.width, 0);
1186
+ }
1187
+
1188
+ revokeImageUrl(image);
1189
+
1190
+ return Conversions.canvasToBlob(canvas);
1191
+ });
1192
+ }
1193
+
1194
+ function crop(blob, x, y, w, h) {
1195
+ return Conversions.blobToImage(blob).then(function(image) {
1196
+ var canvas = Canvas.create(w, h),
1197
+ context = Canvas.get2dContext(canvas);
1198
+
1199
+ context.drawImage(image, -x, -y);
1200
+ revokeImageUrl(image);
1201
+
1202
+ return Conversions.canvasToBlob(canvas);
1203
+ });
1204
+ }
1205
+
1206
+ var revokeImage = function (image) {
1207
+ return function (result) {
1208
+ revokeImageUrl(image);
1209
+ return result;
1210
+ };
1211
+ };
1212
+
1213
+ function resize(blob, w, h) {
1214
+ return Conversions.blobToImage(blob).then(function(image) {
1215
+ var result;
1216
+
1217
+ result = ImageResizerCanvas.scale(image, w, h)
1218
+ .then(function(canvas) {
1219
+ return Conversions.canvasToBlob(canvas, blob.type);
1220
+ })
1221
+ .then(revokeImage(image))
1222
+ .catch(revokeImage(image));
1223
+
1224
+ return result;
1225
+ });
1226
+ }
1227
+
1228
+ return {
1229
+ rotate: rotate,
1230
+ flip: flip,
1231
+ crop: crop,
1232
+ resize: resize
1233
+ };
1234
+ });
1235
+
1236
+ define(
1237
+ 'ephox/imagetools/api/ImageTransformations',
1238
+
1239
+ [
1240
+ 'ephox/imagetools/transformations/Filters',
1241
+ 'ephox/imagetools/transformations/ImageTools'
1242
+ ],
1243
+
1244
+ function (Filters, ImageTools) {
1245
+ var invert = function (blob) {
1246
+ return Filters.invert(blob);
1247
+ };
1248
+
1249
+ var sharpen = function (blob) {
1250
+ return Filters.sharpen(blob);
1251
+ };
1252
+
1253
+ var emboss = function (blob) {
1254
+ return Filters.emboss(blob);
1255
+ };
1256
+
1257
+ var gamma = function (blob, value) {
1258
+ return Filters.gamma(blob, value);
1259
+ };
1260
+
1261
+ var exposure = function (blob, value) {
1262
+ return Filters.exposure(blob, value);
1263
+ };
1264
+
1265
+ var colorize = function (blob, adjustR, adjustG, adjustB) {
1266
+ return Filters.colorize(blob, adjustR, adjustG, adjustB);
1267
+ };
1268
+
1269
+ var brightness = function (blob, adjust) {
1270
+ return Filters.brightness(blob, adjust);
1271
+ };
1272
+
1273
+ var hue = function (blob, adjust) {
1274
+ return Filters.hue(blob, adjust);
1275
+ };
1276
+
1277
+ var saturate = function (blob, adjust) {
1278
+ return Filters.saturate(blob, adjust);
1279
+ };
1280
+
1281
+ var contrast = function (blob, adjust) {
1282
+ return Filters.contrast(blob, adjust);
1283
+ };
1284
+
1285
+ var grayscale = function (blob, adjust) {
1286
+ return Filters.grayscale(blob, adjust);
1287
+ };
1288
+
1289
+ var sepia = function (blob, adjust) {
1290
+ return Filters.sepia(blob, adjust);
1291
+ };
1292
+
1293
+ var flip = function (blob, axis) {
1294
+ return ImageTools.flip(blob, axis);
1295
+ };
1296
+
1297
+ var crop = function (blob, x, y, w, h) {
1298
+ return ImageTools.crop(blob, x, y, w, h);
1299
+ };
1300
+
1301
+ var resize = function (blob, w, h) {
1302
+ return ImageTools.resize(blob, w, h);
1303
+ };
1304
+
1305
+ var rotate = function (blob, angle) {
1306
+ return ImageTools.rotate(blob, angle);
1307
+ };
1308
+
1309
+ return {
1310
+ invert: invert,
1311
+ sharpen: sharpen,
1312
+ emboss: emboss,
1313
+ brightness: brightness,
1314
+ hue: hue,
1315
+ saturate: saturate,
1316
+ contrast: contrast,
1317
+ grayscale: grayscale,
1318
+ sepia: sepia,
1319
+ colorize: colorize,
1320
+ gamma: gamma,
1321
+ exposure: exposure,
1322
+
1323
+ flip: flip,
1324
+ crop: crop,
1325
+ resize: resize,
1326
+ rotate: rotate
1327
+ };
1328
+ }
1329
+ );
1330
+ define(
1331
+ 'ephox/imagetools/api/BlobConversions',
1332
+
1333
+ [
1334
+ 'ephox/imagetools/util/Conversions'
1335
+ ],
1336
+
1337
+ function (Conversions) {
1338
+ var blobToImage = function (image) {
1339
+ return Conversions.blobToImage(image);
1340
+ };
1341
+
1342
+ var imageToBlob = function (blob) {
1343
+ return Conversions.imageToBlob(blob);
1344
+ };
1345
+
1346
+ var blobToDataUri = function (blob) {
1347
+ return Conversions.blobToDataUri(blob);
1348
+ };
1349
+
1350
+ var blobToBase64 = function (blob) {
1351
+ return Conversions.blobToBase64(blob);
1352
+ };
1353
+
1354
+ return {
1355
+ // used outside
1356
+ blobToImage: blobToImage,
1357
+ // used outside
1358
+ imageToBlob: imageToBlob,
1359
+ // used outside
1360
+ blobToDataUri: blobToDataUri,
1361
+ // used outside
1362
+ blobToBase64: blobToBase64
1363
+ };
1364
+ }
1365
+ );
1366
+ defineGlobal("global!tinymce.dom.DOMUtils", tinymce.dom.DOMUtils);
1367
+ defineGlobal("global!tinymce.ui.Factory", tinymce.ui.Factory);
1368
+ defineGlobal("global!tinymce.ui.Form", tinymce.ui.Form);
1369
+ defineGlobal("global!tinymce.ui.Container", tinymce.ui.Container);
1370
+ defineGlobal("global!tinymce.ui.Control", tinymce.ui.Control);
1371
+ defineGlobal("global!tinymce.ui.DragHelper", tinymce.ui.DragHelper);
1372
+ defineGlobal("global!tinymce.geom.Rect", tinymce.geom.Rect);
1373
+ defineGlobal("global!tinymce.dom.DomQuery", tinymce.dom.DomQuery);
1374
+ defineGlobal("global!tinymce.util.Observable", tinymce.util.Observable);
1375
+ defineGlobal("global!tinymce.util.VK", tinymce.util.VK);
1376
+ /**
1377
+ * CropRect.js
1378
+ *
1379
+ * Released under LGPL License.
1380
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1381
+ *
1382
+ * License: http://www.tinymce.com/license
1383
+ * Contributing: http://www.tinymce.com/contributing
1384
+ */
1385
+
1386
+ /**
1387
+ * ...
1388
+ */
1389
+ define("tinymce/imagetoolsplugin/CropRect", [
1390
+ "global!tinymce.dom.DomQuery",
1391
+ "global!tinymce.ui.DragHelper",
1392
+ "global!tinymce.geom.Rect",
1393
+ "global!tinymce.util.Tools",
1394
+ "global!tinymce.util.Observable",
1395
+ "global!tinymce.util.VK"
1396
+ ], function($, DragHelper, Rect, Tools, Observable, VK) {
1397
+ var count = 0;
1398
+
1399
+ return function(currentRect, viewPortRect, clampRect, containerElm, action) {
1400
+ var instance, handles, dragHelpers, blockers, prefix = 'mce-', id = prefix + 'crid-' + (count++);
1401
+
1402
+ handles = [
1403
+ {name: 'move', xMul: 0, yMul: 0, deltaX: 1, deltaY: 1, deltaW: 0, deltaH: 0, label: 'Crop Mask'},
1404
+ {name: 'nw', xMul: 0, yMul: 0, deltaX: 1, deltaY: 1, deltaW: -1, deltaH: -1, label: 'Top Left Crop Handle'},
1405
+ {name: 'ne', xMul: 1, yMul: 0, deltaX: 0, deltaY: 1, deltaW: 1, deltaH: -1, label: 'Top Right Crop Handle'},
1406
+ {name: 'sw', xMul: 0, yMul: 1, deltaX: 1, deltaY: 0, deltaW: -1, deltaH: 1, label: 'Bottom Left Crop Handle'},
1407
+ {name: 'se', xMul: 1, yMul: 1, deltaX: 0, deltaY: 0, deltaW: 1, deltaH: 1, label: 'Bottom Right Crop Handle'}
1408
+ ];
1409
+
1410
+ blockers = ["top", "right", "bottom", "left"];
1411
+
1412
+ function getAbsoluteRect(outerRect, relativeRect) {
1413
+ return {
1414
+ x: relativeRect.x + outerRect.x,
1415
+ y: relativeRect.y + outerRect.y,
1416
+ w: relativeRect.w,
1417
+ h: relativeRect.h
1418
+ };
1419
+ }
1420
+
1421
+ function getRelativeRect(outerRect, innerRect) {
1422
+ return {
1423
+ x: innerRect.x - outerRect.x,
1424
+ y: innerRect.y - outerRect.y,
1425
+ w: innerRect.w,
1426
+ h: innerRect.h
1427
+ };
1428
+ }
1429
+
1430
+ function getInnerRect() {
1431
+ return getRelativeRect(clampRect, currentRect);
1432
+ }
1433
+
1434
+ function moveRect(handle, startRect, deltaX, deltaY) {
1435
+ var x, y, w, h, rect;
1436
+
1437
+ x = startRect.x;
1438
+ y = startRect.y;
1439
+ w = startRect.w;
1440
+ h = startRect.h;
1441
+
1442
+ x += deltaX * handle.deltaX;
1443
+ y += deltaY * handle.deltaY;
1444
+ w += deltaX * handle.deltaW;
1445
+ h += deltaY * handle.deltaH;
1446
+
1447
+ if (w < 20) {
1448
+ w = 20;
1449
+ }
1450
+
1451
+ if (h < 20) {
1452
+ h = 20;
1453
+ }
1454
+
1455
+ rect = currentRect = Rect.clamp({x: x, y: y, w: w, h: h}, clampRect, handle.name == 'move');
1456
+ rect = getRelativeRect(clampRect, rect);
1457
+
1458
+ instance.fire('updateRect', {rect: rect});
1459
+ setInnerRect(rect);
1460
+ }
1461
+
1462
+ function render() {
1463
+ function createDragHelper(handle) {
1464
+ var startRect;
1465
+
1466
+ return new DragHelper(id, {
1467
+ document: containerElm.ownerDocument,
1468
+ handle: id + '-' + handle.name,
1469
+
1470
+ start: function() {
1471
+ startRect = currentRect;
1472
+ },
1473
+
1474
+ drag: function(e) {
1475
+ moveRect(handle, startRect, e.deltaX, e.deltaY);
1476
+ }
1477
+ });
1478
+ }
1479
+
1480
+ $(
1481
+ '<div id="' + id + '" class="' + prefix + 'croprect-container"' +
1482
+ ' role="grid" aria-dropeffect="execute">'
1483
+ ).appendTo(containerElm);
1484
+
1485
+ Tools.each(blockers, function(blocker) {
1486
+ $('#' + id, containerElm).append(
1487
+ '<div id="' + id + '-' + blocker + '"class="' + prefix + 'croprect-block" style="display: none" data-mce-bogus="all">'
1488
+ );
1489
+ });
1490
+
1491
+ Tools.each(handles, function(handle) {
1492
+ $('#' + id, containerElm).append(
1493
+ '<div id="' + id + '-' + handle.name + '" class="' + prefix +
1494
+ 'croprect-handle ' + prefix + 'croprect-handle-' + handle.name + '"' +
1495
+ 'style="display: none" data-mce-bogus="all" role="gridcell" tabindex="-1"' +
1496
+ ' aria-label="' + handle.label + '" aria-grabbed="false">'
1497
+ );
1498
+ });
1499
+
1500
+ dragHelpers = Tools.map(handles, createDragHelper);
1501
+
1502
+ repaint(currentRect);
1503
+
1504
+ $(containerElm).on('focusin focusout', function(e) {
1505
+ $(e.target).attr('aria-grabbed', e.type === 'focus');
1506
+ });
1507
+
1508
+ $(containerElm).on('keydown', function(e) {
1509
+ var activeHandle;
1510
+
1511
+ Tools.each(handles, function(handle) {
1512
+ if (e.target.id == id + '-' + handle.name) {
1513
+ activeHandle = handle;
1514
+ return false;
1515
+ }
1516
+ });
1517
+
1518
+ function moveAndBlock(evt, handle, startRect, deltaX, deltaY) {
1519
+ evt.stopPropagation();
1520
+ evt.preventDefault();
1521
+
1522
+ moveRect(activeHandle, startRect, deltaX, deltaY);
1523
+ }
1524
+
1525
+ switch (e.keyCode) {
1526
+ case VK.LEFT:
1527
+ moveAndBlock(e, activeHandle, currentRect, -10, 0);
1528
+ break;
1529
+
1530
+ case VK.RIGHT:
1531
+ moveAndBlock(e, activeHandle, currentRect, 10, 0);
1532
+ break;
1533
+
1534
+ case VK.UP:
1535
+ moveAndBlock(e, activeHandle, currentRect, 0, -10);
1536
+ break;
1537
+
1538
+ case VK.DOWN:
1539
+ moveAndBlock(e, activeHandle, currentRect, 0, 10);
1540
+ break;
1541
+
1542
+ case VK.ENTER:
1543
+ case VK.SPACEBAR:
1544
+ e.preventDefault();
1545
+ action();
1546
+ break;
1547
+ }
1548
+ });
1549
+ }
1550
+
1551
+ function toggleVisibility(state) {
1552
+ var selectors;
1553
+
1554
+ selectors = Tools.map(handles, function(handle) {
1555
+ return '#' + id + '-' + handle.name;
1556
+ }).concat(Tools.map(blockers, function(blocker) {
1557
+ return '#' + id + '-' + blocker;
1558
+ })).join(',');
1559
+
1560
+ if (state) {
1561
+ $(selectors, containerElm).show();
1562
+ } else {
1563
+ $(selectors, containerElm).hide();
1564
+ }
1565
+ }
1566
+
1567
+ function repaint(rect) {
1568
+ function updateElementRect(name, rect) {
1569
+ if (rect.h < 0) {
1570
+ rect.h = 0;
1571
+ }
1572
+
1573
+ if (rect.w < 0) {
1574
+ rect.w = 0;
1575
+ }
1576
+
1577
+ $('#' + id + '-' + name, containerElm).css({
1578
+ left: rect.x,
1579
+ top: rect.y,
1580
+ width: rect.w,
1581
+ height: rect.h
1582
+ });
1583
+ }
1584
+
1585
+ Tools.each(handles, function(handle) {
1586
+ $('#' + id + '-' + handle.name, containerElm).css({
1587
+ left: rect.w * handle.xMul + rect.x,
1588
+ top: rect.h * handle.yMul + rect.y
1589
+ });
1590
+ });
1591
+
1592
+ updateElementRect('top', {x: viewPortRect.x, y: viewPortRect.y, w: viewPortRect.w, h: rect.y - viewPortRect.y});
1593
+ updateElementRect('right', {x: rect.x + rect.w, y: rect.y, w: viewPortRect.w - rect.x - rect.w + viewPortRect.x, h: rect.h});
1594
+ updateElementRect('bottom', {
1595
+ x: viewPortRect.x,
1596
+ y: rect.y + rect.h,
1597
+ w: viewPortRect.w,
1598
+ h: viewPortRect.h - rect.y - rect.h + viewPortRect.y
1599
+ });
1600
+ updateElementRect('left', {x: viewPortRect.x, y: rect.y, w: rect.x - viewPortRect.x, h: rect.h});
1601
+ updateElementRect('move', rect);
1602
+ }
1603
+
1604
+ function setRect(rect) {
1605
+ currentRect = rect;
1606
+ repaint(currentRect);
1607
+ }
1608
+
1609
+ function setViewPortRect(rect) {
1610
+ viewPortRect = rect;
1611
+ repaint(currentRect);
1612
+ }
1613
+
1614
+ function setInnerRect(rect) {
1615
+ setRect(getAbsoluteRect(clampRect, rect));
1616
+ }
1617
+
1618
+ function setClampRect(rect) {
1619
+ clampRect = rect;
1620
+ repaint(currentRect);
1621
+ }
1622
+
1623
+ function destroy() {
1624
+ Tools.each(dragHelpers, function(helper) {
1625
+ helper.destroy();
1626
+ });
1627
+
1628
+ dragHelpers = [];
1629
+ }
1630
+
1631
+ render(containerElm);
1632
+
1633
+ instance = Tools.extend({
1634
+ toggleVisibility: toggleVisibility,
1635
+ setClampRect: setClampRect,
1636
+ setRect: setRect,
1637
+ getInnerRect: getInnerRect,
1638
+ setInnerRect: setInnerRect,
1639
+ setViewPortRect: setViewPortRect,
1640
+ destroy: destroy
1641
+ }, Observable);
1642
+
1643
+ return instance;
1644
+ };
1645
+ });
1646
+
1647
+ /**
1648
+ * ImagePanel.js
1649
+ *
1650
+ * Released under LGPL License.
1651
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1652
+ *
1653
+ * License: http://www.tinymce.com/license
1654
+ * Contributing: http://www.tinymce.com/contributing
1655
+ */
1656
+
1657
+ /**
1658
+ * ...
1659
+ *
1660
+ * @-x-less ImagePanel.less
1661
+ */
1662
+ define("tinymce/imagetoolsplugin/ImagePanel", [
1663
+ "global!tinymce.ui.Control",
1664
+ "global!tinymce.ui.DragHelper",
1665
+ "global!tinymce.geom.Rect",
1666
+ "global!tinymce.util.Tools",
1667
+ "global!tinymce.util.Promise",
1668
+ "tinymce/imagetoolsplugin/CropRect"
1669
+ ], function(Control, DragHelper, Rect, Tools, Promise, CropRect) {
1670
+ function loadImage(image) {
1671
+ return new Promise(function(resolve) {
1672
+ function loaded() {
1673
+ image.removeEventListener('load', loaded);
1674
+ resolve(image);
1675
+ }
1676
+
1677
+ if (image.complete) {
1678
+ resolve(image);
1679
+ } else {
1680
+ image.addEventListener('load', loaded);
1681
+ }
1682
+ });
1683
+ }
1684
+
1685
+ return Control.extend({
1686
+ Defaults: {
1687
+ classes: "imagepanel"
1688
+ },
1689
+
1690
+ selection: function(rect) {
1691
+ if (arguments.length) {
1692
+ this.state.set('rect', rect);
1693
+ return this;
1694
+ }
1695
+
1696
+ return this.state.get('rect');
1697
+ },
1698
+
1699
+ imageSize: function() {
1700
+ var viewRect = this.state.get('viewRect');
1701
+
1702
+ return {
1703
+ w: viewRect.w,
1704
+ h: viewRect.h
1705
+ };
1706
+ },
1707
+
1708
+ toggleCropRect: function(state) {
1709
+ this.state.set('cropEnabled', state);
1710
+ },
1711
+
1712
+ imageSrc: function(url) {
1713
+ var self = this, img = new Image();
1714
+
1715
+ img.src = url;
1716
+
1717
+ loadImage(img).then(function() {
1718
+ var rect, $img, lastRect = self.state.get('viewRect');
1719
+
1720
+ $img = self.$el.find('img');
1721
+ if ($img[0]) {
1722
+ $img.replaceWith(img);
1723
+ } else {
1724
+ self.getEl().appendChild(img);
1725
+ }
1726
+
1727
+ rect = {x: 0, y: 0, w: img.naturalWidth, h: img.naturalHeight};
1728
+ self.state.set('viewRect', rect);
1729
+ self.state.set('rect', Rect.inflate(rect, -20, -20));
1730
+
1731
+ if (!lastRect || lastRect.w != rect.w || lastRect.h != rect.h) {
1732
+ self.zoomFit();
1733
+ }
1734
+
1735
+ self.repaintImage();
1736
+ self.fire('load');
1737
+ });
1738
+ },
1739
+
1740
+ zoom: function(value) {
1741
+ if (arguments.length) {
1742
+ this.state.set('zoom', value);
1743
+ return this;
1744
+ }
1745
+
1746
+ return this.state.get('zoom');
1747
+ },
1748
+
1749
+ postRender: function() {
1750
+ this.imageSrc(this.settings.imageSrc);
1751
+ return this._super();
1752
+ },
1753
+
1754
+ zoomFit: function() {
1755
+ var self = this, $img, pw, ph, w, h, zoom, padding;
1756
+
1757
+ padding = 10;
1758
+ $img = self.$el.find('img');
1759
+ pw = self.getEl().clientWidth;
1760
+ ph = self.getEl().clientHeight;
1761
+ w = $img[0].naturalWidth;
1762
+ h = $img[0].naturalHeight;
1763
+ zoom = Math.min((pw - padding) / w, (ph - padding) / h);
1764
+
1765
+ if (zoom >= 1) {
1766
+ zoom = 1;
1767
+ }
1768
+
1769
+ self.zoom(zoom);
1770
+ },
1771
+
1772
+ repaintImage: function() {
1773
+ var x, y, w, h, pw, ph, $img, zoom, rect, elm;
1774
+
1775
+ elm = this.getEl();
1776
+ zoom = this.zoom();
1777
+ rect = this.state.get('rect');
1778
+ $img = this.$el.find('img');
1779
+ pw = elm.offsetWidth;
1780
+ ph = elm.offsetHeight;
1781
+ w = $img[0].naturalWidth * zoom;
1782
+ h = $img[0].naturalHeight * zoom;
1783
+ x = Math.max(0, pw / 2 - w / 2);
1784
+ y = Math.max(0, ph / 2 - h / 2);
1785
+
1786
+ $img.css({
1787
+ left: x,
1788
+ top: y,
1789
+ width: w,
1790
+ height: h
1791
+ });
1792
+
1793
+ if (this.cropRect) {
1794
+ this.cropRect.setRect({
1795
+ x: rect.x * zoom + x,
1796
+ y: rect.y * zoom + y,
1797
+ w: rect.w * zoom,
1798
+ h: rect.h * zoom
1799
+ });
1800
+
1801
+ this.cropRect.setClampRect({
1802
+ x: x,
1803
+ y: y,
1804
+ w: w,
1805
+ h: h
1806
+ });
1807
+
1808
+ this.cropRect.setViewPortRect({
1809
+ x: 0,
1810
+ y: 0,
1811
+ w: pw,
1812
+ h: ph
1813
+ });
1814
+ }
1815
+ },
1816
+
1817
+ bindStates: function() {
1818
+ var self = this;
1819
+
1820
+ function setupCropRect(rect) {
1821
+ self.cropRect = new CropRect(
1822
+ rect,
1823
+ self.state.get('viewRect'),
1824
+ self.state.get('viewRect'),
1825
+ self.getEl(),
1826
+ function() {
1827
+ self.fire('crop');
1828
+ }
1829
+ );
1830
+
1831
+ self.cropRect.on('updateRect', function(e) {
1832
+ var rect = e.rect, zoom = self.zoom();
1833
+
1834
+ rect = {
1835
+ x: Math.round(rect.x / zoom),
1836
+ y: Math.round(rect.y / zoom),
1837
+ w: Math.round(rect.w / zoom),
1838
+ h: Math.round(rect.h / zoom)
1839
+ };
1840
+
1841
+ self.state.set('rect', rect);
1842
+ });
1843
+
1844
+ self.on('remove', self.cropRect.destroy);
1845
+ }
1846
+
1847
+ self.state.on('change:cropEnabled', function(e) {
1848
+ self.cropRect.toggleVisibility(e.value);
1849
+ self.repaintImage();
1850
+ });
1851
+
1852
+ self.state.on('change:zoom', function() {
1853
+ self.repaintImage();
1854
+ });
1855
+
1856
+ self.state.on('change:rect', function(e) {
1857
+ var rect = e.value;
1858
+
1859
+ if (!self.cropRect) {
1860
+ setupCropRect(rect);
1861
+ }
1862
+
1863
+ self.cropRect.setRect(rect);
1864
+ });
1865
+ }
1866
+ });
1867
+ });
1868
+
1869
+ /**
1870
+ * UndoStack.js
1871
+ *
1872
+ * Released under LGPL License.
1873
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1874
+ *
1875
+ * License: http://www.tinymce.com/license
1876
+ * Contributing: http://www.tinymce.com/contributing
1877
+ */
1878
+
1879
+ define("tinymce/imagetoolsplugin/UndoStack", [
1880
+ ], function() {
1881
+ return function() {
1882
+ var data = [], index = -1;
1883
+
1884
+ function add(state) {
1885
+ var removed;
1886
+
1887
+ removed = data.splice(++index);
1888
+ data.push(state);
1889
+
1890
+ return {
1891
+ state: state,
1892
+ removed: removed
1893
+ };
1894
+ }
1895
+
1896
+ function undo() {
1897
+ if (canUndo()) {
1898
+ return data[--index];
1899
+ }
1900
+ }
1901
+
1902
+ function redo() {
1903
+ if (canRedo()) {
1904
+ return data[++index];
1905
+ }
1906
+ }
1907
+
1908
+ function canUndo() {
1909
+ return index > 0;
1910
+ }
1911
+
1912
+ function canRedo() {
1913
+ return index != -1 && index < data.length - 1;
1914
+ }
1915
+
1916
+ return {
1917
+ data: data,
1918
+ add: add,
1919
+ undo: undo,
1920
+ redo: redo,
1921
+ canUndo: canUndo,
1922
+ canRedo: canRedo
1923
+ };
1924
+ };
1925
+ });
1926
+
1927
+ /**
1928
+ * Dialog.js
1929
+ *
1930
+ * Released under LGPL License.
1931
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
1932
+ *
1933
+ * License: http://www.tinymce.com/license
1934
+ * Contributing: http://www.tinymce.com/contributing
1935
+ */
1936
+
1937
+ /**
1938
+ * ...
1939
+ */
1940
+ define("tinymce/imagetoolsplugin/Dialog", [
1941
+ "global!tinymce.dom.DOMUtils",
1942
+ "global!tinymce.util.Tools",
1943
+ "global!tinymce.util.Promise",
1944
+ "global!tinymce.ui.Factory",
1945
+ "global!tinymce.ui.Form",
1946
+ "global!tinymce.ui.Container",
1947
+ "tinymce/imagetoolsplugin/ImagePanel",
1948
+ "ephox/imagetools/api/ImageTransformations",
1949
+ "ephox/imagetools/api/BlobConversions",
1950
+ "tinymce/imagetoolsplugin/UndoStack"
1951
+ ], function(DOMUtils, Tools, Promise, Factory, Form, Container, ImagePanel, ImageTransformations, BlobConversions, UndoStack) {
1952
+ function createState(blob) {
1953
+ return {
1954
+ blob: blob,
1955
+ url: URL.createObjectURL(blob)
1956
+ };
1957
+ }
1958
+
1959
+ function destroyState(state) {
1960
+ if (state) {
1961
+ URL.revokeObjectURL(state.url);
1962
+ }
1963
+ }
1964
+
1965
+ function destroyStates(states) {
1966
+ Tools.each(states, destroyState);
1967
+ }
1968
+
1969
+ function open(currentState, resolve, reject) {
1970
+ var win, undoStack = new UndoStack(), mainPanel, filtersPanel, tempState,
1971
+ cropPanel, resizePanel, flipRotatePanel, imagePanel, sidePanel, mainViewContainer,
1972
+ invertPanel, brightnessPanel, huePanel, saturatePanel, contrastPanel, grayscalePanel,
1973
+ sepiaPanel, colorizePanel, sharpenPanel, embossPanel, gammaPanel, exposurePanel, panels,
1974
+ width, height, ratioW, ratioH;
1975
+
1976
+ function recalcSize(e) {
1977
+ var widthCtrl, heightCtrl, newWidth, newHeight;
1978
+
1979
+ widthCtrl = win.find('#w')[0];
1980
+ heightCtrl = win.find('#h')[0];
1981
+
1982
+ newWidth = parseInt(widthCtrl.value(), 10);
1983
+ newHeight = parseInt(heightCtrl.value(), 10);
1984
+
1985
+ if (win.find('#constrain')[0].checked() && width && height && newWidth && newHeight) {
1986
+ if (e.control.settings.name == 'w') {
1987
+ newHeight = Math.round(newWidth * ratioW);
1988
+ heightCtrl.value(newHeight);
1989
+ } else {
1990
+ newWidth = Math.round(newHeight * ratioH);
1991
+ widthCtrl.value(newWidth);
1992
+ }
1993
+ }
1994
+
1995
+ width = newWidth;
1996
+ height = newHeight;
1997
+ }
1998
+
1999
+ function floatToPercent(value) {
2000
+ return Math.round(value * 100) + '%';
2001
+ }
2002
+
2003
+ function updateButtonUndoStates() {
2004
+ win.find('#undo').disabled(!undoStack.canUndo());
2005
+ win.find('#redo').disabled(!undoStack.canRedo());
2006
+ win.statusbar.find('#save').disabled(!undoStack.canUndo());
2007
+ }
2008
+
2009
+ function disableUndoRedo() {
2010
+ win.find('#undo').disabled(true);
2011
+ win.find('#redo').disabled(true);
2012
+ }
2013
+
2014
+ function displayState(state) {
2015
+ if (state) {
2016
+ imagePanel.imageSrc(state.url);
2017
+ }
2018
+ }
2019
+
2020
+ function switchPanel(targetPanel) {
2021
+ return function() {
2022
+ var hidePanels = Tools.grep(panels, function(panel) {
2023
+ return panel.settings.name != targetPanel;
2024
+ });
2025
+
2026
+ Tools.each(hidePanels, function(panel) {
2027
+ panel.hide();
2028
+ });
2029
+
2030
+ targetPanel.show();
2031
+ targetPanel.focus();
2032
+ };
2033
+ }
2034
+
2035
+ function addTempState(blob) {
2036
+ tempState = createState(blob);
2037
+ displayState(tempState);
2038
+ }
2039
+
2040
+ function addBlobState(blob) {
2041
+ currentState = createState(blob);
2042
+ displayState(currentState);
2043
+ destroyStates(undoStack.add(currentState).removed);
2044
+ updateButtonUndoStates();
2045
+ }
2046
+
2047
+ function crop() {
2048
+ var rect = imagePanel.selection();
2049
+
2050
+ ImageTransformations.crop(currentState.blob, rect.x, rect.y, rect.w, rect.h).then(function(blob) {
2051
+ addBlobState(blob);
2052
+ cancel();
2053
+ });
2054
+ }
2055
+
2056
+ function tempAction(fn) {
2057
+ var args = [].slice.call(arguments, 1);
2058
+
2059
+ return function() {
2060
+ var state = tempState || currentState;
2061
+
2062
+ fn.apply(this, [state.blob].concat(args)).then(addTempState);
2063
+ };
2064
+ }
2065
+
2066
+ function action(fn) {
2067
+ var args = [].slice.call(arguments, 1);
2068
+
2069
+ return function() {
2070
+ fn.apply(this, [currentState.blob].concat(args)).then(addBlobState);
2071
+ };
2072
+ }
2073
+
2074
+ function cancel() {
2075
+ displayState(currentState);
2076
+ destroyState(tempState);
2077
+ switchPanel(mainPanel)();
2078
+ updateButtonUndoStates();
2079
+ }
2080
+
2081
+ function applyTempState() {
2082
+ if (tempState) {
2083
+ addBlobState(tempState.blob);
2084
+ cancel();
2085
+ }
2086
+ }
2087
+
2088
+ function zoomIn() {
2089
+ var zoom = imagePanel.zoom();
2090
+
2091
+ if (zoom < 2) {
2092
+ zoom += 0.1;
2093
+ }
2094
+
2095
+ imagePanel.zoom(zoom);
2096
+ }
2097
+
2098
+ function zoomOut() {
2099
+ var zoom = imagePanel.zoom();
2100
+
2101
+ if (zoom > 0.1) {
2102
+ zoom -= 0.1;
2103
+ }
2104
+
2105
+ imagePanel.zoom(zoom);
2106
+ }
2107
+
2108
+ function undo() {
2109
+ currentState = undoStack.undo();
2110
+ displayState(currentState);
2111
+ updateButtonUndoStates();
2112
+ }
2113
+
2114
+ function redo() {
2115
+ currentState = undoStack.redo();
2116
+ displayState(currentState);
2117
+ updateButtonUndoStates();
2118
+ }
2119
+
2120
+ function save() {
2121
+ resolve(currentState.blob);
2122
+ win.close();
2123
+ }
2124
+
2125
+ function createPanel(items) {
2126
+ return new Form({
2127
+ layout: 'flex',
2128
+ direction: 'row',
2129
+ labelGap: 5,
2130
+ border: '0 0 1 0',
2131
+ align: 'center',
2132
+ pack: 'center',
2133
+ padding: '0 10 0 10',
2134
+ spacing: 5,
2135
+ flex: 0,
2136
+ minHeight: 60,
2137
+ defaults: {
2138
+ classes: 'imagetool',
2139
+ type: 'button'
2140
+ },
2141
+ items: items
2142
+ });
2143
+ }
2144
+
2145
+ function createFilterPanel(title, filter) {
2146
+ return createPanel([
2147
+ {text: 'Back', onclick: cancel},
2148
+ {type: 'spacer', flex: 1},
2149
+ {text: 'Apply', subtype: 'primary', onclick: applyTempState}
2150
+ ]).hide().on('show', function() {
2151
+ disableUndoRedo();
2152
+
2153
+ filter(currentState.blob).then(function(blob) {
2154
+ var newTempState = createState(blob);
2155
+
2156
+ displayState(newTempState);
2157
+ destroyState(tempState);
2158
+ tempState = newTempState;
2159
+ });
2160
+ });
2161
+ }
2162
+
2163
+ function createVariableFilterPanel(title, filter, value, min, max) {
2164
+ function update(value) {
2165
+ filter(currentState.blob, value).then(function(blob) {
2166
+ var newTempState = createState(blob);
2167
+ displayState(newTempState);
2168
+ destroyState(tempState);
2169
+ tempState = newTempState;
2170
+ });
2171
+ }
2172
+
2173
+ return createPanel([
2174
+ {text: 'Back', onclick: cancel},
2175
+ {type: 'spacer', flex: 1},
2176
+ {
2177
+ type: 'slider',
2178
+ flex: 1,
2179
+ ondragend: function(e) {
2180
+ update(e.value);
2181
+ },
2182
+ minValue: min,
2183
+ maxValue: max,
2184
+ value: value,
2185
+ previewFilter: floatToPercent
2186
+ },
2187
+ {type: 'spacer', flex: 1},
2188
+ {text: 'Apply', subtype: 'primary', onclick: applyTempState}
2189
+ ]).hide().on('show', function() {
2190
+ this.find('slider').value(value);
2191
+ disableUndoRedo();
2192
+ });
2193
+ }
2194
+
2195
+ function createRgbFilterPanel(title, filter) {
2196
+ function update() {
2197
+ var r, g, b;
2198
+
2199
+ r = win.find('#r')[0].value();
2200
+ g = win.find('#g')[0].value();
2201
+ b = win.find('#b')[0].value();
2202
+
2203
+ filter(currentState.blob, r, g, b).then(function(blob) {
2204
+ var newTempState = createState(blob);
2205
+ displayState(newTempState);
2206
+ destroyState(tempState);
2207
+ tempState = newTempState;
2208
+ });
2209
+ }
2210
+
2211
+ return createPanel([
2212
+ {text: 'Back', onclick: cancel},
2213
+ {type: 'spacer', flex: 1},
2214
+ {
2215
+ type: 'slider', label: 'R', name: 'r', minValue: 0,
2216
+ value: 1, maxValue: 2, ondragend: update, previewFilter: floatToPercent
2217
+ },
2218
+ {
2219
+ type: 'slider', label: 'G', name: 'g', minValue: 0,
2220
+ value: 1, maxValue: 2, ondragend: update, previewFilter: floatToPercent
2221
+ },
2222
+ {
2223
+ type: 'slider', label: 'B', name: 'b', minValue: 0,
2224
+ value: 1, maxValue: 2, ondragend: update, previewFilter: floatToPercent
2225
+ },
2226
+ {type: 'spacer', flex: 1},
2227
+ {text: 'Apply', subtype: 'primary', onclick: applyTempState}
2228
+ ]).hide().on('show', function() {
2229
+ win.find('#r,#g,#b').value(1);
2230
+ disableUndoRedo();
2231
+ });
2232
+ }
2233
+
2234
+ cropPanel = createPanel([
2235
+ {text: 'Back', onclick: cancel},
2236
+ {type: 'spacer', flex: 1},
2237
+ {text: 'Apply', subtype: 'primary', onclick: crop}
2238
+ ]).hide().on('show hide', function(e) {
2239
+ imagePanel.toggleCropRect(e.type == 'show');
2240
+ }).on('show', disableUndoRedo);
2241
+
2242
+ function toggleConstrain(e) {
2243
+ if (e.control.value() === true) {
2244
+ ratioW = height / width;
2245
+ ratioH = width / height;
2246
+ }
2247
+ }
2248
+
2249
+ resizePanel = createPanel([
2250
+ {text: 'Back', onclick: cancel},
2251
+ {type: 'spacer', flex: 1},
2252
+ {type: 'textbox', name: 'w', label: 'Width', size: 4, onkeyup: recalcSize},
2253
+ {type: 'textbox', name: 'h', label: 'Height', size: 4, onkeyup: recalcSize},
2254
+ {type: 'checkbox', name: 'constrain', text: 'Constrain proportions', checked: true, onchange: toggleConstrain},
2255
+ {type: 'spacer', flex: 1},
2256
+ {text: 'Apply', subtype: 'primary', onclick: 'submit'}
2257
+ ]).hide().on('submit', function(e) {
2258
+ var width = parseInt(win.find('#w').value(), 10),
2259
+ height = parseInt(win.find('#h').value(), 10);
2260
+
2261
+ e.preventDefault();
2262
+
2263
+ action(ImageTransformations.resize, width, height)();
2264
+ cancel();
2265
+ }).on('show', disableUndoRedo);
2266
+
2267
+ flipRotatePanel = createPanel([
2268
+ {text: 'Back', onclick: cancel},
2269
+ {type: 'spacer', flex: 1},
2270
+ {icon: 'fliph', tooltip: 'Flip horizontally', onclick: tempAction(ImageTransformations.flip, 'h')},
2271
+ {icon: 'flipv', tooltip: 'Flip vertically', onclick: tempAction(ImageTransformations.flip, 'v')},
2272
+ {icon: 'rotateleft', tooltip: 'Rotate counterclockwise', onclick: tempAction(ImageTransformations.rotate, -90)},
2273
+ {icon: 'rotateright', tooltip: 'Rotate clockwise', onclick: tempAction(ImageTransformations.rotate, 90)},
2274
+ {type: 'spacer', flex: 1},
2275
+ {text: 'Apply', subtype: 'primary', onclick: applyTempState}
2276
+ ]).hide().on('show', disableUndoRedo);
2277
+
2278
+ invertPanel = createFilterPanel("Invert", ImageTransformations.invert);
2279
+ sharpenPanel = createFilterPanel("Sharpen", ImageTransformations.sharpen);
2280
+ embossPanel = createFilterPanel("Emboss", ImageTransformations.emboss);
2281
+
2282
+ brightnessPanel = createVariableFilterPanel("Brightness", ImageTransformations.brightness, 0, -1, 1);
2283
+ huePanel = createVariableFilterPanel("Hue", ImageTransformations.hue, 180, 0, 360);
2284
+ saturatePanel = createVariableFilterPanel("Saturate", ImageTransformations.saturate, 0, -1, 1);
2285
+ contrastPanel = createVariableFilterPanel("Contrast", ImageTransformations.contrast, 0, -1, 1);
2286
+ grayscalePanel = createVariableFilterPanel("Grayscale", ImageTransformations.grayscale, 0, 0, 1);
2287
+ sepiaPanel = createVariableFilterPanel("Sepia", ImageTransformations.sepia, 0, 0, 1);
2288
+ colorizePanel = createRgbFilterPanel("Colorize", ImageTransformations.colorize);
2289
+ gammaPanel = createVariableFilterPanel("Gamma", ImageTransformations.gamma, 0, -1, 1);
2290
+ exposurePanel = createVariableFilterPanel("Exposure", ImageTransformations.exposure, 1, 0, 2);
2291
+
2292
+ filtersPanel = createPanel([
2293
+ {text: 'Back', onclick: cancel},
2294
+ {type: 'spacer', flex: 1},
2295
+ {text: 'hue', icon: 'hue', onclick: switchPanel(huePanel)},
2296
+ {text: 'saturate', icon: 'saturate', onclick: switchPanel(saturatePanel)},
2297
+ {text: 'sepia', icon: 'sepia', onclick: switchPanel(sepiaPanel)},
2298
+ {text: 'emboss', icon: 'emboss', onclick: switchPanel(embossPanel)},
2299
+ {text: 'exposure', icon: 'exposure', onclick: switchPanel(exposurePanel)},
2300
+ {type: 'spacer', flex: 1}
2301
+ ]).hide();
2302
+
2303
+ mainPanel = createPanel([
2304
+ {tooltip: 'Crop', icon: 'crop', onclick: switchPanel(cropPanel)},
2305
+ {tooltip: 'Resize', icon: 'resize2', onclick: switchPanel(resizePanel)},
2306
+ {tooltip: 'Orientation', icon: 'orientation', onclick: switchPanel(flipRotatePanel)},
2307
+ {tooltip: 'Brightness', icon: 'sun', onclick: switchPanel(brightnessPanel)},
2308
+ {tooltip: 'Sharpen', icon: 'sharpen', onclick: switchPanel(sharpenPanel)},
2309
+ {tooltip: 'Contrast', icon: 'contrast', onclick: switchPanel(contrastPanel)},
2310
+ {tooltip: 'Color levels', icon: 'drop', onclick: switchPanel(colorizePanel)},
2311
+ {tooltip: 'Gamma', icon: 'gamma', onclick: switchPanel(gammaPanel)},
2312
+ {tooltip: 'Invert', icon: 'invert', onclick: switchPanel(invertPanel)}
2313
+ //{text: 'More', onclick: switchPanel(filtersPanel)}
2314
+ ]);
2315
+
2316
+ imagePanel = new ImagePanel({
2317
+ flex: 1,
2318
+ imageSrc: currentState.url
2319
+ });
2320
+
2321
+ sidePanel = new Container({
2322
+ layout: 'flex',
2323
+ direction: 'column',
2324
+ border: '0 1 0 0',
2325
+ padding: 5,
2326
+ spacing: 5,
2327
+ items: [
2328
+ {type: 'button', icon: 'undo', tooltip: 'Undo', name: 'undo', onclick: undo},
2329
+ {type: 'button', icon: 'redo', tooltip: 'Redo', name: 'redo', onclick: redo},
2330
+ {type: 'button', icon: 'zoomin', tooltip: 'Zoom in', onclick: zoomIn},
2331
+ {type: 'button', icon: 'zoomout', tooltip: 'Zoom out', onclick: zoomOut}
2332
+ ]
2333
+ });
2334
+
2335
+ mainViewContainer = new Container({
2336
+ type: 'container',
2337
+ layout: 'flex',
2338
+ direction: 'row',
2339
+ align: 'stretch',
2340
+ flex: 1,
2341
+ items: [sidePanel, imagePanel]
2342
+ });
2343
+
2344
+ panels = [
2345
+ mainPanel,
2346
+ cropPanel,
2347
+ resizePanel,
2348
+ flipRotatePanel,
2349
+ filtersPanel,
2350
+ invertPanel,
2351
+ brightnessPanel,
2352
+ huePanel,
2353
+ saturatePanel,
2354
+ contrastPanel,
2355
+ grayscalePanel,
2356
+ sepiaPanel,
2357
+ colorizePanel,
2358
+ sharpenPanel,
2359
+ embossPanel,
2360
+ gammaPanel,
2361
+ exposurePanel
2362
+ ];
2363
+
2364
+ win = Factory.create('window', {
2365
+ layout: 'flex',
2366
+ direction: 'column',
2367
+ align: 'stretch',
2368
+ minWidth: Math.min(DOMUtils.DOM.getViewPort().w, 800),
2369
+ minHeight: Math.min(DOMUtils.DOM.getViewPort().h, 650),
2370
+ title: 'Edit image',
2371
+ items: panels.concat([mainViewContainer]),
2372
+ buttons: [
2373
+ {text: 'Save', name: 'save', subtype: 'primary', onclick: save},
2374
+ {text: 'Cancel', onclick: 'close'}
2375
+ ]
2376
+ });
2377
+
2378
+ win.renderTo(document.body).reflow();
2379
+
2380
+ win.on('close', function() {
2381
+ reject();
2382
+ destroyStates(undoStack.data);
2383
+ undoStack = null;
2384
+ tempState = null;
2385
+ });
2386
+
2387
+ undoStack.add(currentState);
2388
+ updateButtonUndoStates();
2389
+
2390
+ imagePanel.on('load', function() {
2391
+ width = imagePanel.imageSize().w;
2392
+ height = imagePanel.imageSize().h;
2393
+ ratioW = height / width;
2394
+ ratioH = width / height;
2395
+
2396
+ win.find('#w').value(width);
2397
+ win.find('#h').value(height);
2398
+ });
2399
+
2400
+ imagePanel.on('crop', crop);
2401
+ }
2402
+
2403
+ function edit(blob) {
2404
+ return new Promise(function(resolve, reject) {
2405
+ open(createState(blob), resolve, reject);
2406
+ });
2407
+ }
2408
+
2409
+ //edit('img/dogleft.jpg');
2410
+
2411
+ return {
2412
+ edit: edit
2413
+ };
2414
+ });
2415
+
2416
+ /**
2417
+ * ImageSize.js
2418
+ *
2419
+ * Released under LGPL License.
2420
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
2421
+ *
2422
+ * License: http://www.tinymce.com/license
2423
+ * Contributing: http://www.tinymce.com/contributing
2424
+ */
2425
+
2426
+ define("tinymce/imagetoolsplugin/ImageSize", [
2427
+ ], function() {
2428
+ function getImageSize(img) {
2429
+ var width, height;
2430
+
2431
+ function isPxValue(value) {
2432
+ return /^[0-9\.]+px$/.test(value);
2433
+ }
2434
+
2435
+ width = img.style.width;
2436
+ height = img.style.height;
2437
+ if (width || height) {
2438
+ if (isPxValue(width) && isPxValue(height)) {
2439
+ return {
2440
+ w: parseInt(width, 10),
2441
+ h: parseInt(height, 10)
2442
+ };
2443
+ }
2444
+
2445
+ return null;
2446
+ }
2447
+
2448
+ width = img.width;
2449
+ height = img.height;
2450
+
2451
+ if (width && height) {
2452
+ return {
2453
+ w: parseInt(width, 10),
2454
+ h: parseInt(height, 10)
2455
+ };
2456
+ }
2457
+
2458
+ return null;
2459
+ }
2460
+
2461
+ function setImageSize(img, size) {
2462
+ var width, height;
2463
+
2464
+ if (size) {
2465
+ width = img.style.width;
2466
+ height = img.style.height;
2467
+
2468
+ if (width || height) {
2469
+ img.style.width = size.w + 'px';
2470
+ img.style.height = size.h + 'px';
2471
+ img.removeAttribute('data-mce-style');
2472
+ }
2473
+
2474
+ width = img.width;
2475
+ height = img.height;
2476
+
2477
+ if (width || height) {
2478
+ img.setAttribute('width', size.w);
2479
+ img.setAttribute('height', size.h);
2480
+ }
2481
+ }
2482
+ }
2483
+
2484
+ function getNaturalImageSize(img) {
2485
+ return {
2486
+ w: img.naturalWidth,
2487
+ h: img.naturalHeight
2488
+ };
2489
+ }
2490
+
2491
+ return {
2492
+ getImageSize: getImageSize,
2493
+ setImageSize: setImageSize,
2494
+ getNaturalImageSize: getNaturalImageSize
2495
+ };
2496
+ });
2497
+
2498
+ /**
2499
+ * Utils.js
2500
+ *
2501
+ * Released under LGPL License.
2502
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
2503
+ *
2504
+ * License: http://www.tinymce.com/license
2505
+ * Contributing: http://www.tinymce.com/contributing
2506
+ */
2507
+
2508
+ define("tinymce/imagetoolsplugin/Utils", [
2509
+ "global!tinymce.util.Promise",
2510
+ "global!tinymce.util.Tools"
2511
+ ], function(Promise, Tools) {
2512
+ var isValue = function (obj) {
2513
+ return obj !== null && obj !== undefined;
2514
+ };
2515
+
2516
+ var traverse = function (json, path) {
2517
+ var value;
2518
+
2519
+ value = path.reduce(function(result, key) {
2520
+ return isValue(result) ? result[key] : undefined;
2521
+ }, json);
2522
+
2523
+ return isValue(value) ? value : null;
2524
+ };
2525
+
2526
+ var requestUrlAsBlob = function (url, headers) {
2527
+ return new Promise(function(resolve) {
2528
+ var xhr;
2529
+
2530
+ xhr = new XMLHttpRequest();
2531
+
2532
+ xhr.onreadystatechange = function () {
2533
+ if (xhr.readyState === 4) {
2534
+ resolve({
2535
+ status: xhr.status,
2536
+ blob: this.response
2537
+ });
2538
+ }
2539
+ };
2540
+
2541
+ xhr.open('GET', url, true);
2542
+
2543
+ Tools.each(headers, function (value, key) {
2544
+ xhr.setRequestHeader(key, value);
2545
+ });
2546
+
2547
+ xhr.responseType = 'blob';
2548
+ xhr.send();
2549
+ });
2550
+ };
2551
+
2552
+ var readBlob = function (blob) {
2553
+ return new Promise(function(resolve) {
2554
+ var fr = new FileReader();
2555
+
2556
+ fr.onload = function (e) {
2557
+ var data = e.target;
2558
+ resolve(data.result);
2559
+ };
2560
+
2561
+ fr.readAsText(blob);
2562
+ });
2563
+ };
2564
+
2565
+ var parseJson = function (text) {
2566
+ var json;
2567
+
2568
+ try {
2569
+ json = JSON.parse(text);
2570
+ } catch (ex) {
2571
+ // Ignore
2572
+ }
2573
+
2574
+ return json;
2575
+ };
2576
+
2577
+ return {
2578
+ traverse: traverse,
2579
+ readBlob: readBlob,
2580
+ requestUrlAsBlob: requestUrlAsBlob,
2581
+ parseJson: parseJson
2582
+ };
2583
+ });
2584
+
2585
+ /**
2586
+ * Proxy.js
2587
+ *
2588
+ * Released under LGPL License.
2589
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
2590
+ *
2591
+ * License: http://www.tinymce.com/license
2592
+ * Contributing: http://www.tinymce.com/contributing
2593
+ */
2594
+
2595
+ /**
2596
+ * Handles loading images though a proxy for working around cors.
2597
+ */
2598
+ define("tinymce/imagetoolsplugin/Proxy", [
2599
+ "global!tinymce.util.Promise",
2600
+ "global!tinymce.util.Tools",
2601
+ "tinymce/imagetoolsplugin/Utils"
2602
+ ], function(Promise, Tools, Utils) {
2603
+ var isServiceErrorCode = function (code) {
2604
+ return code === 400 || code === 403 || code === 500;
2605
+ };
2606
+
2607
+ var handleHttpError = function (status) {
2608
+ return Promise.reject("ImageProxy HTTP error: " + status);
2609
+ };
2610
+
2611
+ var proxyServiceError = function (error) {
2612
+ Promise.reject("ImageProxy Service error: " + error);
2613
+ };
2614
+
2615
+ var handleServiceError = function (status, blob) {
2616
+ return Utils.readBlob(blob).then(function(text) {
2617
+ var serviceError = Utils.parseJson(text);
2618
+ var errorType = Utils.traverse(serviceError, ['error', 'type']);
2619
+ return errorType ? proxyServiceError(errorType) : proxyServiceError('Invalid JSON');
2620
+ });
2621
+ };
2622
+
2623
+ var handleServiceErrorResponse = function (status, blob) {
2624
+ return isServiceErrorCode(status) ? handleServiceError(status, blob) : handleHttpError(status);
2625
+ };
2626
+
2627
+ var requestServiceBlob = function (url, apiKey) {
2628
+ return Utils.requestUrlAsBlob(url, {
2629
+ 'Content-Type': 'application/json;charset=UTF-8',
2630
+ 'tiny-api-key': apiKey
2631
+ }).then(function (result) {
2632
+ return result.status >= 400 ? handleServiceErrorResponse(result.status, result.blob) : Promise.resolve(result.blob);
2633
+ });
2634
+ };
2635
+
2636
+ function requestBlob(url) {
2637
+ return Utils.requestUrlAsBlob(url, {}).then(function (result) {
2638
+ return result.status >= 400 ? handleHttpError(result.status) : Promise.resolve(result.blob);
2639
+ });
2640
+ }
2641
+
2642
+ var getUrl = function (url, apiKey) {
2643
+ return apiKey ? requestServiceBlob(url, apiKey) : requestBlob(url);
2644
+ };
2645
+
2646
+ return {
2647
+ getUrl: getUrl
2648
+ };
2649
+ });
2650
+
2651
+ /**
2652
+ * Plugin.js
2653
+ *
2654
+ * Released under LGPL License.
2655
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
2656
+ *
2657
+ * License: http://www.tinymce.com/license
2658
+ * Contributing: http://www.tinymce.com/contributing
2659
+ */
2660
+
2661
+ /**
2662
+ *
2663
+ * Settings:
2664
+ * imagetools_cors_hosts - Array of remote domains that has CORS setup.
2665
+ * imagetools_proxy - Url to proxy that streams images from remote host to local host.
2666
+ * imagetools_toolbar - Toolbar items to render when an editable image is selected.
2667
+ */
2668
+ define("tinymce/imagetoolsplugin/Plugin", [
2669
+ "global!tinymce.PluginManager",
2670
+ "global!tinymce.Env",
2671
+ "global!tinymce.util.Promise",
2672
+ "global!tinymce.util.URI",
2673
+ "global!tinymce.util.Tools",
2674
+ "global!tinymce.util.Delay",
2675
+ "ephox/imagetools/api/ImageTransformations",
2676
+ "ephox/imagetools/api/BlobConversions",
2677
+ "tinymce/imagetoolsplugin/Dialog",
2678
+ "tinymce/imagetoolsplugin/ImageSize",
2679
+ "tinymce/imagetoolsplugin/Proxy"
2680
+ ], function(PluginManager, Env, Promise, URI, Tools, Delay, ImageTransformations, BlobConversions, Dialog, ImageSize, Proxy) {
2681
+ var plugin = function(editor) {
2682
+ var count = 0, imageUploadTimer, lastSelectedImage;
2683
+
2684
+ if (!Env.fileApi) {
2685
+ return;
2686
+ }
2687
+
2688
+ function displayError(error) {
2689
+ editor.notificationManager.open({
2690
+ text: error,
2691
+ type: 'error'
2692
+ });
2693
+ }
2694
+
2695
+ function getSelectedImage() {
2696
+ return editor.selection.getNode();
2697
+ }
2698
+
2699
+ function createId() {
2700
+ return 'imagetools' + count++;
2701
+ }
2702
+
2703
+ function isLocalImage(img) {
2704
+ var url = img.src;
2705
+
2706
+ return url.indexOf('data:') === 0 || url.indexOf('blob:') === 0 || new URI(url).host === editor.documentBaseURI.host;
2707
+ }
2708
+
2709
+ function isCorsImage(img) {
2710
+ return Tools.inArray(editor.settings.imagetools_cors_hosts, new URI(img.src).host) !== -1;
2711
+ }
2712
+
2713
+ function getApiKey() {
2714
+ return editor.settings.api_key || editor.settings.imagetools_api_key;
2715
+ }
2716
+
2717
+ function imageToBlob(img) {
2718
+ var src = img.src, apiKey;
2719
+
2720
+ if (isCorsImage(img)) {
2721
+ return Proxy.getUrl(img.src, null);
2722
+ }
2723
+
2724
+ if (!isLocalImage(img)) {
2725
+ src = editor.settings.imagetools_proxy;
2726
+ src += (src.indexOf('?') === -1 ? '?' : '&') + 'url=' + encodeURIComponent(img.src);
2727
+ apiKey = getApiKey();
2728
+ return Proxy.getUrl(src, apiKey);
2729
+ }
2730
+
2731
+ return BlobConversions.imageToBlob(img);
2732
+ }
2733
+
2734
+ function findSelectedBlob() {
2735
+ var blobInfo;
2736
+
2737
+ blobInfo = editor.editorUpload.blobCache.getByUri(getSelectedImage().src);
2738
+ if (blobInfo) {
2739
+ return blobInfo.blob();
2740
+ }
2741
+
2742
+ return imageToBlob(getSelectedImage());
2743
+ }
2744
+
2745
+ function startTimedUpload() {
2746
+ imageUploadTimer = Delay.setEditorTimeout(editor, function() {
2747
+ editor.editorUpload.uploadImagesAuto();
2748
+ }, 30000);
2749
+ }
2750
+
2751
+ function cancelTimedUpload() {
2752
+ clearTimeout(imageUploadTimer);
2753
+ }
2754
+
2755
+ function updateSelectedImage(blob, uploadImmediately) {
2756
+ return BlobConversions.blobToDataUri(blob).then(function(dataUri) {
2757
+ var id, base64, blobCache, blobInfo, selectedImage;
2758
+
2759
+ selectedImage = getSelectedImage();
2760
+ id = createId();
2761
+ blobCache = editor.editorUpload.blobCache;
2762
+ base64 = URI.parseDataUri(dataUri).data;
2763
+
2764
+ blobInfo = blobCache.create(id, blob, base64);
2765
+ blobCache.add(blobInfo);
2766
+
2767
+ editor.undoManager.transact(function() {
2768
+ function imageLoadedHandler() {
2769
+ editor.$(selectedImage).off('load', imageLoadedHandler);
2770
+ editor.nodeChanged();
2771
+
2772
+ if (uploadImmediately) {
2773
+ editor.editorUpload.uploadImagesAuto();
2774
+ } else {
2775
+ cancelTimedUpload();
2776
+ startTimedUpload();
2777
+ }
2778
+ }
2779
+
2780
+ editor.$(selectedImage).on('load', imageLoadedHandler);
2781
+
2782
+ editor.$(selectedImage).attr({
2783
+ src: blobInfo.blobUri()
2784
+ }).removeAttr('data-mce-src');
2785
+ });
2786
+
2787
+ return blobInfo;
2788
+ });
2789
+ }
2790
+
2791
+ function selectedImageOperation(fn) {
2792
+ return function() {
2793
+ return editor._scanForImages().then(findSelectedBlob).then(fn).then(updateSelectedImage, displayError);
2794
+ };
2795
+ }
2796
+
2797
+ function rotate(angle) {
2798
+ return function() {
2799
+ return selectedImageOperation(function(blob) {
2800
+ var size = ImageSize.getImageSize(getSelectedImage());
2801
+
2802
+ if (size) {
2803
+ ImageSize.setImageSize(getSelectedImage(), {
2804
+ w: size.h,
2805
+ h: size.w
2806
+ });
2807
+ }
2808
+
2809
+ return ImageTransformations.rotate(blob, angle);
2810
+ })();
2811
+ };
2812
+ }
2813
+
2814
+ function flip(axis) {
2815
+ return function() {
2816
+ return selectedImageOperation(function(blob) {
2817
+ return ImageTransformations.flip(blob, axis);
2818
+ })();
2819
+ };
2820
+ }
2821
+
2822
+ function editImageDialog() {
2823
+ var img = getSelectedImage(), originalSize = ImageSize.getNaturalImageSize(img);
2824
+ var handleDialogBlob = function(blob) {
2825
+ return new Promise(function(resolve) {
2826
+ BlobConversions.blobToImage(blob).then(function(newImage) {
2827
+ var newSize = ImageSize.getNaturalImageSize(newImage);
2828
+
2829
+ if (originalSize.w != newSize.w || originalSize.h != newSize.h) {
2830
+ if (ImageSize.getImageSize(img)) {
2831
+ ImageSize.setImageSize(img, newSize);
2832
+ }
2833
+ }
2834
+
2835
+ URL.revokeObjectURL(newImage.src);
2836
+ resolve(blob);
2837
+ });
2838
+ });
2839
+ };
2840
+
2841
+ var openDialog = function (blob) {
2842
+ return Dialog.edit(blob).then(handleDialogBlob).then(function(blob) {
2843
+ updateSelectedImage(blob, true);
2844
+ }, function () {
2845
+ // Close dialog
2846
+ });
2847
+ };
2848
+
2849
+ if (img) {
2850
+ imageToBlob(img).then(openDialog, displayError);
2851
+ }
2852
+ }
2853
+
2854
+ function addButtons() {
2855
+ editor.addButton('rotateleft', {
2856
+ title: 'Rotate counterclockwise',
2857
+ onclick: rotate(-90)
2858
+ });
2859
+
2860
+ editor.addButton('rotateright', {
2861
+ title: 'Rotate clockwise',
2862
+ onclick: rotate(90)
2863
+ });
2864
+
2865
+ editor.addButton('flipv', {
2866
+ title: 'Flip vertically',
2867
+ onclick: flip('v')
2868
+ });
2869
+
2870
+ editor.addButton('fliph', {
2871
+ title: 'Flip horizontally',
2872
+ onclick: flip('h')
2873
+ });
2874
+
2875
+ editor.addButton('editimage', {
2876
+ title: 'Edit image',
2877
+ onclick: editImageDialog
2878
+ });
2879
+
2880
+ editor.addButton('imageoptions', {
2881
+ title: 'Image options',
2882
+ icon: 'options',
2883
+ cmd: 'mceImage'
2884
+ });
2885
+
2886
+ /*
2887
+ editor.addButton('crop', {
2888
+ title: 'Crop',
2889
+ onclick: startCrop
2890
+ });
2891
+ */
2892
+ }
2893
+
2894
+ function addEvents() {
2895
+ editor.on('NodeChange', function(e) {
2896
+ //If the last node we selected was an image
2897
+ //And had a source that doesn't match the current blob url
2898
+ //We need to attempt to upload it
2899
+ if (lastSelectedImage && lastSelectedImage.src != e.element.src) {
2900
+ cancelTimedUpload();
2901
+ editor.editorUpload.uploadImagesAuto();
2902
+ lastSelectedImage = undefined;
2903
+ }
2904
+
2905
+ //Set up the lastSelectedImage
2906
+ if (isEditableImage(e.element)) {
2907
+ lastSelectedImage = e.element;
2908
+ }
2909
+ });
2910
+ }
2911
+
2912
+ function isEditableImage(img) {
2913
+ var selectorMatched = editor.dom.is(img, 'img:not([data-mce-object],[data-mce-placeholder])');
2914
+
2915
+ return selectorMatched && (isLocalImage(img) || isCorsImage(img) || editor.settings.imagetools_proxy);
2916
+ }
2917
+
2918
+ function addToolbars() {
2919
+ var toolbarItems = editor.settings.imagetools_toolbar;
2920
+
2921
+ if (!toolbarItems) {
2922
+ toolbarItems = 'rotateleft rotateright | flipv fliph | crop editimage imageoptions';
2923
+ }
2924
+
2925
+ editor.addContextToolbar(
2926
+ isEditableImage,
2927
+ toolbarItems
2928
+ );
2929
+ }
2930
+
2931
+ addButtons();
2932
+ addToolbars();
2933
+ addEvents();
2934
+
2935
+ editor.addCommand('mceEditImage', editImageDialog);
2936
+ };
2937
+
2938
+ PluginManager.add('imagetools', plugin);
2939
+
2940
+ return function() {};
2941
+ });
2942
+
2943
+ dem('tinymce/imagetoolsplugin/Plugin')();
2944
+ })();