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("media",function(e,t){function n(e){return e=e.toLowerCase(),e.indexOf(".mp3")!=-1?"audio/mpeg":e.indexOf(".wav")!=-1?"audio/wav":e.indexOf(".mp4")!=-1?"video/mp4":e.indexOf(".webm")!=-1?"video/webm":e.indexOf(".ogg")!=-1?"video/ogg":e.indexOf(".swf")!=-1?"application/x-shockwave-flash":""}function r(t){var n=e.settings.media_scripts;if(n)for(var r=0;r<n.length;r++)if(t.indexOf(n[r].filter)!==-1)return n[r]}function i(){function t(e){var t,n,o,a;t=r.find("#width")[0],n=r.find("#height")[0],o=t.value(),a=n.value(),r.find("#constrain")[0].checked()&&i&&c&&o&&a&&(e.control==t?(a=Math.round(o/i*a),isNaN(a)||n.value(a)):(o=Math.round(a/c*o),isNaN(o)||t.value(o))),i=o,c=a}function n(){u=s(this.value()),this.parent().parent().fromJSON(u)}var r,i,c,u,d=[{name:"source1",type:"filepicker",filetype:"media",size:40,autofocus:!0,label:"Source",onchange:function(e){tinymce.each(e.meta,function(e,t){r.find("#"+t).value(e)})}}];e.settings.media_alt_source!==!1&&d.push({name:"source2",type:"filepicker",filetype:"media",size:40,label:"Alternative source"}),e.settings.media_poster!==!1&&d.push({name:"poster",type:"filepicker",filetype:"image",size:40,label:"Poster"}),e.settings.media_dimensions!==!1&&d.push({type:"container",label:"Dimensions",layout:"flex",align:"center",spacing:5,items:[{name:"width",type:"textbox",maxLength:5,size:3,onchange:t,ariaLabel:"Width"},{type:"label",text:"x"},{name:"height",type:"textbox",maxLength:5,size:3,onchange:t,ariaLabel:"Height"},{name:"constrain",type:"checkbox",checked:!0,text:"Constrain proportions"}]}),u=l(e.selection.getNode()),i=u.width,c=u.height;var f={id:"mcemediasource",type:"textbox",flex:1,name:"embed",value:o(),multiline:!0,label:"Source"};f[m]=n,r=e.windowManager.open({title:"Insert/edit video",data:u,bodyType:"tabpanel",body:[{title:"General",type:"form",onShowTab:function(){u=s(this.next().find("#embed").value()),this.fromJSON(u)},items:d},{title:"Embed",type:"container",layout:"flex",direction:"column",align:"stretch",padding:10,spacing:10,onShowTab:function(){this.find("#embed").value(a(this.parent().toJSON()))},items:[{type:"label",text:"Paste your embed code below:",forId:"mcemediasource"},f]}],onSubmit:function(){var t,n,r,i;for(t=e.dom.select("img[data-mce-object]"),e.insertContent(a(this.toJSON())),n=e.dom.select("img[data-mce-object]"),r=0;r<t.length;r++)for(i=n.length-1;i>=0;i--)t[r]==n[i]&&n.splice(i,1);e.selection.select(n[0]),e.nodeChanged()}})}function o(){var t=e.selection.getNode();if(t.getAttribute("data-mce-object"))return e.selection.getContent()}function a(i){var o="";if(!i.source1&&(tinymce.extend(i,s(i.embed)),!i.source1))return"";if(i.source2||(i.source2=""),i.poster||(i.poster=""),i.source1=e.convertURL(i.source1,"source"),i.source2=e.convertURL(i.source2,"source"),i.source1mime=n(i.source1),i.source2mime=n(i.source2),i.poster=e.convertURL(i.poster,"poster"),i.flashPlayerUrl=e.convertURL(t+"/moxieplayer.swf","movie"),tinymce.each(p,function(e){var t,n,r;if(t=e.regex.exec(i.source1)){for(r=e.url,n=0;t[n];n++)r=r.replace("$"+n,function(){return t[n]});i.source1=r,i.type=e.type,i.allowFullscreen=e.allowFullscreen,i.width=i.width||e.w,i.height=i.height||e.h}}),i.embed)o=u(i.embed,i,!0);else{var a=r(i.source1);if(a&&(i.type="script",i.width=a.width,i.height=a.height),i.width=i.width||300,i.height=i.height||150,tinymce.each(i,function(t,n){i[n]=e.dom.encode(t)}),"iframe"==i.type){var l=i.allowFullscreen?' allowFullscreen="1"':"";o+='<iframe src="'+i.source1+'" width="'+i.width+'" height="'+i.height+'"'+l+"></iframe>"}else"application/x-shockwave-flash"==i.source1mime?(o+='<object data="'+i.source1+'" width="'+i.width+'" height="'+i.height+'" type="application/x-shockwave-flash">',i.poster&&(o+='<img src="'+i.poster+'" width="'+i.width+'" height="'+i.height+'" />'),o+="</object>"):i.source1mime.indexOf("audio")!=-1?e.settings.audio_template_callback?o=e.settings.audio_template_callback(i):o+='<audio controls="controls" src="'+i.source1+'">'+(i.source2?'\n<source src="'+i.source2+'"'+(i.source2mime?' type="'+i.source2mime+'"':"")+" />\n":"")+"</audio>":"script"==i.type?o+='<script src="'+i.source1+'"></script>':o=e.settings.video_template_callback?e.settings.video_template_callback(i):'<video width="'+i.width+'" height="'+i.height+'"'+(i.poster?' poster="'+i.poster+'"':"")+' controls="controls">\n<source src="'+i.source1+'"'+(i.source1mime?' type="'+i.source1mime+'"':"")+" />\n"+(i.source2?'<source src="'+i.source2+'"'+(i.source2mime?' type="'+i.source2mime+'"':"")+" />\n":"")+"</video>"}return o}function s(e){var t={};return new tinymce.html.SaxParser({validate:!1,allow_conditional_comments:!0,special:"script,noscript",start:function(e,n){if(t.source1||"param"!=e||(t.source1=n.map.movie),"iframe"!=e&&"object"!=e&&"embed"!=e&&"video"!=e&&"audio"!=e||(t.type||(t.type=e),t=tinymce.extend(n.map,t)),"script"==e){var i=r(n.map.src);if(!i)return;t={type:"script",source1:n.map.src,width:i.width,height:i.height}}"source"==e&&(t.source1?t.source2||(t.source2=n.map.src):t.source1=n.map.src),"img"!=e||t.poster||(t.poster=n.map.src)}}).parse(e),t.source1=t.source1||t.src||t.data,t.source2=t.source2||"",t.poster=t.poster||"",t}function l(t){return t.getAttribute("data-mce-object")?s(e.serializer.serialize(t,{selection:!0})):{}}function c(t){if(e.settings.media_filter_html===!1)return t;var n,r=new tinymce.html.Writer;return new tinymce.html.SaxParser({validate:!1,allow_conditional_comments:!1,special:"script,noscript",comment:function(e){r.comment(e)},cdata:function(e){r.cdata(e)},text:function(e,t){r.text(e,t)},start:function(t,i,o){if(n=!0,"script"!=t&&"noscript"!=t){for(var a=0;a<i.length;a++){if(0===i[a].name.indexOf("on"))return;"style"==i[a].name&&(i[a].value=e.dom.serializeStyle(e.dom.parseStyle(i[a].value),t))}r.start(t,i,o),n=!1}},end:function(e){n||r.end(e)}},new tinymce.html.Schema({})).parse(t),r.getContent()}function u(e,t,n){function r(e,t){var n,r,i,o;for(n in t)if(i=""+t[n],e.map[n])for(r=e.length;r--;)o=e[r],o.name==n&&(i?(e.map[n]=i,o.value=i):(delete e.map[n],e.splice(r,1)));else i&&(e.push({name:n,value:i}),e.map[n]=i)}var i,o=new tinymce.html.Writer,a=0;return new tinymce.html.SaxParser({validate:!1,allow_conditional_comments:!0,special:"script,noscript",comment:function(e){o.comment(e)},cdata:function(e){o.cdata(e)},text:function(e,t){o.text(e,t)},start:function(e,s,l){switch(e){case"video":case"object":case"embed":case"img":case"iframe":r(s,{width:t.width,height:t.height})}if(n)switch(e){case"video":r(s,{poster:t.poster,src:""}),t.source2&&r(s,{src:""});break;case"iframe":r(s,{src:t.source1});break;case"source":if(a++,a<=2&&(r(s,{src:t["source"+a],type:t["source"+a+"mime"]}),!t["source"+a]))return;break;case"img":if(!t.poster)return;i=!0}o.start(e,s,l)},end:function(e){if("video"==e&&n)for(var s=1;s<=2;s++)if(t["source"+s]){var l=[];l.map={},a<s&&(r(l,{src:t["source"+s],type:t["source"+s+"mime"]}),o.start("source",l,!0))}if(t.poster&&"object"==e&&n&&!i){var c=[];c.map={},r(c,{src:t.poster,width:t.width,height:t.height}),o.start("img",c,!0)}o.end(e)}},new tinymce.html.Schema({})).parse(e),o.getContent()}function d(t,n){var r,i,o,a,s;for(o=t.attributes,a=o.length;a--;)r=o[a].name,i=o[a].value,"width"!==r&&"height"!==r&&"style"!==r&&("data"!=r&&"src"!=r||(i=e.convertURL(i,r)),n.attr("data-mce-p-"+r,i));s=t.firstChild&&t.firstChild.value,s&&(n.attr("data-mce-html",escape(s)),n.firstChild=null)}function f(e){var t,n=e.name;return t=new tinymce.html.Node("img",1),t.shortEnded=!0,d(e,t),t.attr({width:e.attr("width")||"300",height:e.attr("height")||("audio"==n?"30":"150"),style:e.attr("style"),src:tinymce.Env.transparentSrc,"data-mce-object":n,class:"mce-object mce-object-"+n}),t}function h(e){var t,n,r,i=e.name;return t=new tinymce.html.Node("span",1),t.attr({contentEditable:"false",style:e.attr("style"),"data-mce-object":i,class:"mce-preview-object mce-object-"+i}),d(e,t),n=new tinymce.html.Node(i,1),n.attr({src:e.attr("src"),allowfullscreen:e.attr("allowfullscreen"),width:e.attr("width")||"300",height:e.attr("height")||("audio"==i?"30":"150"),frameborder:"0"}),r=new tinymce.html.Node("span",1),r.attr("class","mce-shim"),t.append(n),t.append(r),t}var p=[{regex:/youtu\.be\/([\w\-.]+)/,type:"iframe",w:560,h:314,url:"//www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/youtube\.com(.+)v=([^&]+)/,type:"iframe",w:560,h:314,url:"//www.youtube.com/embed/$2",allowFullscreen:!0},{regex:/youtube.com\/embed\/([a-z0-9\-_]+(?:\?.+)?)/i,type:"iframe",w:560,h:314,url:"//www.youtube.com/embed/$1",allowFullscreen:!0},{regex:/vimeo\.com\/([0-9]+)/,type:"iframe",w:425,h:350,url:"//player.vimeo.com/video/$1?title=0&byline=0&portrait=0&color=8dc7dc",allowfullscreen:!0},{regex:/vimeo\.com\/(.*)\/([0-9]+)/,type:"iframe",w:425,h:350,url:"//player.vimeo.com/video/$2?title=0&amp;byline=0",allowfullscreen:!0},{regex:/maps\.google\.([a-z]{2,3})\/maps\/(.+)msid=(.+)/,type:"iframe",w:425,h:350,url:'//maps.google.com/maps/ms?msid=$2&output=embed"',allowFullscreen:!1},{regex:/dailymotion\.com\/video\/([^_]+)/,type:"iframe",w:480,h:270,url:"//www.dailymotion.com/embed/video/$1",allowFullscreen:!0}],m=tinymce.Env.ie&&tinymce.Env.ie<=8?"onChange":"onInput";e.on("ResolveName",function(e){var t;1==e.target.nodeType&&(t=e.target.getAttribute("data-mce-object"))&&(e.name=t)}),e.on("preInit",function(){var t=e.schema.getSpecialElements();tinymce.each("video audio iframe object".split(" "),function(e){t[e]=new RegExp("</"+e+"[^>]*>","gi")});var n=e.schema.getBoolAttrs();tinymce.each("webkitallowfullscreen mozallowfullscreen allowfullscreen".split(" "),function(e){n[e]={}}),e.parser.addNodeFilter("iframe,video,audio,object,embed,script",function(t){for(var n,i,o,a=t.length;a--;)n=t[a],n.parent&&(n.parent.attr("data-mce-object")||("script"!=n.name||(o=r(n.attr("src"))))&&(o&&(o.width&&n.attr("width",o.width.toString()),o.height&&n.attr("height",o.height.toString())),i="iframe"==n.name&&e.settings.media_live_embeds!==!1&&tinymce.Env.ceFalse?h(n):f(n),n.replace(i)))}),e.serializer.addAttributeFilter("data-mce-object",function(e,t){for(var n,r,i,o,a,s,l,u,d=e.length;d--;)if(n=e[d],n.parent){for(l=n.attr(t),r=new tinymce.html.Node(l,1),"audio"!=l&&"script"!=l&&(u=n.attr("class"),u&&u.indexOf("mce-preview-object")!==-1?r.attr({width:n.firstChild.attr("width"),height:n.firstChild.attr("height")}):r.attr({width:n.attr("width"),height:n.attr("height")})),r.attr({style:n.attr("style")}),o=n.attributes,i=o.length;i--;){var f=o[i].name;0===f.indexOf("data-mce-p-")&&r.attr(f.substr(11),o[i].value)}"script"==l&&r.attr("type","text/javascript"),a=n.attr("data-mce-html"),a&&(s=new tinymce.html.Node("#text",3),s.raw=!0,s.value=c(unescape(a)),r.append(s)),n.replace(r)}})}),e.on("click keyup",function(){var t=e.selection.getNode();t&&e.dom.hasClass(t,"mce-preview-object")&&e.dom.getAttrib(t,"data-mce-selected")&&t.setAttribute("data-mce-selected","2")}),e.on("ObjectSelected",function(e){var t=e.target.getAttribute("data-mce-object");"audio"!=t&&"script"!=t||e.preventDefault()}),e.on("objectResized",function(e){var t,n=e.target;n.getAttribute("data-mce-object")&&(t=n.getAttribute("data-mce-html"),t&&(t=unescape(t),n.setAttribute("data-mce-html",escape(u(t,{width:e.width,height:e.height})))))}),e.addButton("media",{tooltip:"Insert/edit video",onclick:i,stateSelector:["img[data-mce-object]","span[data-mce-object]"]}),e.addMenuItem("media",{icon:"media",text:"Insert/edit video",onclick:i,context:"insert",prependToContext:!0}),e.on("setContent",function(){e.$("span.mce-preview-object").each(function(t,n){var r=e.$(n);0===r.find("span.mce-shim",n).length&&r.append('<span class="mce-shim"></span>')})}),e.addCommand("mceMedia",i),this.showDialog=i});
@@ -0,0 +1,53 @@
1
+ /**
2
+ * plugin.js
3
+ *
4
+ * Released under LGPL License.
5
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
6
+ *
7
+ * License: http://www.tinymce.com/license
8
+ * Contributing: http://www.tinymce.com/contributing
9
+ */
10
+
11
+ /*global tinymce:true */
12
+
13
+ tinymce.PluginManager.add('nonbreaking', function(editor) {
14
+ var setting = editor.getParam('nonbreaking_force_tab');
15
+
16
+ editor.addCommand('mceNonBreaking', function() {
17
+ editor.insertContent(
18
+ (editor.plugins.visualchars && editor.plugins.visualchars.state) ?
19
+ '<span class="mce-nbsp">&nbsp;</span>' : '&nbsp;'
20
+ );
21
+
22
+ editor.dom.setAttrib(editor.dom.select('span.mce-nbsp'), 'data-mce-bogus', '1');
23
+ });
24
+
25
+ editor.addButton('nonbreaking', {
26
+ title: 'Nonbreaking space',
27
+ cmd: 'mceNonBreaking'
28
+ });
29
+
30
+ editor.addMenuItem('nonbreaking', {
31
+ text: 'Nonbreaking space',
32
+ cmd: 'mceNonBreaking',
33
+ context: 'insert'
34
+ });
35
+
36
+ if (setting) {
37
+ var spaces = +setting > 1 ? +setting : 3; // defaults to 3 spaces if setting is true (or 1)
38
+
39
+ editor.on('keydown', function(e) {
40
+ if (e.keyCode == 9) {
41
+
42
+ if (e.shiftKey) {
43
+ return;
44
+ }
45
+
46
+ e.preventDefault();
47
+ for (var i = 0; i < spaces; i++) {
48
+ editor.execCommand('mceNonBreaking');
49
+ }
50
+ }
51
+ });
52
+ }
53
+ });
@@ -0,0 +1 @@
1
+ tinymce.PluginManager.add("nonbreaking",function(e){var t=e.getParam("nonbreaking_force_tab");if(e.addCommand("mceNonBreaking",function(){e.insertContent(e.plugins.visualchars&&e.plugins.visualchars.state?'<span class="mce-nbsp">&nbsp;</span>':"&nbsp;"),e.dom.setAttrib(e.dom.select("span.mce-nbsp"),"data-mce-bogus","1")}),e.addButton("nonbreaking",{title:"Nonbreaking space",cmd:"mceNonBreaking"}),e.addMenuItem("nonbreaking",{text:"Nonbreaking space",cmd:"mceNonBreaking",context:"insert"}),t){var n=+t>1?+t:3;e.on("keydown",function(t){if(9==t.keyCode){if(t.shiftKey)return;t.preventDefault();for(var r=0;r<n;r++)e.execCommand("mceNonBreaking")}})}});
@@ -0,0 +1,101 @@
1
+ /**
2
+ * plugin.js
3
+ *
4
+ * Released under LGPL License.
5
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
6
+ *
7
+ * License: http://www.tinymce.com/license
8
+ * Contributing: http://www.tinymce.com/contributing
9
+ */
10
+
11
+ /*global tinymce:true */
12
+
13
+ tinymce.PluginManager.add('noneditable', function(editor) {
14
+ var editClass, nonEditClass, nonEditableRegExps, contentEditableAttrName = 'contenteditable';
15
+
16
+ function hasClass(checkClassName) {
17
+ return function(node) {
18
+ return (" " + node.attr("class") + " ").indexOf(checkClassName) !== -1;
19
+ };
20
+ }
21
+
22
+ function convertRegExpsToNonEditable(e) {
23
+ var i = nonEditableRegExps.length, content = e.content, cls = tinymce.trim(nonEditClass);
24
+
25
+ function replaceMatchWithSpan(match) {
26
+ var args = arguments, index = args[args.length - 2];
27
+
28
+ // Is value inside an attribute then don't replace
29
+ if (index > 0 && content.charAt(index - 1) == '"') {
30
+ return match;
31
+ }
32
+
33
+ return (
34
+ '<span class="' + cls + '" data-mce-content="' + editor.dom.encode(args[0]) + '">' +
35
+ editor.dom.encode(typeof args[1] === "string" ? args[1] : args[0]) + '</span>'
36
+ );
37
+ }
38
+
39
+ // Don't replace the variables when raw is used for example on undo/redo
40
+ if (e.format == "raw") {
41
+ return;
42
+ }
43
+
44
+ while (i--) {
45
+ content = content.replace(nonEditableRegExps[i], replaceMatchWithSpan);
46
+ }
47
+
48
+ e.content = content;
49
+ }
50
+
51
+ editClass = " " + tinymce.trim(editor.getParam("noneditable_editable_class", "mceEditable")) + " ";
52
+ nonEditClass = " " + tinymce.trim(editor.getParam("noneditable_noneditable_class", "mceNonEditable")) + " ";
53
+
54
+ var hasEditClass = hasClass(editClass);
55
+ var hasNonEditClass = hasClass(nonEditClass);
56
+
57
+ nonEditableRegExps = editor.getParam("noneditable_regexp");
58
+ if (nonEditableRegExps && !nonEditableRegExps.length) {
59
+ nonEditableRegExps = [nonEditableRegExps];
60
+ }
61
+
62
+ editor.on('PreInit', function() {
63
+ if (nonEditableRegExps) {
64
+ editor.on('BeforeSetContent', convertRegExpsToNonEditable);
65
+ }
66
+
67
+ editor.parser.addAttributeFilter('class', function(nodes) {
68
+ var i = nodes.length, node;
69
+
70
+ while (i--) {
71
+ node = nodes[i];
72
+
73
+ if (hasEditClass(node)) {
74
+ node.attr(contentEditableAttrName, "true");
75
+ } else if (hasNonEditClass(node)) {
76
+ node.attr(contentEditableAttrName, "false");
77
+ }
78
+ }
79
+ });
80
+
81
+ editor.serializer.addAttributeFilter(contentEditableAttrName, function(nodes) {
82
+ var i = nodes.length, node;
83
+
84
+ while (i--) {
85
+ node = nodes[i];
86
+ if (!hasEditClass(node) && !hasNonEditClass(node)) {
87
+ continue;
88
+ }
89
+
90
+ if (nonEditableRegExps && node.attr('data-mce-content')) {
91
+ node.name = "#text";
92
+ node.type = 3;
93
+ node.raw = true;
94
+ node.value = node.attr('data-mce-content');
95
+ } else {
96
+ node.attr(contentEditableAttrName, null);
97
+ }
98
+ }
99
+ });
100
+ });
101
+ });
@@ -0,0 +1 @@
1
+ tinymce.PluginManager.add("noneditable",function(e){function t(e){return function(t){return(" "+t.attr("class")+" ").indexOf(e)!==-1}}function n(t){function n(t){var n=arguments,r=n[n.length-2];return r>0&&'"'==a.charAt(r-1)?t:'<span class="'+s+'" data-mce-content="'+e.dom.encode(n[0])+'">'+e.dom.encode("string"==typeof n[1]?n[1]:n[0])+"</span>"}var r=o.length,a=t.content,s=tinymce.trim(i);if("raw"!=t.format){for(;r--;)a=a.replace(o[r],n);t.content=a}}var r,i,o,a="contenteditable";r=" "+tinymce.trim(e.getParam("noneditable_editable_class","mceEditable"))+" ",i=" "+tinymce.trim(e.getParam("noneditable_noneditable_class","mceNonEditable"))+" ";var s=t(r),l=t(i);o=e.getParam("noneditable_regexp"),o&&!o.length&&(o=[o]),e.on("PreInit",function(){o&&e.on("BeforeSetContent",n),e.parser.addAttributeFilter("class",function(e){for(var t,n=e.length;n--;)t=e[n],s(t)?t.attr(a,"true"):l(t)&&t.attr(a,"false")}),e.serializer.addAttributeFilter(a,function(e){for(var t,n=e.length;n--;)t=e[n],(s(t)||l(t))&&(o&&t.attr("data-mce-content")?(t.name="#text",t.type=3,t.raw=!0,t.value=t.attr("data-mce-content")):t.attr(a,null))})})});
@@ -0,0 +1,88 @@
1
+ /**
2
+ * plugin.js
3
+ *
4
+ * Released under LGPL License.
5
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
6
+ *
7
+ * License: http://www.tinymce.com/license
8
+ * Contributing: http://www.tinymce.com/contributing
9
+ */
10
+
11
+ /*global tinymce:true */
12
+
13
+ tinymce.PluginManager.add('pagebreak', function(editor) {
14
+ var pageBreakClass = 'mce-pagebreak', separatorHtml = editor.getParam('pagebreak_separator', '<!-- pagebreak -->');
15
+
16
+ var pageBreakSeparatorRegExp = new RegExp(separatorHtml.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g, function(a) {
17
+ return '\\' + a;
18
+ }), 'gi');
19
+
20
+ var pageBreakPlaceHolderHtml = '<img src="' + tinymce.Env.transparentSrc + '" class="' +
21
+ pageBreakClass + '" data-mce-resize="false" data-mce-placeholder />';
22
+
23
+ // Register commands
24
+ editor.addCommand('mcePageBreak', function() {
25
+ if (editor.settings.pagebreak_split_block) {
26
+ editor.insertContent('<p>' + pageBreakPlaceHolderHtml + '</p>');
27
+ } else {
28
+ editor.insertContent(pageBreakPlaceHolderHtml);
29
+ }
30
+ });
31
+
32
+ // Register buttons
33
+ editor.addButton('pagebreak', {
34
+ title: 'Page break',
35
+ cmd: 'mcePageBreak'
36
+ });
37
+
38
+ editor.addMenuItem('pagebreak', {
39
+ text: 'Page break',
40
+ icon: 'pagebreak',
41
+ cmd: 'mcePageBreak',
42
+ context: 'insert'
43
+ });
44
+
45
+ editor.on('ResolveName', function(e) {
46
+ if (e.target.nodeName == 'IMG' && editor.dom.hasClass(e.target, pageBreakClass)) {
47
+ e.name = 'pagebreak';
48
+ }
49
+ });
50
+
51
+ editor.on('click', function(e) {
52
+ e = e.target;
53
+
54
+ if (e.nodeName === 'IMG' && editor.dom.hasClass(e, pageBreakClass)) {
55
+ editor.selection.select(e);
56
+ }
57
+ });
58
+
59
+ editor.on('BeforeSetContent', function(e) {
60
+ e.content = e.content.replace(pageBreakSeparatorRegExp, pageBreakPlaceHolderHtml);
61
+ });
62
+
63
+ editor.on('PreInit', function() {
64
+ editor.serializer.addNodeFilter('img', function(nodes) {
65
+ var i = nodes.length, node, className;
66
+
67
+ while (i--) {
68
+ node = nodes[i];
69
+ className = node.attr('class');
70
+ if (className && className.indexOf('mce-pagebreak') !== -1) {
71
+ // Replace parent block node if pagebreak_split_block is enabled
72
+ var parentNode = node.parent;
73
+ if (editor.schema.getBlockElements()[parentNode.name] && editor.settings.pagebreak_split_block) {
74
+ parentNode.type = 3;
75
+ parentNode.value = separatorHtml;
76
+ parentNode.raw = true;
77
+ node.remove();
78
+ continue;
79
+ }
80
+
81
+ node.type = 3;
82
+ node.value = separatorHtml;
83
+ node.raw = true;
84
+ }
85
+ }
86
+ });
87
+ });
88
+ });
@@ -0,0 +1 @@
1
+ tinymce.PluginManager.add("pagebreak",function(e){var t="mce-pagebreak",n=e.getParam("pagebreak_separator","<!-- pagebreak -->"),r=new RegExp(n.replace(/[\?\.\*\[\]\(\)\{\}\+\^\$\:]/g,function(e){return"\\"+e}),"gi"),i='<img src="'+tinymce.Env.transparentSrc+'" class="'+t+'" data-mce-resize="false" data-mce-placeholder />';e.addCommand("mcePageBreak",function(){e.settings.pagebreak_split_block?e.insertContent("<p>"+i+"</p>"):e.insertContent(i)}),e.addButton("pagebreak",{title:"Page break",cmd:"mcePageBreak"}),e.addMenuItem("pagebreak",{text:"Page break",icon:"pagebreak",cmd:"mcePageBreak",context:"insert"}),e.on("ResolveName",function(n){"IMG"==n.target.nodeName&&e.dom.hasClass(n.target,t)&&(n.name="pagebreak")}),e.on("click",function(n){n=n.target,"IMG"===n.nodeName&&e.dom.hasClass(n,t)&&e.selection.select(n)}),e.on("BeforeSetContent",function(e){e.content=e.content.replace(r,i)}),e.on("PreInit",function(){e.serializer.addNodeFilter("img",function(t){for(var r,i,o=t.length;o--;)if(r=t[o],i=r.attr("class"),i&&i.indexOf("mce-pagebreak")!==-1){var a=r.parent;if(e.schema.getBlockElements()[a.name]&&e.settings.pagebreak_split_block){a.type=3,a.value=n,a.raw=!0,r.remove();continue}r.type=3,r.value=n,r.raw=!0}})})});
@@ -0,0 +1,1844 @@
1
+ /**
2
+ * Compiled inline version. (Library mode)
3
+ */
4
+
5
+ /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
6
+ /*globals $code */
7
+
8
+ (function(exports, undefined) {
9
+ "use strict";
10
+
11
+ var modules = {};
12
+
13
+ function require(ids, callback) {
14
+ var module, defs = [];
15
+
16
+ for (var i = 0; i < ids.length; ++i) {
17
+ module = modules[ids[i]] || resolve(ids[i]);
18
+ if (!module) {
19
+ throw 'module definition dependecy not found: ' + ids[i];
20
+ }
21
+
22
+ defs.push(module);
23
+ }
24
+
25
+ callback.apply(null, defs);
26
+ }
27
+
28
+ function define(id, dependencies, definition) {
29
+ if (typeof id !== 'string') {
30
+ throw 'invalid module definition, module id must be defined and be a string';
31
+ }
32
+
33
+ if (dependencies === undefined) {
34
+ throw 'invalid module definition, dependencies must be specified';
35
+ }
36
+
37
+ if (definition === undefined) {
38
+ throw 'invalid module definition, definition function must be specified';
39
+ }
40
+
41
+ require(dependencies, function() {
42
+ modules[id] = definition.apply(null, arguments);
43
+ });
44
+ }
45
+
46
+ function defined(id) {
47
+ return !!modules[id];
48
+ }
49
+
50
+ function resolve(id) {
51
+ var target = exports;
52
+ var fragments = id.split(/[.\/]/);
53
+
54
+ for (var fi = 0; fi < fragments.length; ++fi) {
55
+ if (!target[fragments[fi]]) {
56
+ return;
57
+ }
58
+
59
+ target = target[fragments[fi]];
60
+ }
61
+
62
+ return target;
63
+ }
64
+
65
+ function expose(ids) {
66
+ var i, target, id, fragments, privateModules;
67
+
68
+ for (i = 0; i < ids.length; i++) {
69
+ target = exports;
70
+ id = ids[i];
71
+ fragments = id.split(/[.\/]/);
72
+
73
+ for (var fi = 0; fi < fragments.length - 1; ++fi) {
74
+ if (target[fragments[fi]] === undefined) {
75
+ target[fragments[fi]] = {};
76
+ }
77
+
78
+ target = target[fragments[fi]];
79
+ }
80
+
81
+ target[fragments[fragments.length - 1]] = modules[id];
82
+ }
83
+
84
+ // Expose private modules for unit tests
85
+ if (exports.AMDLC_TESTS) {
86
+ privateModules = exports.privateModules || {};
87
+
88
+ for (id in modules) {
89
+ privateModules[id] = modules[id];
90
+ }
91
+
92
+ for (i = 0; i < ids.length; i++) {
93
+ delete privateModules[ids[i]];
94
+ }
95
+
96
+ exports.privateModules = privateModules;
97
+ }
98
+ }
99
+
100
+ // Included from: js/tinymce/plugins/paste/classes/Utils.js
101
+
102
+ /**
103
+ * Utils.js
104
+ *
105
+ * Released under LGPL License.
106
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
107
+ *
108
+ * License: http://www.tinymce.com/license
109
+ * Contributing: http://www.tinymce.com/contributing
110
+ */
111
+
112
+ /**
113
+ * This class contails various utility functions for the paste plugin.
114
+ *
115
+ * @class tinymce.pasteplugin.Utils
116
+ */
117
+ define("tinymce/pasteplugin/Utils", [
118
+ "tinymce/util/Tools",
119
+ "tinymce/html/DomParser",
120
+ "tinymce/html/Schema"
121
+ ], function(Tools, DomParser, Schema) {
122
+ function filter(content, items) {
123
+ Tools.each(items, function(v) {
124
+ if (v.constructor == RegExp) {
125
+ content = content.replace(v, '');
126
+ } else {
127
+ content = content.replace(v[0], v[1]);
128
+ }
129
+ });
130
+
131
+ return content;
132
+ }
133
+
134
+ /**
135
+ * Gets the innerText of the specified element. It will handle edge cases
136
+ * and works better than textContent on Gecko.
137
+ *
138
+ * @param {String} html HTML string to get text from.
139
+ * @return {String} String of text with line feeds.
140
+ */
141
+ function innerText(html) {
142
+ var schema = new Schema(), domParser = new DomParser({}, schema), text = '';
143
+ var shortEndedElements = schema.getShortEndedElements();
144
+ var ignoreElements = Tools.makeMap('script noscript style textarea video audio iframe object', ' ');
145
+ var blockElements = schema.getBlockElements();
146
+
147
+ function walk(node) {
148
+ var name = node.name, currentNode = node;
149
+
150
+ if (name === 'br') {
151
+ text += '\n';
152
+ return;
153
+ }
154
+
155
+ // img/input/hr
156
+ if (shortEndedElements[name]) {
157
+ text += ' ';
158
+ }
159
+
160
+ // Ingore script, video contents
161
+ if (ignoreElements[name]) {
162
+ text += ' ';
163
+ return;
164
+ }
165
+
166
+ if (node.type == 3) {
167
+ text += node.value;
168
+ }
169
+
170
+ // Walk all children
171
+ if (!node.shortEnded) {
172
+ if ((node = node.firstChild)) {
173
+ do {
174
+ walk(node);
175
+ } while ((node = node.next));
176
+ }
177
+ }
178
+
179
+ // Add \n or \n\n for blocks or P
180
+ if (blockElements[name] && currentNode.next) {
181
+ text += '\n';
182
+
183
+ if (name == 'p') {
184
+ text += '\n';
185
+ }
186
+ }
187
+ }
188
+
189
+ html = filter(html, [
190
+ /<!\[[^\]]+\]>/g // Conditional comments
191
+ ]);
192
+
193
+ walk(domParser.parse(html));
194
+
195
+ return text;
196
+ }
197
+
198
+ /**
199
+ * Trims the specified HTML by removing all WebKit fragments, all elements wrapping the body trailing BR elements etc.
200
+ *
201
+ * @param {String} html Html string to trim contents on.
202
+ * @return {String} Html contents that got trimmed.
203
+ */
204
+ function trimHtml(html) {
205
+ function trimSpaces(all, s1, s2) {
206
+ // WebKit &nbsp; meant to preserve multiple spaces but instead inserted around all inline tags,
207
+ // including the spans with inline styles created on paste
208
+ if (!s1 && !s2) {
209
+ return ' ';
210
+ }
211
+
212
+ return '\u00a0';
213
+ }
214
+
215
+ html = filter(html, [
216
+ /^[\s\S]*<body[^>]*>\s*|\s*<\/body[^>]*>[\s\S]*$/g, // Remove anything but the contents within the BODY element
217
+ /<!--StartFragment-->|<!--EndFragment-->/g, // Inner fragments (tables from excel on mac)
218
+ [/( ?)<span class="Apple-converted-space">\u00a0<\/span>( ?)/g, trimSpaces],
219
+ /<br class="Apple-interchange-newline">/g,
220
+ /<br>$/i // Trailing BR elements
221
+ ]);
222
+
223
+ return html;
224
+ }
225
+
226
+ // TODO: Should be in some global class
227
+ function createIdGenerator(prefix) {
228
+ var count = 0;
229
+
230
+ return function() {
231
+ return prefix + (count++);
232
+ };
233
+ }
234
+
235
+ return {
236
+ filter: filter,
237
+ innerText: innerText,
238
+ trimHtml: trimHtml,
239
+ createIdGenerator: createIdGenerator
240
+ };
241
+ });
242
+
243
+ // Included from: js/tinymce/plugins/paste/classes/SmartPaste.js
244
+
245
+ /**
246
+ * SmartPaste.js
247
+ *
248
+ * Released under LGPL License.
249
+ * Copyright (c) 1999-2016 Ephox Corp. All rights reserved
250
+ *
251
+ * License: http://www.tinymce.com/license
252
+ * Contributing: http://www.tinymce.com/contributing
253
+ */
254
+
255
+ /**
256
+ * Tries to be smart depending on what the user pastes if it looks like an url
257
+ * it will make a link out of the current selection. If it's an image url that looks
258
+ * like an image it will check if it's an image and insert it as an image.
259
+ *
260
+ * @class tinymce.pasteplugin.SmartPaste
261
+ * @private
262
+ */
263
+ define("tinymce/pasteplugin/SmartPaste", [
264
+ "tinymce/util/Tools"
265
+ ], function (Tools) {
266
+ var isAbsoluteUrl = function (url) {
267
+ return /^https?:\/\/[\w\?\-\/+=.&%@~#]+$/i.test(url);
268
+ };
269
+
270
+ var isImageUrl = function (url) {
271
+ return isAbsoluteUrl(url) && /.(gif|jpe?g|png)$/.test(url);
272
+ };
273
+
274
+ var createImage = function (editor, url, pasteHtml) {
275
+ editor.undoManager.extra(function () {
276
+ pasteHtml(editor, url);
277
+ }, function () {
278
+ editor.insertContent('<img src="' + url + '">');
279
+ });
280
+
281
+ return true;
282
+ };
283
+
284
+ var createLink = function (editor, url, pasteHtml) {
285
+ editor.undoManager.extra(function () {
286
+ pasteHtml(editor, url);
287
+ }, function () {
288
+ editor.execCommand('mceInsertLink', false, url);
289
+ });
290
+
291
+ return true;
292
+ };
293
+
294
+ var linkSelection = function (editor, html, pasteHtml) {
295
+ return editor.selection.isCollapsed() === false && isAbsoluteUrl(html) ? createLink(editor, html, pasteHtml) : false;
296
+ };
297
+
298
+ var insertImage = function (editor, html, pasteHtml) {
299
+ return isImageUrl(html) ? createImage(editor, html, pasteHtml) : false;
300
+ };
301
+
302
+ var pasteHtml = function (editor, html) {
303
+ editor.insertContent(html, {
304
+ merge: editor.settings.paste_merge_formats !== false,
305
+ paste: true
306
+ });
307
+
308
+ return true;
309
+ };
310
+
311
+ var smartInsertContent = function (editor, html) {
312
+ Tools.each([
313
+ linkSelection,
314
+ insertImage,
315
+ pasteHtml
316
+ ], function (action) {
317
+ return action(editor, html, pasteHtml) !== true;
318
+ });
319
+ };
320
+
321
+ var insertContent = function (editor, html) {
322
+ if (editor.settings.smart_paste === false) {
323
+ pasteHtml(editor, html);
324
+ } else {
325
+ smartInsertContent(editor, html);
326
+ }
327
+ };
328
+
329
+ return {
330
+ isImageUrl: isImageUrl,
331
+ isAbsoluteUrl: isAbsoluteUrl,
332
+ insertContent: insertContent
333
+ };
334
+ });
335
+
336
+ // Included from: js/tinymce/plugins/paste/classes/Clipboard.js
337
+
338
+ /**
339
+ * Clipboard.js
340
+ *
341
+ * Released under LGPL License.
342
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
343
+ *
344
+ * License: http://www.tinymce.com/license
345
+ * Contributing: http://www.tinymce.com/contributing
346
+ */
347
+
348
+ /**
349
+ * This class contains logic for getting HTML contents out of the clipboard.
350
+ *
351
+ * We need to make a lot of ugly hacks to get the contents out of the clipboard since
352
+ * the W3C Clipboard API is broken in all browsers that have it: Gecko/WebKit/Blink.
353
+ * We might rewrite this the way those API:s stabilize. Browsers doesn't handle pasting
354
+ * from applications like Word the same way as it does when pasting into a contentEditable area
355
+ * so we need to do lots of extra work to try to get to this clipboard data.
356
+ *
357
+ * Current implementation steps:
358
+ * 1. On keydown with paste keys Ctrl+V or Shift+Insert create
359
+ * a paste bin element and move focus to that element.
360
+ * 2. Wait for the browser to fire a "paste" event and get the contents out of the paste bin.
361
+ * 3. Check if the paste was successful if true, process the HTML.
362
+ * (4). If the paste was unsuccessful use IE execCommand, Clipboard API, document.dataTransfer old WebKit API etc.
363
+ *
364
+ * @class tinymce.pasteplugin.Clipboard
365
+ * @private
366
+ */
367
+ define("tinymce/pasteplugin/Clipboard", [
368
+ "tinymce/Env",
369
+ "tinymce/dom/RangeUtils",
370
+ "tinymce/util/VK",
371
+ "tinymce/pasteplugin/Utils",
372
+ "tinymce/pasteplugin/SmartPaste",
373
+ "tinymce/util/Delay"
374
+ ], function(Env, RangeUtils, VK, Utils, SmartPaste, Delay) {
375
+ return function(editor) {
376
+ var self = this, pasteBinElm, lastRng, keyboardPasteTimeStamp = 0, draggingInternally = false;
377
+ var pasteBinDefaultContent = '%MCEPASTEBIN%', keyboardPastePlainTextState;
378
+ var mceInternalUrlPrefix = 'data:text/mce-internal,';
379
+ var uniqueId = Utils.createIdGenerator("mceclip");
380
+
381
+ /**
382
+ * Pastes the specified HTML. This means that the HTML is filtered and then
383
+ * inserted at the current selection in the editor. It will also fire paste events
384
+ * for custom user filtering.
385
+ *
386
+ * @param {String} html HTML code to paste into the current selection.
387
+ */
388
+ function pasteHtml(html) {
389
+ var args, dom = editor.dom;
390
+
391
+ args = editor.fire('BeforePastePreProcess', {content: html}); // Internal event used by Quirks
392
+ args = editor.fire('PastePreProcess', args);
393
+ html = args.content;
394
+
395
+ if (!args.isDefaultPrevented()) {
396
+ // User has bound PastePostProcess events then we need to pass it through a DOM node
397
+ // This is not ideal but we don't want to let the browser mess up the HTML for example
398
+ // some browsers add &nbsp; to P tags etc
399
+ if (editor.hasEventListeners('PastePostProcess') && !args.isDefaultPrevented()) {
400
+ // We need to attach the element to the DOM so Sizzle selectors work on the contents
401
+ var tempBody = dom.add(editor.getBody(), 'div', {style: 'display:none'}, html);
402
+ args = editor.fire('PastePostProcess', {node: tempBody});
403
+ dom.remove(tempBody);
404
+ html = args.node.innerHTML;
405
+ }
406
+
407
+ if (!args.isDefaultPrevented()) {
408
+ SmartPaste.insertContent(editor, html);
409
+ }
410
+ }
411
+ }
412
+
413
+ /**
414
+ * Pastes the specified text. This means that the plain text is processed
415
+ * and converted into BR and P elements. It will fire paste events for custom filtering.
416
+ *
417
+ * @param {String} text Text to paste as the current selection location.
418
+ */
419
+ function pasteText(text) {
420
+ text = editor.dom.encode(text).replace(/\r\n/g, '\n');
421
+
422
+ var startBlock = editor.dom.getParent(editor.selection.getStart(), editor.dom.isBlock);
423
+
424
+ // Create start block html for example <p attr="value">
425
+ var forcedRootBlockName = editor.settings.forced_root_block;
426
+ var forcedRootBlockStartHtml;
427
+ if (forcedRootBlockName) {
428
+ forcedRootBlockStartHtml = editor.dom.createHTML(forcedRootBlockName, editor.settings.forced_root_block_attrs);
429
+ forcedRootBlockStartHtml = forcedRootBlockStartHtml.substr(0, forcedRootBlockStartHtml.length - 3) + '>';
430
+ }
431
+
432
+ if ((startBlock && /^(PRE|DIV)$/.test(startBlock.nodeName)) || !forcedRootBlockName) {
433
+ text = Utils.filter(text, [
434
+ [/\n/g, "<br>"]
435
+ ]);
436
+ } else {
437
+ text = Utils.filter(text, [
438
+ [/\n\n/g, "</p>" + forcedRootBlockStartHtml],
439
+ [/^(.*<\/p>)(<p>)$/, forcedRootBlockStartHtml + '$1'],
440
+ [/\n/g, "<br />"]
441
+ ]);
442
+
443
+ if (text.indexOf('<p>') != -1) {
444
+ text = forcedRootBlockStartHtml + text;
445
+ }
446
+ }
447
+
448
+ pasteHtml(text);
449
+ }
450
+
451
+ /**
452
+ * Creates a paste bin element as close as possible to the current caret location and places the focus inside that element
453
+ * so that when the real paste event occurs the contents gets inserted into this element
454
+ * instead of the current editor selection element.
455
+ */
456
+ function createPasteBin() {
457
+ var dom = editor.dom, body = editor.getBody();
458
+ var viewport = editor.dom.getViewPort(editor.getWin()), scrollTop = viewport.y, top = 20;
459
+ var scrollContainer;
460
+
461
+ lastRng = editor.selection.getRng();
462
+
463
+ if (editor.inline) {
464
+ scrollContainer = editor.selection.getScrollContainer();
465
+
466
+ // Can't always rely on scrollTop returning a useful value.
467
+ // It returns 0 if the browser doesn't support scrollTop for the element or is non-scrollable
468
+ if (scrollContainer && scrollContainer.scrollTop > 0) {
469
+ scrollTop = scrollContainer.scrollTop;
470
+ }
471
+ }
472
+
473
+ /**
474
+ * Returns the rect of the current caret if the caret is in an empty block before a
475
+ * BR we insert a temporary invisible character that we get the rect this way we always get a proper rect.
476
+ *
477
+ * TODO: This might be useful in core.
478
+ */
479
+ function getCaretRect(rng) {
480
+ var rects, textNode, node, container = rng.startContainer;
481
+
482
+ rects = rng.getClientRects();
483
+ if (rects.length) {
484
+ return rects[0];
485
+ }
486
+
487
+ if (!rng.collapsed || container.nodeType != 1) {
488
+ return;
489
+ }
490
+
491
+ node = container.childNodes[lastRng.startOffset];
492
+
493
+ // Skip empty whitespace nodes
494
+ while (node && node.nodeType == 3 && !node.data.length) {
495
+ node = node.nextSibling;
496
+ }
497
+
498
+ if (!node) {
499
+ return;
500
+ }
501
+
502
+ // Check if the location is |<br>
503
+ // TODO: Might need to expand this to say |<table>
504
+ if (node.tagName == 'BR') {
505
+ textNode = dom.doc.createTextNode('\uFEFF');
506
+ node.parentNode.insertBefore(textNode, node);
507
+
508
+ rng = dom.createRng();
509
+ rng.setStartBefore(textNode);
510
+ rng.setEndAfter(textNode);
511
+
512
+ rects = rng.getClientRects();
513
+ dom.remove(textNode);
514
+ }
515
+
516
+ if (rects.length) {
517
+ return rects[0];
518
+ }
519
+ }
520
+
521
+ // Calculate top cordinate this is needed to avoid scrolling to top of document
522
+ // We want the paste bin to be as close to the caret as possible to avoid scrolling
523
+ if (lastRng.getClientRects) {
524
+ var rect = getCaretRect(lastRng);
525
+
526
+ if (rect) {
527
+ // Client rects gets us closes to the actual
528
+ // caret location in for example a wrapped paragraph block
529
+ top = scrollTop + (rect.top - dom.getPos(body).y);
530
+ } else {
531
+ top = scrollTop;
532
+
533
+ // Check if we can find a closer location by checking the range element
534
+ var container = lastRng.startContainer;
535
+ if (container) {
536
+ if (container.nodeType == 3 && container.parentNode != body) {
537
+ container = container.parentNode;
538
+ }
539
+
540
+ if (container.nodeType == 1) {
541
+ top = dom.getPos(container, scrollContainer || body).y;
542
+ }
543
+ }
544
+ }
545
+ }
546
+
547
+ // Create a pastebin
548
+ pasteBinElm = dom.add(editor.getBody(), 'div', {
549
+ id: "mcepastebin",
550
+ contentEditable: true,
551
+ "data-mce-bogus": "all",
552
+ style: 'position: absolute; top: ' + top + 'px;' +
553
+ 'width: 10px; height: 10px; overflow: hidden; opacity: 0'
554
+ }, pasteBinDefaultContent);
555
+
556
+ // Move paste bin out of sight since the controlSelection rect gets displayed otherwise on IE and Gecko
557
+ if (Env.ie || Env.gecko) {
558
+ dom.setStyle(pasteBinElm, 'left', dom.getStyle(body, 'direction', true) == 'rtl' ? 0xFFFF : -0xFFFF);
559
+ }
560
+
561
+ // Prevent focus events from bubbeling fixed FocusManager issues
562
+ dom.bind(pasteBinElm, 'beforedeactivate focusin focusout', function(e) {
563
+ e.stopPropagation();
564
+ });
565
+
566
+ pasteBinElm.focus();
567
+ editor.selection.select(pasteBinElm, true);
568
+ }
569
+
570
+ /**
571
+ * Removes the paste bin if it exists.
572
+ */
573
+ function removePasteBin() {
574
+ if (pasteBinElm) {
575
+ var pasteBinClone;
576
+
577
+ // WebKit/Blink might clone the div so
578
+ // lets make sure we remove all clones
579
+ // TODO: Man o man is this ugly. WebKit is the new IE! Remove this if they ever fix it!
580
+ while ((pasteBinClone = editor.dom.get('mcepastebin'))) {
581
+ editor.dom.remove(pasteBinClone);
582
+ editor.dom.unbind(pasteBinClone);
583
+ }
584
+
585
+ if (lastRng) {
586
+ editor.selection.setRng(lastRng);
587
+ }
588
+ }
589
+
590
+ pasteBinElm = lastRng = null;
591
+ }
592
+
593
+ /**
594
+ * Returns the contents of the paste bin as a HTML string.
595
+ *
596
+ * @return {String} Get the contents of the paste bin.
597
+ */
598
+ function getPasteBinHtml() {
599
+ var html = '', pasteBinClones, i, clone, cloneHtml;
600
+
601
+ // Since WebKit/Chrome might clone the paste bin when pasting
602
+ // for example: <img style="float: right"> we need to check if any of them contains some useful html.
603
+ // TODO: Man o man is this ugly. WebKit is the new IE! Remove this if they ever fix it!
604
+ pasteBinClones = editor.dom.select('div[id=mcepastebin]');
605
+ for (i = 0; i < pasteBinClones.length; i++) {
606
+ clone = pasteBinClones[i];
607
+
608
+ // Pasting plain text produces pastebins in pastebinds makes sence right!?
609
+ if (clone.firstChild && clone.firstChild.id == 'mcepastebin') {
610
+ clone = clone.firstChild;
611
+ }
612
+
613
+ cloneHtml = clone.innerHTML;
614
+ if (html != pasteBinDefaultContent) {
615
+ html += cloneHtml;
616
+ }
617
+ }
618
+
619
+ return html;
620
+ }
621
+
622
+ /**
623
+ * Gets various content types out of a datatransfer object.
624
+ *
625
+ * @param {DataTransfer} dataTransfer Event fired on paste.
626
+ * @return {Object} Object with mime types and data for those mime types.
627
+ */
628
+ function getDataTransferItems(dataTransfer) {
629
+ var items = {};
630
+
631
+ if (dataTransfer) {
632
+ // Use old WebKit/IE API
633
+ if (dataTransfer.getData) {
634
+ var legacyText = dataTransfer.getData('Text');
635
+ if (legacyText && legacyText.length > 0) {
636
+ if (legacyText.indexOf(mceInternalUrlPrefix) == -1) {
637
+ items['text/plain'] = legacyText;
638
+ }
639
+ }
640
+ }
641
+
642
+ if (dataTransfer.types) {
643
+ for (var i = 0; i < dataTransfer.types.length; i++) {
644
+ var contentType = dataTransfer.types[i];
645
+ items[contentType] = dataTransfer.getData(contentType);
646
+ }
647
+ }
648
+ }
649
+
650
+ return items;
651
+ }
652
+
653
+ /**
654
+ * Gets various content types out of the Clipboard API. It will also get the
655
+ * plain text using older IE and WebKit API:s.
656
+ *
657
+ * @param {ClipboardEvent} clipboardEvent Event fired on paste.
658
+ * @return {Object} Object with mime types and data for those mime types.
659
+ */
660
+ function getClipboardContent(clipboardEvent) {
661
+ return getDataTransferItems(clipboardEvent.clipboardData || editor.getDoc().dataTransfer);
662
+ }
663
+
664
+ function hasHtmlOrText(content) {
665
+ return hasContentType(content, 'text/html') || hasContentType(content, 'text/plain');
666
+ }
667
+
668
+ function getBase64FromUri(uri) {
669
+ var idx;
670
+
671
+ idx = uri.indexOf(',');
672
+ if (idx !== -1) {
673
+ return uri.substr(idx + 1);
674
+ }
675
+
676
+ return null;
677
+ }
678
+
679
+ function isValidDataUriImage(settings, imgElm) {
680
+ return settings.images_dataimg_filter ? settings.images_dataimg_filter(imgElm) : true;
681
+ }
682
+
683
+ function pasteImage(rng, reader, blob) {
684
+ if (rng) {
685
+ editor.selection.setRng(rng);
686
+ rng = null;
687
+ }
688
+
689
+ var dataUri = reader.result;
690
+ var base64 = getBase64FromUri(dataUri);
691
+
692
+ var img = new Image();
693
+ img.src = dataUri;
694
+
695
+ // TODO: Move the bulk of the cache logic to EditorUpload
696
+ if (isValidDataUriImage(editor.settings, img)) {
697
+ var blobCache = editor.editorUpload.blobCache;
698
+ var blobInfo, existingBlobInfo;
699
+
700
+ existingBlobInfo = blobCache.findFirst(function(cachedBlobInfo) {
701
+ return cachedBlobInfo.base64() === base64;
702
+ });
703
+
704
+ if (!existingBlobInfo) {
705
+ blobInfo = blobCache.create(uniqueId(), blob, base64);
706
+ blobCache.add(blobInfo);
707
+ } else {
708
+ blobInfo = existingBlobInfo;
709
+ }
710
+
711
+ pasteHtml('<img src="' + blobInfo.blobUri() + '">');
712
+ } else {
713
+ pasteHtml('<img src="' + dataUri + '">');
714
+ }
715
+ }
716
+
717
+ /**
718
+ * Checks if the clipboard contains image data if it does it will take that data
719
+ * and convert it into a data url image and paste that image at the caret location.
720
+ *
721
+ * @param {ClipboardEvent} e Paste/drop event object.
722
+ * @param {DOMRange} rng Rng object to move selection to.
723
+ * @return {Boolean} true/false if the image data was found or not.
724
+ */
725
+ function pasteImageData(e, rng) {
726
+ var dataTransfer = e.clipboardData || e.dataTransfer;
727
+
728
+ function processItems(items) {
729
+ var i, item, reader, hadImage = false;
730
+
731
+ if (items) {
732
+ for (i = 0; i < items.length; i++) {
733
+ item = items[i];
734
+
735
+ if (/^image\/(jpeg|png|gif|bmp)$/.test(item.type)) {
736
+ var blob = item.getAsFile ? item.getAsFile() : item;
737
+
738
+ reader = new FileReader();
739
+ reader.onload = pasteImage.bind(null, rng, reader, blob);
740
+ reader.readAsDataURL(blob);
741
+
742
+ e.preventDefault();
743
+ hadImage = true;
744
+ }
745
+ }
746
+ }
747
+
748
+ return hadImage;
749
+ }
750
+
751
+ if (editor.settings.paste_data_images && dataTransfer) {
752
+ return processItems(dataTransfer.items) || processItems(dataTransfer.files);
753
+ }
754
+ }
755
+
756
+ /**
757
+ * Chrome on Android doesn't support proper clipboard access so we have no choice but to allow the browser default behavior.
758
+ *
759
+ * @param {Event} e Paste event object to check if it contains any data.
760
+ * @return {Boolean} true/false if the clipboard is empty or not.
761
+ */
762
+ function isBrokenAndroidClipboardEvent(e) {
763
+ var clipboardData = e.clipboardData;
764
+
765
+ return navigator.userAgent.indexOf('Android') != -1 && clipboardData && clipboardData.items && clipboardData.items.length === 0;
766
+ }
767
+
768
+ function getCaretRangeFromEvent(e) {
769
+ return RangeUtils.getCaretRangeFromPoint(e.clientX, e.clientY, editor.getDoc());
770
+ }
771
+
772
+ function hasContentType(clipboardContent, mimeType) {
773
+ return mimeType in clipboardContent && clipboardContent[mimeType].length > 0;
774
+ }
775
+
776
+ function isKeyboardPasteEvent(e) {
777
+ return (VK.metaKeyPressed(e) && e.keyCode == 86) || (e.shiftKey && e.keyCode == 45);
778
+ }
779
+
780
+ function registerEventHandlers() {
781
+ editor.on('keydown', function(e) {
782
+ function removePasteBinOnKeyUp(e) {
783
+ // Ctrl+V or Shift+Insert
784
+ if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
785
+ removePasteBin();
786
+ }
787
+ }
788
+
789
+ // Ctrl+V or Shift+Insert
790
+ if (isKeyboardPasteEvent(e) && !e.isDefaultPrevented()) {
791
+ keyboardPastePlainTextState = e.shiftKey && e.keyCode == 86;
792
+
793
+ // Edge case on Safari on Mac where it doesn't handle Cmd+Shift+V correctly
794
+ // it fires the keydown but no paste or keyup so we are left with a paste bin
795
+ if (keyboardPastePlainTextState && Env.webkit && navigator.userAgent.indexOf('Version/') != -1) {
796
+ return;
797
+ }
798
+
799
+ // Prevent undoManager keydown handler from making an undo level with the pastebin in it
800
+ e.stopImmediatePropagation();
801
+
802
+ keyboardPasteTimeStamp = new Date().getTime();
803
+
804
+ // IE doesn't support Ctrl+Shift+V and it doesn't even produce a paste event
805
+ // so lets fake a paste event and let IE use the execCommand/dataTransfer methods
806
+ if (Env.ie && keyboardPastePlainTextState) {
807
+ e.preventDefault();
808
+ editor.fire('paste', {ieFake: true});
809
+ return;
810
+ }
811
+
812
+ removePasteBin();
813
+ createPasteBin();
814
+
815
+ // Remove pastebin if we get a keyup and no paste event
816
+ // For example pasting a file in IE 11 will not produce a paste event
817
+ editor.once('keyup', removePasteBinOnKeyUp);
818
+ editor.once('paste', function() {
819
+ editor.off('keyup', removePasteBinOnKeyUp);
820
+ });
821
+ }
822
+ });
823
+
824
+ function insertClipboardContent(clipboardContent, isKeyBoardPaste, plainTextMode) {
825
+ var content;
826
+
827
+ // Grab HTML from Clipboard API or paste bin as a fallback
828
+ if (hasContentType(clipboardContent, 'text/html')) {
829
+ content = clipboardContent['text/html'];
830
+ } else {
831
+ content = getPasteBinHtml();
832
+
833
+ // If paste bin is empty try using plain text mode
834
+ // since that is better than nothing right
835
+ if (content == pasteBinDefaultContent) {
836
+ plainTextMode = true;
837
+ }
838
+ }
839
+
840
+ content = Utils.trimHtml(content);
841
+
842
+ // WebKit has a nice bug where it clones the paste bin if you paste from for example notepad
843
+ // so we need to force plain text mode in this case
844
+ if (pasteBinElm && pasteBinElm.firstChild && pasteBinElm.firstChild.id === 'mcepastebin') {
845
+ plainTextMode = true;
846
+ }
847
+
848
+ removePasteBin();
849
+
850
+ // If we got nothing from clipboard API and pastebin then we could try the last resort: plain/text
851
+ if (!content.length) {
852
+ plainTextMode = true;
853
+ }
854
+
855
+ // Grab plain text from Clipboard API or convert existing HTML to plain text
856
+ if (plainTextMode) {
857
+ // Use plain text contents from Clipboard API unless the HTML contains paragraphs then
858
+ // we should convert the HTML to plain text since works better when pasting HTML/Word contents as plain text
859
+ if (hasContentType(clipboardContent, 'text/plain') && content.indexOf('</p>') == -1) {
860
+ content = clipboardContent['text/plain'];
861
+ } else {
862
+ content = Utils.innerText(content);
863
+ }
864
+ }
865
+
866
+ // If the content is the paste bin default HTML then it was
867
+ // impossible to get the cliboard data out.
868
+ if (content == pasteBinDefaultContent) {
869
+ if (!isKeyBoardPaste) {
870
+ editor.windowManager.alert('Please use Ctrl+V/Cmd+V keyboard shortcuts to paste contents.');
871
+ }
872
+
873
+ return;
874
+ }
875
+
876
+ if (plainTextMode) {
877
+ pasteText(content);
878
+ } else {
879
+ pasteHtml(content);
880
+ }
881
+ }
882
+
883
+ var getLastRng = function() {
884
+ return lastRng || editor.selection.getRng();
885
+ };
886
+
887
+ editor.on('paste', function(e) {
888
+ // Getting content from the Clipboard can take some time
889
+ var clipboardTimer = new Date().getTime();
890
+ var clipboardContent = getClipboardContent(e);
891
+ var clipboardDelay = new Date().getTime() - clipboardTimer;
892
+
893
+ var isKeyBoardPaste = (new Date().getTime() - keyboardPasteTimeStamp - clipboardDelay) < 1000;
894
+ var plainTextMode = self.pasteFormat == "text" || keyboardPastePlainTextState;
895
+
896
+ keyboardPastePlainTextState = false;
897
+
898
+ if (e.isDefaultPrevented() || isBrokenAndroidClipboardEvent(e)) {
899
+ removePasteBin();
900
+ return;
901
+ }
902
+
903
+ if (!hasHtmlOrText(clipboardContent) && pasteImageData(e, getLastRng())) {
904
+ removePasteBin();
905
+ return;
906
+ }
907
+
908
+ // Not a keyboard paste prevent default paste and try to grab the clipboard contents using different APIs
909
+ if (!isKeyBoardPaste) {
910
+ e.preventDefault();
911
+ }
912
+
913
+ // Try IE only method if paste isn't a keyboard paste
914
+ if (Env.ie && (!isKeyBoardPaste || e.ieFake)) {
915
+ createPasteBin();
916
+
917
+ editor.dom.bind(pasteBinElm, 'paste', function(e) {
918
+ e.stopPropagation();
919
+ });
920
+
921
+ editor.getDoc().execCommand('Paste', false, null);
922
+ clipboardContent["text/html"] = getPasteBinHtml();
923
+ }
924
+
925
+ // If clipboard API has HTML then use that directly
926
+ if (hasContentType(clipboardContent, 'text/html')) {
927
+ e.preventDefault();
928
+ insertClipboardContent(clipboardContent, isKeyBoardPaste, plainTextMode);
929
+ } else {
930
+ Delay.setEditorTimeout(editor, function() {
931
+ insertClipboardContent(clipboardContent, isKeyBoardPaste, plainTextMode);
932
+ }, 0);
933
+ }
934
+ });
935
+
936
+ editor.on('dragstart dragend', function(e) {
937
+ draggingInternally = e.type == 'dragstart';
938
+ });
939
+
940
+ function isPlainTextFileUrl(content) {
941
+ return content['text/plain'].indexOf('file://') === 0;
942
+ }
943
+
944
+ editor.on('drop', function(e) {
945
+ var dropContent, rng;
946
+
947
+ rng = getCaretRangeFromEvent(e);
948
+
949
+ if (e.isDefaultPrevented() || draggingInternally) {
950
+ return;
951
+ }
952
+
953
+ dropContent = getDataTransferItems(e.dataTransfer);
954
+
955
+ if ((!hasHtmlOrText(dropContent) || isPlainTextFileUrl(dropContent)) && pasteImageData(e, rng)) {
956
+ return;
957
+ }
958
+
959
+ if (rng && editor.settings.paste_filter_drop !== false) {
960
+ var content = dropContent['mce-internal'] || dropContent['text/html'] || dropContent['text/plain'];
961
+
962
+ if (content) {
963
+ e.preventDefault();
964
+
965
+ // FF 45 doesn't paint a caret when dragging in text in due to focus call by execCommand
966
+ Delay.setEditorTimeout(editor, function() {
967
+ editor.undoManager.transact(function() {
968
+ if (dropContent['mce-internal']) {
969
+ editor.execCommand('Delete');
970
+ }
971
+
972
+ editor.selection.setRng(rng);
973
+
974
+ content = Utils.trimHtml(content);
975
+
976
+ if (!dropContent['text/html']) {
977
+ pasteText(content);
978
+ } else {
979
+ pasteHtml(content);
980
+ }
981
+ });
982
+ });
983
+ }
984
+ }
985
+ });
986
+
987
+ editor.on('dragover dragend', function(e) {
988
+ if (editor.settings.paste_data_images) {
989
+ e.preventDefault();
990
+ }
991
+ });
992
+ }
993
+
994
+ self.pasteHtml = pasteHtml;
995
+ self.pasteText = pasteText;
996
+ self.pasteImageData = pasteImageData;
997
+
998
+ editor.on('preInit', function() {
999
+ registerEventHandlers();
1000
+
1001
+ // Remove all data images from paste for example from Gecko
1002
+ // except internal images like video elements
1003
+ editor.parser.addNodeFilter('img', function(nodes, name, args) {
1004
+ function isPasteInsert(args) {
1005
+ return args.data && args.data.paste === true;
1006
+ }
1007
+
1008
+ function remove(node) {
1009
+ if (!node.attr('data-mce-object') && src !== Env.transparentSrc) {
1010
+ node.remove();
1011
+ }
1012
+ }
1013
+
1014
+ function isWebKitFakeUrl(src) {
1015
+ return src.indexOf("webkit-fake-url") === 0;
1016
+ }
1017
+
1018
+ function isDataUri(src) {
1019
+ return src.indexOf("data:") === 0;
1020
+ }
1021
+
1022
+ if (!editor.settings.paste_data_images && isPasteInsert(args)) {
1023
+ var i = nodes.length;
1024
+
1025
+ while (i--) {
1026
+ var src = nodes[i].attributes.map.src;
1027
+
1028
+ if (!src) {
1029
+ continue;
1030
+ }
1031
+
1032
+ // Safari on Mac produces webkit-fake-url see: https://bugs.webkit.org/show_bug.cgi?id=49141
1033
+ if (isWebKitFakeUrl(src)) {
1034
+ remove(nodes[i]);
1035
+ } else if (!editor.settings.allow_html_data_urls && isDataUri(src)) {
1036
+ remove(nodes[i]);
1037
+ }
1038
+ }
1039
+ }
1040
+ });
1041
+ });
1042
+ };
1043
+ });
1044
+
1045
+ // Included from: js/tinymce/plugins/paste/classes/WordFilter.js
1046
+
1047
+ /**
1048
+ * WordFilter.js
1049
+ *
1050
+ * Released under LGPL License.
1051
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
1052
+ *
1053
+ * License: http://www.tinymce.com/license
1054
+ * Contributing: http://www.tinymce.com/contributing
1055
+ */
1056
+
1057
+ /**
1058
+ * This class parses word HTML into proper TinyMCE markup.
1059
+ *
1060
+ * @class tinymce.pasteplugin.WordFilter
1061
+ * @private
1062
+ */
1063
+ define("tinymce/pasteplugin/WordFilter", [
1064
+ "tinymce/util/Tools",
1065
+ "tinymce/html/DomParser",
1066
+ "tinymce/html/Schema",
1067
+ "tinymce/html/Serializer",
1068
+ "tinymce/html/Node",
1069
+ "tinymce/pasteplugin/Utils"
1070
+ ], function(Tools, DomParser, Schema, Serializer, Node, Utils) {
1071
+ /**
1072
+ * Checks if the specified content is from any of the following sources: MS Word/Office 365/Google docs.
1073
+ */
1074
+ function isWordContent(content) {
1075
+ return (
1076
+ (/<font face="Times New Roman"|class="?Mso|style="[^"]*\bmso-|style='[^'']*\bmso-|w:WordDocument/i).test(content) ||
1077
+ (/class="OutlineElement/).test(content) ||
1078
+ (/id="?docs\-internal\-guid\-/.test(content))
1079
+ );
1080
+ }
1081
+
1082
+ /**
1083
+ * Checks if the specified text starts with "1. " or "a. " etc.
1084
+ */
1085
+ function isNumericList(text) {
1086
+ var found, patterns;
1087
+
1088
+ patterns = [
1089
+ /^[IVXLMCD]{1,2}\.[ \u00a0]/, // Roman upper case
1090
+ /^[ivxlmcd]{1,2}\.[ \u00a0]/, // Roman lower case
1091
+ /^[a-z]{1,2}[\.\)][ \u00a0]/, // Alphabetical a-z
1092
+ /^[A-Z]{1,2}[\.\)][ \u00a0]/, // Alphabetical A-Z
1093
+ /^[0-9]+\.[ \u00a0]/, // Numeric lists
1094
+ /^[\u3007\u4e00\u4e8c\u4e09\u56db\u4e94\u516d\u4e03\u516b\u4e5d]+\.[ \u00a0]/, // Japanese
1095
+ /^[\u58f1\u5f10\u53c2\u56db\u4f0d\u516d\u4e03\u516b\u4e5d\u62fe]+\.[ \u00a0]/ // Chinese
1096
+ ];
1097
+
1098
+ text = text.replace(/^[\u00a0 ]+/, '');
1099
+
1100
+ Tools.each(patterns, function(pattern) {
1101
+ if (pattern.test(text)) {
1102
+ found = true;
1103
+ return false;
1104
+ }
1105
+ });
1106
+
1107
+ return found;
1108
+ }
1109
+
1110
+ function isBulletList(text) {
1111
+ return /^[\s\u00a0]*[\u2022\u00b7\u00a7\u25CF]\s*/.test(text);
1112
+ }
1113
+
1114
+ function WordFilter(editor) {
1115
+ var settings = editor.settings;
1116
+
1117
+ editor.on('BeforePastePreProcess', function(e) {
1118
+ var content = e.content, retainStyleProperties, validStyles;
1119
+
1120
+ // Remove google docs internal guid markers
1121
+ content = content.replace(/<b[^>]+id="?docs-internal-[^>]*>/gi, '');
1122
+ content = content.replace(/<br class="?Apple-interchange-newline"?>/gi, '');
1123
+
1124
+ retainStyleProperties = settings.paste_retain_style_properties;
1125
+ if (retainStyleProperties) {
1126
+ validStyles = Tools.makeMap(retainStyleProperties.split(/[, ]/));
1127
+ }
1128
+
1129
+ /**
1130
+ * Converts fake bullet and numbered lists to real semantic OL/UL.
1131
+ *
1132
+ * @param {tinymce.html.Node} node Root node to convert children of.
1133
+ */
1134
+ function convertFakeListsToProperLists(node) {
1135
+ var currentListNode, prevListNode, lastLevel = 1;
1136
+
1137
+ function getText(node) {
1138
+ var txt = '';
1139
+
1140
+ if (node.type === 3) {
1141
+ return node.value;
1142
+ }
1143
+
1144
+ if ((node = node.firstChild)) {
1145
+ do {
1146
+ txt += getText(node);
1147
+ } while ((node = node.next));
1148
+ }
1149
+
1150
+ return txt;
1151
+ }
1152
+
1153
+ function trimListStart(node, regExp) {
1154
+ if (node.type === 3) {
1155
+ if (regExp.test(node.value)) {
1156
+ node.value = node.value.replace(regExp, '');
1157
+ return false;
1158
+ }
1159
+ }
1160
+
1161
+ if ((node = node.firstChild)) {
1162
+ do {
1163
+ if (!trimListStart(node, regExp)) {
1164
+ return false;
1165
+ }
1166
+ } while ((node = node.next));
1167
+ }
1168
+
1169
+ return true;
1170
+ }
1171
+
1172
+ function removeIgnoredNodes(node) {
1173
+ if (node._listIgnore) {
1174
+ node.remove();
1175
+ return;
1176
+ }
1177
+
1178
+ if ((node = node.firstChild)) {
1179
+ do {
1180
+ removeIgnoredNodes(node);
1181
+ } while ((node = node.next));
1182
+ }
1183
+ }
1184
+
1185
+ function convertParagraphToLi(paragraphNode, listName, start) {
1186
+ var level = paragraphNode._listLevel || lastLevel;
1187
+
1188
+ // Handle list nesting
1189
+ if (level != lastLevel) {
1190
+ if (level < lastLevel) {
1191
+ // Move to parent list
1192
+ if (currentListNode) {
1193
+ currentListNode = currentListNode.parent.parent;
1194
+ }
1195
+ } else {
1196
+ // Create new list
1197
+ prevListNode = currentListNode;
1198
+ currentListNode = null;
1199
+ }
1200
+ }
1201
+
1202
+ if (!currentListNode || currentListNode.name != listName) {
1203
+ prevListNode = prevListNode || currentListNode;
1204
+ currentListNode = new Node(listName, 1);
1205
+
1206
+ if (start > 1) {
1207
+ currentListNode.attr('start', '' + start);
1208
+ }
1209
+
1210
+ paragraphNode.wrap(currentListNode);
1211
+ } else {
1212
+ currentListNode.append(paragraphNode);
1213
+ }
1214
+
1215
+ paragraphNode.name = 'li';
1216
+
1217
+ // Append list to previous list if it exists
1218
+ if (level > lastLevel && prevListNode) {
1219
+ prevListNode.lastChild.append(currentListNode);
1220
+ }
1221
+
1222
+ lastLevel = level;
1223
+
1224
+ // Remove start of list item "1. " or "&middot; " etc
1225
+ removeIgnoredNodes(paragraphNode);
1226
+ trimListStart(paragraphNode, /^\u00a0+/);
1227
+ trimListStart(paragraphNode, /^\s*([\u2022\u00b7\u00a7\u25CF]|\w+\.)/);
1228
+ trimListStart(paragraphNode, /^\u00a0+/);
1229
+ }
1230
+
1231
+ // Build a list of all root level elements before we start
1232
+ // altering them in the loop below.
1233
+ var elements = [], child = node.firstChild;
1234
+ while (typeof child !== 'undefined' && child !== null) {
1235
+ elements.push(child);
1236
+
1237
+ child = child.walk();
1238
+ if (child !== null) {
1239
+ while (typeof child !== 'undefined' && child.parent !== node) {
1240
+ child = child.walk();
1241
+ }
1242
+ }
1243
+ }
1244
+
1245
+ for (var i = 0; i < elements.length; i++) {
1246
+ node = elements[i];
1247
+
1248
+ if (node.name == 'p' && node.firstChild) {
1249
+ // Find first text node in paragraph
1250
+ var nodeText = getText(node);
1251
+
1252
+ // Detect unordered lists look for bullets
1253
+ if (isBulletList(nodeText)) {
1254
+ convertParagraphToLi(node, 'ul');
1255
+ continue;
1256
+ }
1257
+
1258
+ // Detect ordered lists 1., a. or ixv.
1259
+ if (isNumericList(nodeText)) {
1260
+ // Parse OL start number
1261
+ var matches = /([0-9]+)\./.exec(nodeText);
1262
+ var start = 1;
1263
+ if (matches) {
1264
+ start = parseInt(matches[1], 10);
1265
+ }
1266
+
1267
+ convertParagraphToLi(node, 'ol', start);
1268
+ continue;
1269
+ }
1270
+
1271
+ // Convert paragraphs marked as lists but doesn't look like anything
1272
+ if (node._listLevel) {
1273
+ convertParagraphToLi(node, 'ul', 1);
1274
+ continue;
1275
+ }
1276
+
1277
+ currentListNode = null;
1278
+ } else {
1279
+ // If the root level element isn't a p tag which can be
1280
+ // processed by convertParagraphToLi, it interrupts the
1281
+ // lists, causing a new list to start instead of having
1282
+ // elements from the next list inserted above this tag.
1283
+ prevListNode = currentListNode;
1284
+ currentListNode = null;
1285
+ }
1286
+ }
1287
+ }
1288
+
1289
+ function filterStyles(node, styleValue) {
1290
+ var outputStyles = {}, matches, styles = editor.dom.parseStyle(styleValue);
1291
+
1292
+ Tools.each(styles, function(value, name) {
1293
+ // Convert various MS styles to W3C styles
1294
+ switch (name) {
1295
+ case 'mso-list':
1296
+ // Parse out list indent level for lists
1297
+ matches = /\w+ \w+([0-9]+)/i.exec(styleValue);
1298
+ if (matches) {
1299
+ node._listLevel = parseInt(matches[1], 10);
1300
+ }
1301
+
1302
+ // Remove these nodes <span style="mso-list:Ignore">o</span>
1303
+ // Since the span gets removed we mark the text node and the span
1304
+ if (/Ignore/i.test(value) && node.firstChild) {
1305
+ node._listIgnore = true;
1306
+ node.firstChild._listIgnore = true;
1307
+ }
1308
+
1309
+ break;
1310
+
1311
+ case "horiz-align":
1312
+ name = "text-align";
1313
+ break;
1314
+
1315
+ case "vert-align":
1316
+ name = "vertical-align";
1317
+ break;
1318
+
1319
+ case "font-color":
1320
+ case "mso-foreground":
1321
+ name = "color";
1322
+ break;
1323
+
1324
+ case "mso-background":
1325
+ case "mso-highlight":
1326
+ name = "background";
1327
+ break;
1328
+
1329
+ case "font-weight":
1330
+ case "font-style":
1331
+ if (value != "normal") {
1332
+ outputStyles[name] = value;
1333
+ }
1334
+ return;
1335
+
1336
+ case "mso-element":
1337
+ // Remove track changes code
1338
+ if (/^(comment|comment-list)$/i.test(value)) {
1339
+ node.remove();
1340
+ return;
1341
+ }
1342
+
1343
+ break;
1344
+ }
1345
+
1346
+ if (name.indexOf('mso-comment') === 0) {
1347
+ node.remove();
1348
+ return;
1349
+ }
1350
+
1351
+ // Never allow mso- prefixed names
1352
+ if (name.indexOf('mso-') === 0) {
1353
+ return;
1354
+ }
1355
+
1356
+ // Output only valid styles
1357
+ if (retainStyleProperties == "all" || (validStyles && validStyles[name])) {
1358
+ outputStyles[name] = value;
1359
+ }
1360
+ });
1361
+
1362
+ // Convert bold style to "b" element
1363
+ if (/(bold)/i.test(outputStyles["font-weight"])) {
1364
+ delete outputStyles["font-weight"];
1365
+ node.wrap(new Node("b", 1));
1366
+ }
1367
+
1368
+ // Convert italic style to "i" element
1369
+ if (/(italic)/i.test(outputStyles["font-style"])) {
1370
+ delete outputStyles["font-style"];
1371
+ node.wrap(new Node("i", 1));
1372
+ }
1373
+
1374
+ // Serialize the styles and see if there is something left to keep
1375
+ outputStyles = editor.dom.serializeStyle(outputStyles, node.name);
1376
+ if (outputStyles) {
1377
+ return outputStyles;
1378
+ }
1379
+
1380
+ return null;
1381
+ }
1382
+
1383
+ if (settings.paste_enable_default_filters === false) {
1384
+ return;
1385
+ }
1386
+
1387
+ // Detect is the contents is Word junk HTML
1388
+ if (isWordContent(e.content)) {
1389
+ e.wordContent = true; // Mark it for other processors
1390
+
1391
+ // Remove basic Word junk
1392
+ content = Utils.filter(content, [
1393
+ // Word comments like conditional comments etc
1394
+ /<!--[\s\S]+?-->/gi,
1395
+
1396
+ // Remove comments, scripts (e.g., msoShowComment), XML tag, VML content,
1397
+ // MS Office namespaced tags, and a few other tags
1398
+ /<(!|script[^>]*>.*?<\/script(?=[>\s])|\/?(\?xml(:\w+)?|img|meta|link|style|\w:\w+)(?=[\s\/>]))[^>]*>/gi,
1399
+
1400
+ // Convert <s> into <strike> for line-though
1401
+ [/<(\/?)s>/gi, "<$1strike>"],
1402
+
1403
+ // Replace nsbp entites to char since it's easier to handle
1404
+ [/&nbsp;/gi, "\u00a0"],
1405
+
1406
+ // Convert <span style="mso-spacerun:yes">___</span> to string of alternating
1407
+ // breaking/non-breaking spaces of same length
1408
+ [/<span\s+style\s*=\s*"\s*mso-spacerun\s*:\s*yes\s*;?\s*"\s*>([\s\u00a0]*)<\/span>/gi,
1409
+ function(str, spaces) {
1410
+ return (spaces.length > 0) ?
1411
+ spaces.replace(/./, " ").slice(Math.floor(spaces.length / 2)).split("").join("\u00a0") : "";
1412
+ }
1413
+ ]
1414
+ ]);
1415
+
1416
+ var validElements = settings.paste_word_valid_elements;
1417
+ if (!validElements) {
1418
+ validElements = (
1419
+ '-strong/b,-em/i,-u,-span,-p,-ol,-ul,-li,-h1,-h2,-h3,-h4,-h5,-h6,' +
1420
+ '-p/div,-a[href|name],sub,sup,strike,br,del,table[width],tr,' +
1421
+ 'td[colspan|rowspan|width],th[colspan|rowspan|width],thead,tfoot,tbody'
1422
+ );
1423
+ }
1424
+
1425
+ // Setup strict schema
1426
+ var schema = new Schema({
1427
+ valid_elements: validElements,
1428
+ valid_children: '-li[p]'
1429
+ });
1430
+
1431
+ // Add style/class attribute to all element rules since the user might have removed them from
1432
+ // paste_word_valid_elements config option and we need to check them for properties
1433
+ Tools.each(schema.elements, function(rule) {
1434
+ /*eslint dot-notation:0*/
1435
+ if (!rule.attributes["class"]) {
1436
+ rule.attributes["class"] = {};
1437
+ rule.attributesOrder.push("class");
1438
+ }
1439
+
1440
+ if (!rule.attributes.style) {
1441
+ rule.attributes.style = {};
1442
+ rule.attributesOrder.push("style");
1443
+ }
1444
+ });
1445
+
1446
+ // Parse HTML into DOM structure
1447
+ var domParser = new DomParser({}, schema);
1448
+
1449
+ // Filter styles to remove "mso" specific styles and convert some of them
1450
+ domParser.addAttributeFilter('style', function(nodes) {
1451
+ var i = nodes.length, node;
1452
+
1453
+ while (i--) {
1454
+ node = nodes[i];
1455
+ node.attr('style', filterStyles(node, node.attr('style')));
1456
+
1457
+ // Remove pointess spans
1458
+ if (node.name == 'span' && node.parent && !node.attributes.length) {
1459
+ node.unwrap();
1460
+ }
1461
+ }
1462
+ });
1463
+
1464
+ // Check the class attribute for comments or del items and remove those
1465
+ domParser.addAttributeFilter('class', function(nodes) {
1466
+ var i = nodes.length, node, className;
1467
+
1468
+ while (i--) {
1469
+ node = nodes[i];
1470
+
1471
+ className = node.attr('class');
1472
+ if (/^(MsoCommentReference|MsoCommentText|msoDel)$/i.test(className)) {
1473
+ node.remove();
1474
+ }
1475
+
1476
+ node.attr('class', null);
1477
+ }
1478
+ });
1479
+
1480
+ // Remove all del elements since we don't want the track changes code in the editor
1481
+ domParser.addNodeFilter('del', function(nodes) {
1482
+ var i = nodes.length;
1483
+
1484
+ while (i--) {
1485
+ nodes[i].remove();
1486
+ }
1487
+ });
1488
+
1489
+ // Keep some of the links and anchors
1490
+ domParser.addNodeFilter('a', function(nodes) {
1491
+ var i = nodes.length, node, href, name;
1492
+
1493
+ while (i--) {
1494
+ node = nodes[i];
1495
+ href = node.attr('href');
1496
+ name = node.attr('name');
1497
+
1498
+ if (href && href.indexOf('#_msocom_') != -1) {
1499
+ node.remove();
1500
+ continue;
1501
+ }
1502
+
1503
+ if (href && href.indexOf('file://') === 0) {
1504
+ href = href.split('#')[1];
1505
+ if (href) {
1506
+ href = '#' + href;
1507
+ }
1508
+ }
1509
+
1510
+ if (!href && !name) {
1511
+ node.unwrap();
1512
+ } else {
1513
+ // Remove all named anchors that aren't specific to TOC, Footnotes or Endnotes
1514
+ if (name && !/^_?(?:toc|edn|ftn)/i.test(name)) {
1515
+ node.unwrap();
1516
+ continue;
1517
+ }
1518
+
1519
+ node.attr({
1520
+ href: href,
1521
+ name: name
1522
+ });
1523
+ }
1524
+ }
1525
+ });
1526
+
1527
+ // Parse into DOM structure
1528
+ var rootNode = domParser.parse(content);
1529
+
1530
+ // Process DOM
1531
+ if (settings.paste_convert_word_fake_lists !== false) {
1532
+ convertFakeListsToProperLists(rootNode);
1533
+ }
1534
+
1535
+ // Serialize DOM back to HTML
1536
+ e.content = new Serializer({
1537
+ validate: settings.validate
1538
+ }, schema).serialize(rootNode);
1539
+ }
1540
+ });
1541
+ }
1542
+
1543
+ WordFilter.isWordContent = isWordContent;
1544
+
1545
+ return WordFilter;
1546
+ });
1547
+
1548
+ // Included from: js/tinymce/plugins/paste/classes/Quirks.js
1549
+
1550
+ /**
1551
+ * Quirks.js
1552
+ *
1553
+ * Released under LGPL License.
1554
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
1555
+ *
1556
+ * License: http://www.tinymce.com/license
1557
+ * Contributing: http://www.tinymce.com/contributing
1558
+ */
1559
+
1560
+ /**
1561
+ * This class contains various fixes for browsers. These issues can not be feature
1562
+ * detected since we have no direct control over the clipboard. However we might be able
1563
+ * to remove some of these fixes once the browsers gets updated/fixed.
1564
+ *
1565
+ * @class tinymce.pasteplugin.Quirks
1566
+ * @private
1567
+ */
1568
+ define("tinymce/pasteplugin/Quirks", [
1569
+ "tinymce/Env",
1570
+ "tinymce/util/Tools",
1571
+ "tinymce/pasteplugin/WordFilter",
1572
+ "tinymce/pasteplugin/Utils"
1573
+ ], function(Env, Tools, WordFilter, Utils) {
1574
+ "use strict";
1575
+
1576
+ return function(editor) {
1577
+ function addPreProcessFilter(filterFunc) {
1578
+ editor.on('BeforePastePreProcess', function(e) {
1579
+ e.content = filterFunc(e.content);
1580
+ });
1581
+ }
1582
+
1583
+ /**
1584
+ * Removes BR elements after block elements. IE9 has a nasty bug where it puts a BR element after each
1585
+ * block element when pasting from word. This removes those elements.
1586
+ *
1587
+ * This:
1588
+ * <p>a</p><br><p>b</p>
1589
+ *
1590
+ * Becomes:
1591
+ * <p>a</p><p>b</p>
1592
+ */
1593
+ function removeExplorerBrElementsAfterBlocks(html) {
1594
+ // Only filter word specific content
1595
+ if (!WordFilter.isWordContent(html)) {
1596
+ return html;
1597
+ }
1598
+
1599
+ // Produce block regexp based on the block elements in schema
1600
+ var blockElements = [];
1601
+
1602
+ Tools.each(editor.schema.getBlockElements(), function(block, blockName) {
1603
+ blockElements.push(blockName);
1604
+ });
1605
+
1606
+ var explorerBlocksRegExp = new RegExp(
1607
+ '(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*(<\\/?(' + blockElements.join('|') + ')[^>]*>)(?:<br>&nbsp;[\\s\\r\\n]+|<br>)*',
1608
+ 'g'
1609
+ );
1610
+
1611
+ // Remove BR:s from: <BLOCK>X</BLOCK><BR>
1612
+ html = Utils.filter(html, [
1613
+ [explorerBlocksRegExp, '$1']
1614
+ ]);
1615
+
1616
+ // IE9 also adds an extra BR element for each soft-linefeed and it also adds a BR for each word wrap break
1617
+ html = Utils.filter(html, [
1618
+ [/<br><br>/g, '<BR><BR>'], // Replace multiple BR elements with uppercase BR to keep them intact
1619
+ [/<br>/g, ' '], // Replace single br elements with space since they are word wrap BR:s
1620
+ [/<BR><BR>/g, '<br>'] // Replace back the double brs but into a single BR
1621
+ ]);
1622
+
1623
+ return html;
1624
+ }
1625
+
1626
+ /**
1627
+ * WebKit has a nasty bug where the all computed styles gets added to style attributes when copy/pasting contents.
1628
+ * This fix solves that by simply removing the whole style attribute.
1629
+ *
1630
+ * The paste_webkit_styles option can be set to specify what to keep:
1631
+ * paste_webkit_styles: "none" // Keep no styles
1632
+ * paste_webkit_styles: "all", // Keep all of them
1633
+ * paste_webkit_styles: "font-weight color" // Keep specific ones
1634
+ *
1635
+ * @param {String} content Content that needs to be processed.
1636
+ * @return {String} Processed contents.
1637
+ */
1638
+ function removeWebKitStyles(content) {
1639
+ // Passthrough all styles from Word and let the WordFilter handle that junk
1640
+ if (WordFilter.isWordContent(content)) {
1641
+ return content;
1642
+ }
1643
+
1644
+ // Filter away styles that isn't matching the target node
1645
+ var webKitStyles = editor.settings.paste_webkit_styles;
1646
+
1647
+ if (editor.settings.paste_remove_styles_if_webkit === false || webKitStyles == "all") {
1648
+ return content;
1649
+ }
1650
+
1651
+ if (webKitStyles) {
1652
+ webKitStyles = webKitStyles.split(/[, ]/);
1653
+ }
1654
+
1655
+ // Keep specific styles that doesn't match the current node computed style
1656
+ if (webKitStyles) {
1657
+ var dom = editor.dom, node = editor.selection.getNode();
1658
+
1659
+ content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, function(all, before, value, after) {
1660
+ var inputStyles = dom.parseStyle(value, 'span'), outputStyles = {};
1661
+
1662
+ if (webKitStyles === "none") {
1663
+ return before + after;
1664
+ }
1665
+
1666
+ for (var i = 0; i < webKitStyles.length; i++) {
1667
+ var inputValue = inputStyles[webKitStyles[i]], currentValue = dom.getStyle(node, webKitStyles[i], true);
1668
+
1669
+ if (/color/.test(webKitStyles[i])) {
1670
+ inputValue = dom.toHex(inputValue);
1671
+ currentValue = dom.toHex(currentValue);
1672
+ }
1673
+
1674
+ if (currentValue != inputValue) {
1675
+ outputStyles[webKitStyles[i]] = inputValue;
1676
+ }
1677
+ }
1678
+
1679
+ outputStyles = dom.serializeStyle(outputStyles, 'span');
1680
+ if (outputStyles) {
1681
+ return before + ' style="' + outputStyles + '"' + after;
1682
+ }
1683
+
1684
+ return before + after;
1685
+ });
1686
+ } else {
1687
+ // Remove all external styles
1688
+ content = content.replace(/(<[^>]+) style="([^"]*)"([^>]*>)/gi, '$1$3');
1689
+ }
1690
+
1691
+ // Keep internal styles
1692
+ content = content.replace(/(<[^>]+) data-mce-style="([^"]+)"([^>]*>)/gi, function(all, before, value, after) {
1693
+ return before + ' style="' + value + '"' + after;
1694
+ });
1695
+
1696
+ return content;
1697
+ }
1698
+
1699
+ // Sniff browsers and apply fixes since we can't feature detect
1700
+ if (Env.webkit) {
1701
+ addPreProcessFilter(removeWebKitStyles);
1702
+ }
1703
+
1704
+ if (Env.ie) {
1705
+ addPreProcessFilter(removeExplorerBrElementsAfterBlocks);
1706
+ }
1707
+ };
1708
+ });
1709
+
1710
+ // Included from: js/tinymce/plugins/paste/classes/Plugin.js
1711
+
1712
+ /**
1713
+ * Plugin.js
1714
+ *
1715
+ * Released under LGPL License.
1716
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
1717
+ *
1718
+ * License: http://www.tinymce.com/license
1719
+ * Contributing: http://www.tinymce.com/contributing
1720
+ */
1721
+
1722
+ /**
1723
+ * This class contains the tinymce plugin logic for the paste plugin.
1724
+ *
1725
+ * @class tinymce.pasteplugin.Plugin
1726
+ * @private
1727
+ */
1728
+ define("tinymce/pasteplugin/Plugin", [
1729
+ "tinymce/PluginManager",
1730
+ "tinymce/pasteplugin/Clipboard",
1731
+ "tinymce/pasteplugin/WordFilter",
1732
+ "tinymce/pasteplugin/Quirks"
1733
+ ], function(PluginManager, Clipboard, WordFilter, Quirks) {
1734
+ var userIsInformed;
1735
+
1736
+ PluginManager.add('paste', function(editor) {
1737
+ var self = this, clipboard, settings = editor.settings;
1738
+
1739
+ function isUserInformedAboutPlainText() {
1740
+ return userIsInformed || editor.settings.paste_plaintext_inform === false;
1741
+ }
1742
+
1743
+ function togglePlainTextPaste() {
1744
+ if (clipboard.pasteFormat == "text") {
1745
+ this.active(false);
1746
+ clipboard.pasteFormat = "html";
1747
+ editor.fire('PastePlainTextToggle', {state: false});
1748
+ } else {
1749
+ clipboard.pasteFormat = "text";
1750
+ this.active(true);
1751
+
1752
+ if (!isUserInformedAboutPlainText()) {
1753
+ var message = editor.translate('Paste is now in plain text mode. Contents will now ' +
1754
+ 'be pasted as plain text until you toggle this option off.');
1755
+
1756
+ editor.notificationManager.open({
1757
+ text: message,
1758
+ type: 'info'
1759
+ });
1760
+
1761
+ userIsInformed = true;
1762
+ editor.fire('PastePlainTextToggle', {state: true});
1763
+ }
1764
+ }
1765
+
1766
+ editor.focus();
1767
+ }
1768
+
1769
+ // draw back if power version is requested and registered
1770
+ if (/(^|[ ,])powerpaste([, ]|$)/.test(settings.plugins) && PluginManager.get('powerpaste')) {
1771
+ /*eslint no-console:0 */
1772
+ if (typeof console !== "undefined" && console.log) {
1773
+ console.log("PowerPaste is incompatible with Paste plugin! Remove 'paste' from the 'plugins' option.");
1774
+ }
1775
+ return;
1776
+ }
1777
+
1778
+ self.clipboard = clipboard = new Clipboard(editor);
1779
+ self.quirks = new Quirks(editor);
1780
+ self.wordFilter = new WordFilter(editor);
1781
+
1782
+ if (editor.settings.paste_as_text) {
1783
+ self.clipboard.pasteFormat = "text";
1784
+ }
1785
+
1786
+ if (settings.paste_preprocess) {
1787
+ editor.on('PastePreProcess', function(e) {
1788
+ settings.paste_preprocess.call(self, self, e);
1789
+ });
1790
+ }
1791
+
1792
+ if (settings.paste_postprocess) {
1793
+ editor.on('PastePostProcess', function(e) {
1794
+ settings.paste_postprocess.call(self, self, e);
1795
+ });
1796
+ }
1797
+
1798
+ editor.addCommand('mceInsertClipboardContent', function(ui, value) {
1799
+ if (value.content) {
1800
+ self.clipboard.pasteHtml(value.content);
1801
+ }
1802
+
1803
+ if (value.text) {
1804
+ self.clipboard.pasteText(value.text);
1805
+ }
1806
+ });
1807
+
1808
+ // Block all drag/drop events
1809
+ if (editor.settings.paste_block_drop) {
1810
+ editor.on('dragend dragover draggesture dragdrop drop drag', function(e) {
1811
+ e.preventDefault();
1812
+ e.stopPropagation();
1813
+ });
1814
+ }
1815
+
1816
+ // Prevent users from dropping data images on Gecko
1817
+ if (!editor.settings.paste_data_images) {
1818
+ editor.on('drop', function(e) {
1819
+ var dataTransfer = e.dataTransfer;
1820
+
1821
+ if (dataTransfer && dataTransfer.files && dataTransfer.files.length > 0) {
1822
+ e.preventDefault();
1823
+ }
1824
+ });
1825
+ }
1826
+
1827
+ editor.addButton('pastetext', {
1828
+ icon: 'pastetext',
1829
+ tooltip: 'Paste as text',
1830
+ onclick: togglePlainTextPaste,
1831
+ active: self.clipboard.pasteFormat == "text"
1832
+ });
1833
+
1834
+ editor.addMenuItem('pastetext', {
1835
+ text: 'Paste as text',
1836
+ selectable: true,
1837
+ active: clipboard.pasteFormat,
1838
+ onclick: togglePlainTextPaste
1839
+ });
1840
+ });
1841
+ });
1842
+
1843
+ expose(["tinymce/pasteplugin/Utils"]);
1844
+ })(this);