mosaico 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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);