spiderfw 0.6.38 → 0.6.39

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (515) hide show
  1. checksums.yaml +13 -5
  2. data/CHANGELOG +23 -0
  3. data/VERSION +1 -1
  4. data/apps/core/admin/views/admin.layout.shtml +6 -0
  5. data/apps/core/auth/controllers/login_controller.rb +1 -1
  6. data/apps/core/components/assets.rb +55 -6
  7. data/apps/core/components/public/bootstrap/scss/_variables.scss +5 -2
  8. data/apps/core/components/public/bootstrap/scss/bootstrap.css +942 -236
  9. data/apps/core/components/public/bootstrap/scss/responsive.css +187 -30
  10. data/apps/core/components/public/css/tinymce/skins/lightgray/AbsoluteLayout.less +17 -0
  11. data/apps/core/components/public/css/tinymce/skins/lightgray/Animations.less +10 -0
  12. data/apps/core/components/public/css/tinymce/skins/lightgray/Button.less +172 -0
  13. data/apps/core/components/public/css/tinymce/skins/lightgray/ButtonGroup.less +71 -0
  14. data/apps/core/components/public/css/tinymce/skins/lightgray/Checkbox.less +49 -0
  15. data/apps/core/components/public/css/tinymce/skins/lightgray/ColorBox.less +6 -0
  16. data/apps/core/components/public/css/tinymce/skins/lightgray/ColorButton.less +72 -0
  17. data/apps/core/components/public/css/tinymce/skins/lightgray/ColorPicker.less +80 -0
  18. data/apps/core/components/public/css/tinymce/skins/lightgray/ComboBox.less +39 -0
  19. data/apps/core/components/public/css/tinymce/skins/lightgray/Container.less +9 -0
  20. data/apps/core/components/public/css/tinymce/skins/lightgray/Content.Inline.less +4 -0
  21. data/apps/core/components/public/css/tinymce/skins/lightgray/Content.Objects.less +166 -0
  22. data/apps/core/components/public/css/tinymce/skins/lightgray/Content.less +27 -0
  23. data/apps/core/components/public/css/tinymce/skins/lightgray/CropRect.less +54 -0
  24. data/apps/core/components/public/css/tinymce/skins/lightgray/FieldSet.less +15 -0
  25. data/apps/core/components/public/css/tinymce/skins/lightgray/FitLayout.less +9 -0
  26. data/apps/core/components/public/css/tinymce/skins/lightgray/FloatPanel.less +69 -0
  27. data/apps/core/components/public/css/tinymce/skins/lightgray/FlowLayout.less +36 -0
  28. data/apps/core/components/public/css/tinymce/skins/lightgray/Icons.Ie7.less +136 -0
  29. data/apps/core/components/public/css/tinymce/skins/lightgray/Icons.less +180 -0
  30. data/apps/core/components/public/css/tinymce/skins/lightgray/Iframe.less +6 -0
  31. data/apps/core/components/public/css/tinymce/skins/lightgray/ImagePanel.less +20 -0
  32. data/apps/core/components/public/css/tinymce/skins/lightgray/InfoBox.less +71 -0
  33. data/apps/core/components/public/css/tinymce/skins/lightgray/Label.less +38 -0
  34. data/apps/core/components/public/css/tinymce/skins/lightgray/ListBox.less +26 -0
  35. data/apps/core/components/public/css/tinymce/skins/lightgray/Menu.less +34 -0
  36. data/apps/core/components/public/css/tinymce/skins/lightgray/MenuBar.less +32 -0
  37. data/apps/core/components/public/css/tinymce/skins/lightgray/MenuButton.less +34 -0
  38. data/apps/core/components/public/css/tinymce/skins/lightgray/MenuItem.less +142 -0
  39. data/apps/core/components/public/css/tinymce/skins/lightgray/Mixins.less +54 -0
  40. data/apps/core/components/public/css/tinymce/skins/lightgray/Notification.less +144 -0
  41. data/apps/core/components/public/css/tinymce/skins/lightgray/Panel.less +7 -0
  42. data/apps/core/components/public/css/tinymce/skins/lightgray/Path.less +45 -0
  43. data/apps/core/components/public/css/tinymce/skins/lightgray/Progress.less +34 -0
  44. data/apps/core/components/public/css/tinymce/skins/lightgray/Radio.less +1 -0
  45. data/apps/core/components/public/css/tinymce/skins/lightgray/Reset.less +32 -0
  46. data/apps/core/components/public/css/tinymce/skins/lightgray/ResizeHandle.less +18 -0
  47. data/apps/core/components/public/css/tinymce/skins/lightgray/Scrollable.less +44 -0
  48. data/apps/core/components/public/css/tinymce/skins/lightgray/SelectBox.less +6 -0
  49. data/apps/core/components/public/css/tinymce/skins/lightgray/Slider.less +29 -0
  50. data/apps/core/components/public/css/tinymce/skins/lightgray/Spacer.less +5 -0
  51. data/apps/core/components/public/css/tinymce/skins/lightgray/SplitButton.less +49 -0
  52. data/apps/core/components/public/css/tinymce/skins/lightgray/StackLayout.less +5 -0
  53. data/apps/core/components/public/css/tinymce/skins/lightgray/TabPanel.less +44 -0
  54. data/apps/core/components/public/css/tinymce/skins/lightgray/TextBox.less +41 -0
  55. data/apps/core/components/public/css/tinymce/skins/lightgray/Throbber.less +19 -0
  56. data/apps/core/components/public/css/tinymce/skins/lightgray/TinyMCE.less +159 -0
  57. data/apps/core/components/public/css/tinymce/skins/lightgray/ToolTip.less +129 -0
  58. data/apps/core/components/public/css/tinymce/skins/lightgray/Variables.less +214 -0
  59. data/apps/core/components/public/css/tinymce/skins/lightgray/Window.less +127 -0
  60. data/apps/core/components/public/css/tinymce/skins/lightgray/content.inline.min.css +1 -0
  61. data/apps/core/components/public/css/tinymce/skins/lightgray/content.min.css +1 -0
  62. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/readme.md +1 -0
  63. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce-small.eot +0 -0
  64. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce-small.json +1277 -0
  65. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce-small.svg +63 -0
  66. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce-small.ttf +0 -0
  67. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce-small.woff +0 -0
  68. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce.eot +0 -0
  69. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce.json +3381 -0
  70. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce.svg +129 -0
  71. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce.ttf +0 -0
  72. data/apps/core/components/public/css/tinymce/skins/lightgray/fonts/tinymce.woff +0 -0
  73. data/apps/core/components/public/css/tinymce/skins/lightgray/img/anchor.gif +0 -0
  74. data/apps/core/components/public/css/tinymce/skins/lightgray/img/loader.gif +0 -0
  75. data/apps/core/components/public/css/tinymce/skins/lightgray/img/object.gif +0 -0
  76. data/apps/core/components/public/css/tinymce/skins/lightgray/img/trans.gif +0 -0
  77. data/apps/core/components/public/css/tinymce/skins/lightgray/skin.dev.less +46 -0
  78. data/apps/core/components/public/css/tinymce/skins/lightgray/skin.ie7.dev.less +46 -0
  79. data/apps/core/components/public/css/tinymce/skins/lightgray/skin.ie7.less +2542 -0
  80. data/apps/core/components/public/css/tinymce/skins/lightgray/skin.ie7.min.css +1 -0
  81. data/apps/core/components/public/css/tinymce/skins/lightgray/skin.less +2586 -0
  82. data/apps/core/components/public/css/tinymce/skins/lightgray/skin.min.css +1 -0
  83. data/apps/core/components/public/js/bootbox_2/bootbox.js +551 -0
  84. data/apps/core/components/public/js/jquery/jquery-ui-1.9.2/ui/i18n/jquery.ui.datepicker-it-min.js +4 -0
  85. data/apps/core/components/public/js/spider.js +7 -3
  86. data/apps/core/components/public/js/tinymce/classes/AddOnManager.js +265 -0
  87. data/apps/core/components/public/js/tinymce/classes/Compat.js +90 -0
  88. data/apps/core/components/public/js/tinymce/classes/DragDropOverrides.js +224 -0
  89. data/apps/core/components/public/js/tinymce/classes/Editor.js +2221 -0
  90. data/apps/core/components/public/js/tinymce/classes/EditorCommands.js +1028 -0
  91. data/apps/core/components/public/js/tinymce/classes/EditorManager.js +715 -0
  92. data/apps/core/components/public/js/tinymce/classes/EditorObservable.js +204 -0
  93. data/apps/core/components/public/js/tinymce/classes/EditorUpload.js +191 -0
  94. data/apps/core/components/public/js/tinymce/classes/EnterKey.js +676 -0
  95. data/apps/core/components/public/js/tinymce/classes/Env.js +177 -0
  96. data/apps/core/components/public/js/tinymce/classes/FocusManager.js +266 -0
  97. data/apps/core/components/public/js/tinymce/classes/ForceBlocks.js +138 -0
  98. data/apps/core/components/public/js/tinymce/classes/Formatter.js +2378 -0
  99. data/apps/core/components/public/js/tinymce/classes/LegacyInput.js +82 -0
  100. data/apps/core/components/public/js/tinymce/classes/Mode.js +54 -0
  101. data/apps/core/components/public/js/tinymce/classes/NodeChange.js +154 -0
  102. data/apps/core/components/public/js/tinymce/classes/NotificationManager.js +156 -0
  103. data/apps/core/components/public/js/tinymce/classes/Register.js +34 -0
  104. data/apps/core/components/public/js/tinymce/classes/SelectionOverrides.js +810 -0
  105. data/apps/core/components/public/js/tinymce/classes/Shortcuts.js +172 -0
  106. data/apps/core/components/public/js/tinymce/classes/UndoManager.js +346 -0
  107. data/apps/core/components/public/js/tinymce/classes/WindowManager.js +278 -0
  108. data/apps/core/components/public/js/tinymce/classes/caret/CaretBookmark.js +263 -0
  109. data/apps/core/components/public/js/tinymce/classes/caret/CaretCandidate.js +86 -0
  110. data/apps/core/components/public/js/tinymce/classes/caret/CaretContainer.js +151 -0
  111. data/apps/core/components/public/js/tinymce/classes/caret/CaretPosition.js +371 -0
  112. data/apps/core/components/public/js/tinymce/classes/caret/CaretUtils.js +302 -0
  113. data/apps/core/components/public/js/tinymce/classes/caret/CaretWalker.js +215 -0
  114. data/apps/core/components/public/js/tinymce/classes/caret/FakeCaret.js +192 -0
  115. data/apps/core/components/public/js/tinymce/classes/caret/LineUtils.js +135 -0
  116. data/apps/core/components/public/js/tinymce/classes/caret/LineWalker.js +166 -0
  117. data/apps/core/components/public/js/tinymce/classes/data/Binding.js +79 -0
  118. data/apps/core/components/public/js/tinymce/classes/data/ObservableArray.js +196 -0
  119. data/apps/core/components/public/js/tinymce/classes/data/ObservableObject.js +194 -0
  120. data/apps/core/components/public/js/tinymce/classes/dom/BookmarkManager.js +456 -0
  121. data/apps/core/components/public/js/tinymce/classes/dom/ControlSelection.js +634 -0
  122. data/apps/core/components/public/js/tinymce/classes/dom/DOMUtils.js +1853 -0
  123. data/apps/core/components/public/js/tinymce/classes/dom/Dimensions.js +64 -0
  124. data/apps/core/components/public/js/tinymce/classes/dom/DomQuery.js +1578 -0
  125. data/apps/core/components/public/js/tinymce/classes/dom/ElementUtils.js +118 -0
  126. data/apps/core/components/public/js/tinymce/classes/dom/EventUtils.js +583 -0
  127. data/apps/core/components/public/js/tinymce/classes/dom/NodePath.js +50 -0
  128. data/apps/core/components/public/js/tinymce/classes/dom/NodeType.js +110 -0
  129. data/apps/core/components/public/js/tinymce/classes/dom/Range.js +785 -0
  130. data/apps/core/components/public/js/tinymce/classes/dom/RangeUtils.js +628 -0
  131. data/apps/core/components/public/js/tinymce/classes/dom/ScriptLoader.js +254 -0
  132. data/apps/core/components/public/js/tinymce/classes/dom/Selection.js +1008 -0
  133. data/apps/core/components/public/js/tinymce/classes/dom/Serializer.js +506 -0
  134. data/apps/core/components/public/js/tinymce/classes/dom/Sizzle.jQuery.js +23 -0
  135. data/apps/core/components/public/js/tinymce/classes/dom/Sizzle.js +2039 -0
  136. data/apps/core/components/public/js/tinymce/classes/dom/StyleSheetLoader.js +190 -0
  137. data/apps/core/components/public/js/tinymce/classes/dom/TreeWalker.js +127 -0
  138. data/apps/core/components/public/js/tinymce/classes/dom/TridentSelection.js +508 -0
  139. data/apps/core/components/public/js/tinymce/classes/file/BlobCache.js +72 -0
  140. data/apps/core/components/public/js/tinymce/classes/file/Conversions.js +106 -0
  141. data/apps/core/components/public/js/tinymce/classes/file/ImageScanner.js +145 -0
  142. data/apps/core/components/public/js/tinymce/classes/file/Uploader.js +193 -0
  143. data/apps/core/components/public/js/tinymce/classes/fmt/Hooks.js +66 -0
  144. data/apps/core/components/public/js/tinymce/classes/fmt/Preview.js +151 -0
  145. data/apps/core/components/public/js/tinymce/classes/geom/ClientRect.js +136 -0
  146. data/apps/core/components/public/js/tinymce/classes/geom/Rect.js +214 -0
  147. data/apps/core/components/public/js/tinymce/classes/html/DomParser.js +822 -0
  148. data/apps/core/components/public/js/tinymce/classes/html/Entities.js +268 -0
  149. data/apps/core/components/public/js/tinymce/classes/html/Node.js +496 -0
  150. data/apps/core/components/public/js/tinymce/classes/html/SaxParser.js +474 -0
  151. data/apps/core/components/public/js/tinymce/classes/html/Schema.js +1004 -0
  152. data/apps/core/components/public/js/tinymce/classes/html/Serializer.js +158 -0
  153. data/apps/core/components/public/js/tinymce/classes/html/Styles.js +363 -0
  154. data/apps/core/components/public/js/tinymce/classes/html/Writer.js +199 -0
  155. data/apps/core/components/public/js/tinymce/classes/jquery.tinymce.js +377 -0
  156. data/apps/core/components/public/js/tinymce/classes/text/ExtendingChar.js +53 -0
  157. data/apps/core/components/public/js/tinymce/classes/text/Zwsp.js +36 -0
  158. data/apps/core/components/public/js/tinymce/classes/ui/AbsoluteLayout.js +63 -0
  159. data/apps/core/components/public/js/tinymce/classes/ui/BoxUtils.js +98 -0
  160. data/apps/core/components/public/js/tinymce/classes/ui/Button.js +199 -0
  161. data/apps/core/components/public/js/tinymce/classes/ui/ButtonGroup.js +62 -0
  162. data/apps/core/components/public/js/tinymce/classes/ui/Checkbox.js +162 -0
  163. data/apps/core/components/public/js/tinymce/classes/ui/ClassList.js +149 -0
  164. data/apps/core/components/public/js/tinymce/classes/ui/Collection.js +438 -0
  165. data/apps/core/components/public/js/tinymce/classes/ui/ColorBox.js +72 -0
  166. data/apps/core/components/public/js/tinymce/classes/ui/ColorButton.js +124 -0
  167. data/apps/core/components/public/js/tinymce/classes/ui/ColorPicker.js +206 -0
  168. data/apps/core/components/public/js/tinymce/classes/ui/ComboBox.js +306 -0
  169. data/apps/core/components/public/js/tinymce/classes/ui/Container.js +506 -0
  170. data/apps/core/components/public/js/tinymce/classes/ui/Control.js +1301 -0
  171. data/apps/core/components/public/js/tinymce/classes/ui/DomUtils.js +107 -0
  172. data/apps/core/components/public/js/tinymce/classes/ui/DragHelper.js +144 -0
  173. data/apps/core/components/public/js/tinymce/classes/ui/ElementPath.js +79 -0
  174. data/apps/core/components/public/js/tinymce/classes/ui/Factory.js +105 -0
  175. data/apps/core/components/public/js/tinymce/classes/ui/FieldSet.js +59 -0
  176. data/apps/core/components/public/js/tinymce/classes/ui/FilePicker.js +85 -0
  177. data/apps/core/components/public/js/tinymce/classes/ui/FitLayout.js +48 -0
  178. data/apps/core/components/public/js/tinymce/classes/ui/FlexLayout.js +246 -0
  179. data/apps/core/components/public/js/tinymce/classes/ui/FloatPanel.js +409 -0
  180. data/apps/core/components/public/js/tinymce/classes/ui/FlowLayout.js +46 -0
  181. data/apps/core/components/public/js/tinymce/classes/ui/Form.js +157 -0
  182. data/apps/core/components/public/js/tinymce/classes/ui/FormItem.js +56 -0
  183. data/apps/core/components/public/js/tinymce/classes/ui/FormatControls.js +535 -0
  184. data/apps/core/components/public/js/tinymce/classes/ui/GridLayout.js +233 -0
  185. data/apps/core/components/public/js/tinymce/classes/ui/Iframe.js +85 -0
  186. data/apps/core/components/public/js/tinymce/classes/ui/InfoBox.js +93 -0
  187. data/apps/core/components/public/js/tinymce/classes/ui/KeyboardNavigation.js +406 -0
  188. data/apps/core/components/public/js/tinymce/classes/ui/Label.js +144 -0
  189. data/apps/core/components/public/js/tinymce/classes/ui/Layout.js +120 -0
  190. data/apps/core/components/public/js/tinymce/classes/ui/ListBox.js +152 -0
  191. data/apps/core/components/public/js/tinymce/classes/ui/Menu.js +195 -0
  192. data/apps/core/components/public/js/tinymce/classes/ui/MenuBar.js +33 -0
  193. data/apps/core/components/public/js/tinymce/classes/ui/MenuButton.js +268 -0
  194. data/apps/core/components/public/js/tinymce/classes/ui/MenuItem.js +336 -0
  195. data/apps/core/components/public/js/tinymce/classes/ui/MessageBox.js +202 -0
  196. data/apps/core/components/public/js/tinymce/classes/ui/Movable.js +200 -0
  197. data/apps/core/components/public/js/tinymce/classes/ui/Notification.js +154 -0
  198. data/apps/core/components/public/js/tinymce/classes/ui/Panel.js +67 -0
  199. data/apps/core/components/public/js/tinymce/classes/ui/PanelButton.js +114 -0
  200. data/apps/core/components/public/js/tinymce/classes/ui/Path.js +127 -0
  201. data/apps/core/components/public/js/tinymce/classes/ui/Progress.js +81 -0
  202. data/apps/core/components/public/js/tinymce/classes/ui/Radio.js +29 -0
  203. data/apps/core/components/public/js/tinymce/classes/ui/ReflowQueue.js +79 -0
  204. data/apps/core/components/public/js/tinymce/classes/ui/Resizable.js +68 -0
  205. data/apps/core/components/public/js/tinymce/classes/ui/ResizeHandle.js +86 -0
  206. data/apps/core/components/public/js/tinymce/classes/ui/Scrollable.js +141 -0
  207. data/apps/core/components/public/js/tinymce/classes/ui/SelectBox.js +106 -0
  208. data/apps/core/components/public/js/tinymce/classes/ui/Selector.js +369 -0
  209. data/apps/core/components/public/js/tinymce/classes/ui/Slider.js +161 -0
  210. data/apps/core/components/public/js/tinymce/classes/ui/Spacer.js +39 -0
  211. data/apps/core/components/public/js/tinymce/classes/ui/SplitButton.js +146 -0
  212. data/apps/core/components/public/js/tinymce/classes/ui/StackLayout.js +34 -0
  213. data/apps/core/components/public/js/tinymce/classes/ui/TabPanel.js +178 -0
  214. data/apps/core/components/public/js/tinymce/classes/ui/TextBox.js +208 -0
  215. data/apps/core/components/public/js/tinymce/classes/ui/Throbber.js +88 -0
  216. data/apps/core/components/public/js/tinymce/classes/ui/Toolbar.js +56 -0
  217. data/apps/core/components/public/js/tinymce/classes/ui/Tooltip.js +73 -0
  218. data/apps/core/components/public/js/tinymce/classes/ui/Widget.js +151 -0
  219. data/apps/core/components/public/js/tinymce/classes/ui/Window.js +474 -0
  220. data/apps/core/components/public/js/tinymce/classes/util/Arr.js +153 -0
  221. data/apps/core/components/public/js/tinymce/classes/util/Class.js +167 -0
  222. data/apps/core/components/public/js/tinymce/classes/util/Color.js +235 -0
  223. data/apps/core/components/public/js/tinymce/classes/util/Delay.js +191 -0
  224. data/apps/core/components/public/js/tinymce/classes/util/EventDispatcher.js +294 -0
  225. data/apps/core/components/public/js/tinymce/classes/util/Fun.js +87 -0
  226. data/apps/core/components/public/js/tinymce/classes/util/I18n.js +116 -0
  227. data/apps/core/components/public/js/tinymce/classes/util/JSON.js +109 -0
  228. data/apps/core/components/public/js/tinymce/classes/util/JSONP.js +38 -0
  229. data/apps/core/components/public/js/tinymce/classes/util/JSONRequest.js +110 -0
  230. data/apps/core/components/public/js/tinymce/classes/util/LocalStorage.js +213 -0
  231. data/apps/core/components/public/js/tinymce/classes/util/Observable.js +129 -0
  232. data/apps/core/components/public/js/tinymce/classes/util/Promise.js +200 -0
  233. data/apps/core/components/public/js/tinymce/classes/util/Quirks.js +1701 -0
  234. data/apps/core/components/public/js/tinymce/classes/util/Tools.js +442 -0
  235. data/apps/core/components/public/js/tinymce/classes/util/URI.js +411 -0
  236. data/apps/core/components/public/js/tinymce/classes/util/VK.js +37 -0
  237. data/apps/core/components/public/js/tinymce/classes/util/XHR.js +110 -0
  238. data/apps/core/components/public/js/tinymce/jquery.tinymce.min.js +1 -0
  239. data/apps/core/components/public/js/tinymce/langs/it.js +219 -0
  240. data/apps/core/components/public/js/tinymce/langs/readme.md +3 -0
  241. data/apps/core/components/public/js/tinymce/license.txt +504 -0
  242. data/apps/core/components/public/js/tinymce/plugins/advlist/plugin.js +97 -0
  243. data/apps/core/components/public/js/tinymce/plugins/advlist/plugin.min.js +1 -0
  244. data/apps/core/components/public/js/tinymce/plugins/anchor/plugin.js +55 -0
  245. data/apps/core/components/public/js/tinymce/plugins/anchor/plugin.min.js +1 -0
  246. data/apps/core/components/public/js/tinymce/plugins/autolink/plugin.js +204 -0
  247. data/apps/core/components/public/js/tinymce/plugins/autolink/plugin.min.js +1 -0
  248. data/apps/core/components/public/js/tinymce/plugins/autoresize/plugin.js +162 -0
  249. data/apps/core/components/public/js/tinymce/plugins/autoresize/plugin.min.js +1 -0
  250. data/apps/core/components/public/js/tinymce/plugins/autosave/plugin.js +165 -0
  251. data/apps/core/components/public/js/tinymce/plugins/autosave/plugin.min.js +1 -0
  252. data/apps/core/components/public/js/tinymce/plugins/bbcode/plugin.js +123 -0
  253. data/apps/core/components/public/js/tinymce/plugins/bbcode/plugin.min.js +1 -0
  254. data/apps/core/components/public/js/tinymce/plugins/charmap/plugin.js +450 -0
  255. data/apps/core/components/public/js/tinymce/plugins/charmap/plugin.min.js +1 -0
  256. data/apps/core/components/public/js/tinymce/plugins/code/plugin.js +60 -0
  257. data/apps/core/components/public/js/tinymce/plugins/code/plugin.min.js +1 -0
  258. data/apps/core/components/public/js/tinymce/plugins/codesample/classes/Dialog.js +121 -0
  259. data/apps/core/components/public/js/tinymce/plugins/codesample/classes/Plugin.js +95 -0
  260. data/apps/core/components/public/js/tinymce/plugins/codesample/classes/Prism.js +937 -0
  261. data/apps/core/components/public/js/tinymce/plugins/codesample/classes/Utils.js +33 -0
  262. data/apps/core/components/public/js/tinymce/plugins/codesample/css/prism.css +138 -0
  263. data/apps/core/components/public/js/tinymce/plugins/codesample/plugin.dev.js +141 -0
  264. data/apps/core/components/public/js/tinymce/plugins/codesample/plugin.js +1299 -0
  265. data/apps/core/components/public/js/tinymce/plugins/codesample/plugin.min.js +1 -0
  266. data/apps/core/components/public/js/tinymce/plugins/colorpicker/plugin.js +112 -0
  267. data/apps/core/components/public/js/tinymce/plugins/colorpicker/plugin.min.js +1 -0
  268. data/apps/core/components/public/js/tinymce/plugins/compat3x/css/dialog.css +118 -0
  269. data/apps/core/components/public/js/tinymce/plugins/compat3x/img/buttons.png +0 -0
  270. data/apps/core/components/public/js/tinymce/plugins/compat3x/img/icons.gif +0 -0
  271. data/apps/core/components/public/js/tinymce/plugins/compat3x/img/items.gif +0 -0
  272. data/apps/core/components/public/js/tinymce/plugins/compat3x/img/menu_arrow.gif +0 -0
  273. data/apps/core/components/public/js/tinymce/plugins/compat3x/img/menu_check.gif +0 -0
  274. data/apps/core/components/public/js/tinymce/plugins/compat3x/img/progress.gif +0 -0
  275. data/apps/core/components/public/js/tinymce/plugins/compat3x/img/tabs.gif +0 -0
  276. data/apps/core/components/public/js/tinymce/plugins/compat3x/plugin.js +297 -0
  277. data/apps/core/components/public/js/tinymce/plugins/compat3x/plugin.min.js +1 -0
  278. data/apps/core/components/public/js/tinymce/plugins/compat3x/tiny_mce_popup.js +542 -0
  279. data/apps/core/components/public/js/tinymce/plugins/compat3x/utils/editable_selects.js +70 -0
  280. data/apps/core/components/public/js/tinymce/plugins/compat3x/utils/form_utils.js +210 -0
  281. data/apps/core/components/public/js/tinymce/plugins/compat3x/utils/mctabs.js +164 -0
  282. data/apps/core/components/public/js/tinymce/plugins/compat3x/utils/validate.js +252 -0
  283. data/apps/core/components/public/js/tinymce/plugins/contextmenu/plugin.js +88 -0
  284. data/apps/core/components/public/js/tinymce/plugins/contextmenu/plugin.min.js +1 -0
  285. data/apps/core/components/public/js/tinymce/plugins/directionality/plugin.js +64 -0
  286. data/apps/core/components/public/js/tinymce/plugins/directionality/plugin.min.js +1 -0
  287. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-cool.gif +0 -0
  288. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-cry.gif +0 -0
  289. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-embarassed.gif +0 -0
  290. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-foot-in-mouth.gif +0 -0
  291. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-frown.gif +0 -0
  292. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-innocent.gif +0 -0
  293. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-kiss.gif +0 -0
  294. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-laughing.gif +0 -0
  295. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-money-mouth.gif +0 -0
  296. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-sealed.gif +0 -0
  297. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-smile.gif +0 -0
  298. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-surprised.gif +0 -0
  299. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-tongue-out.gif +0 -0
  300. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-undecided.gif +0 -0
  301. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-wink.gif +0 -0
  302. data/apps/core/components/public/js/tinymce/plugins/emoticons/img/smiley-yell.gif +0 -0
  303. data/apps/core/components/public/js/tinymce/plugins/emoticons/plugin.js +65 -0
  304. data/apps/core/components/public/js/tinymce/plugins/emoticons/plugin.min.js +1 -0
  305. data/apps/core/components/public/js/tinymce/plugins/example/dialog.html +8 -0
  306. data/apps/core/components/public/js/tinymce/plugins/example/plugin.js +68 -0
  307. data/apps/core/components/public/js/tinymce/plugins/example/plugin.min.js +1 -0
  308. data/apps/core/components/public/js/tinymce/plugins/example_dependency/plugin.js +22 -0
  309. data/apps/core/components/public/js/tinymce/plugins/example_dependency/plugin.min.js +1 -0
  310. data/apps/core/components/public/js/tinymce/plugins/fullpage/plugin.js +490 -0
  311. data/apps/core/components/public/js/tinymce/plugins/fullpage/plugin.min.js +1 -0
  312. data/apps/core/components/public/js/tinymce/plugins/fullscreen/plugin.js +154 -0
  313. data/apps/core/components/public/js/tinymce/plugins/fullscreen/plugin.min.js +1 -0
  314. data/apps/core/components/public/js/tinymce/plugins/hr/plugin.js +30 -0
  315. data/apps/core/components/public/js/tinymce/plugins/hr/plugin.min.js +1 -0
  316. data/apps/core/components/public/js/tinymce/plugins/image/plugin.js +630 -0
  317. data/apps/core/components/public/js/tinymce/plugins/image/plugin.min.js +1 -0
  318. data/apps/core/components/public/js/tinymce/plugins/imagetools/config/bolt/atomic.js +6 -0
  319. data/apps/core/components/public/js/tinymce/plugins/imagetools/config/bolt/browser.js +6 -0
  320. data/apps/core/components/public/js/tinymce/plugins/imagetools/config/bolt/demo.js +8 -0
  321. data/apps/core/components/public/js/tinymce/plugins/imagetools/config/bolt/prod.js +6 -0
  322. data/apps/core/components/public/js/tinymce/plugins/imagetools/plugin.js +2668 -0
  323. data/apps/core/components/public/js/tinymce/plugins/imagetools/plugin.min.js +1 -0
  324. data/apps/core/components/public/js/tinymce/plugins/imagetools/src/demo/html/demo.html +16 -0
  325. data/apps/core/components/public/js/tinymce/plugins/imagetools/src/demo/js/Demo.js +92 -0
  326. data/apps/core/components/public/js/tinymce/plugins/imagetools/src/main/js/CropRect.js +214 -0
  327. data/apps/core/components/public/js/tinymce/plugins/imagetools/src/main/js/Dialog.js +485 -0
  328. data/apps/core/components/public/js/tinymce/plugins/imagetools/src/main/js/ImagePanel.js +218 -0
  329. data/apps/core/components/public/js/tinymce/plugins/imagetools/src/main/js/Plugin.js +411 -0
  330. data/apps/core/components/public/js/tinymce/plugins/imagetools/src/main/js/UndoStack.js +57 -0
  331. data/apps/core/components/public/js/tinymce/plugins/importcss/plugin.js +227 -0
  332. data/apps/core/components/public/js/tinymce/plugins/importcss/plugin.min.js +1 -0
  333. data/apps/core/components/public/js/tinymce/plugins/insertdatetime/plugin.js +121 -0
  334. data/apps/core/components/public/js/tinymce/plugins/insertdatetime/plugin.min.js +1 -0
  335. data/apps/core/components/public/js/tinymce/plugins/layer/plugin.js +225 -0
  336. data/apps/core/components/public/js/tinymce/plugins/layer/plugin.min.js +1 -0
  337. data/apps/core/components/public/js/tinymce/plugins/legacyoutput/plugin.js +211 -0
  338. data/apps/core/components/public/js/tinymce/plugins/legacyoutput/plugin.min.js +1 -0
  339. data/apps/core/components/public/js/tinymce/plugins/link/plugin.js +403 -0
  340. data/apps/core/components/public/js/tinymce/plugins/link/plugin.min.js +1 -0
  341. data/apps/core/components/public/js/tinymce/plugins/lists/plugin.js +885 -0
  342. data/apps/core/components/public/js/tinymce/plugins/lists/plugin.min.js +1 -0
  343. data/apps/core/components/public/js/tinymce/plugins/media/moxieplayer.swf +0 -0
  344. data/apps/core/components/public/js/tinymce/plugins/media/plugin.js +878 -0
  345. data/apps/core/components/public/js/tinymce/plugins/media/plugin.min.js +1 -0
  346. data/apps/core/components/public/js/tinymce/plugins/nonbreaking/plugin.js +53 -0
  347. data/apps/core/components/public/js/tinymce/plugins/nonbreaking/plugin.min.js +1 -0
  348. data/apps/core/components/public/js/tinymce/plugins/noneditable/plugin.js +101 -0
  349. data/apps/core/components/public/js/tinymce/plugins/noneditable/plugin.min.js +1 -0
  350. data/apps/core/components/public/js/tinymce/plugins/pagebreak/plugin.js +88 -0
  351. data/apps/core/components/public/js/tinymce/plugins/pagebreak/plugin.min.js +1 -0
  352. data/apps/core/components/public/js/tinymce/plugins/paste/classes/Clipboard.js +672 -0
  353. data/apps/core/components/public/js/tinymce/plugins/paste/classes/Plugin.js +121 -0
  354. data/apps/core/components/public/js/tinymce/plugins/paste/classes/Quirks.js +159 -0
  355. data/apps/core/components/public/js/tinymce/plugins/paste/classes/Utils.js +140 -0
  356. data/apps/core/components/public/js/tinymce/plugins/paste/classes/WordFilter.js +500 -0
  357. data/apps/core/components/public/js/tinymce/plugins/paste/plugin.dev.js +142 -0
  358. data/apps/core/components/public/js/tinymce/plugins/paste/plugin.js +1708 -0
  359. data/apps/core/components/public/js/tinymce/plugins/paste/plugin.min.js +1 -0
  360. data/apps/core/components/public/js/tinymce/plugins/preview/plugin.js +88 -0
  361. data/apps/core/components/public/js/tinymce/plugins/preview/plugin.min.js +1 -0
  362. data/apps/core/components/public/js/tinymce/plugins/print/plugin.js +32 -0
  363. data/apps/core/components/public/js/tinymce/plugins/print/plugin.min.js +1 -0
  364. data/apps/core/components/public/js/tinymce/plugins/save/plugin.js +98 -0
  365. data/apps/core/components/public/js/tinymce/plugins/save/plugin.min.js +1 -0
  366. data/apps/core/components/public/js/tinymce/plugins/searchreplace/plugin.js +609 -0
  367. data/apps/core/components/public/js/tinymce/plugins/searchreplace/plugin.min.js +1 -0
  368. data/apps/core/components/public/js/tinymce/plugins/spellchecker/classes/DomTextMatcher.js +480 -0
  369. data/apps/core/components/public/js/tinymce/plugins/spellchecker/classes/Plugin.js +439 -0
  370. data/apps/core/components/public/js/tinymce/plugins/spellchecker/plugin.dev.js +139 -0
  371. data/apps/core/components/public/js/tinymce/plugins/spellchecker/plugin.js +1026 -0
  372. data/apps/core/components/public/js/tinymce/plugins/spellchecker/plugin.min.js +1 -0
  373. data/apps/core/components/public/js/tinymce/plugins/tabfocus/plugin.js +120 -0
  374. data/apps/core/components/public/js/tinymce/plugins/tabfocus/plugin.min.js +1 -0
  375. data/apps/core/components/public/js/tinymce/plugins/table/classes/CellSelection.js +202 -0
  376. data/apps/core/components/public/js/tinymce/plugins/table/classes/Dialogs.js +824 -0
  377. data/apps/core/components/public/js/tinymce/plugins/table/classes/Plugin.js +599 -0
  378. data/apps/core/components/public/js/tinymce/plugins/table/classes/Quirks.js +400 -0
  379. data/apps/core/components/public/js/tinymce/plugins/table/classes/ResizeBars.js +984 -0
  380. data/apps/core/components/public/js/tinymce/plugins/table/classes/TableGrid.js +941 -0
  381. data/apps/core/components/public/js/tinymce/plugins/table/classes/Utils.js +36 -0
  382. data/apps/core/components/public/js/tinymce/plugins/table/plugin.dev.js +142 -0
  383. data/apps/core/components/public/js/tinymce/plugins/table/plugin.js +4106 -0
  384. data/apps/core/components/public/js/tinymce/plugins/table/plugin.min.js +2 -0
  385. data/apps/core/components/public/js/tinymce/plugins/template/plugin.js +270 -0
  386. data/apps/core/components/public/js/tinymce/plugins/template/plugin.min.js +1 -0
  387. data/apps/core/components/public/js/tinymce/plugins/textcolor/plugin.js +282 -0
  388. data/apps/core/components/public/js/tinymce/plugins/textcolor/plugin.min.js +1 -0
  389. data/apps/core/components/public/js/tinymce/plugins/textpattern/plugin.js +268 -0
  390. data/apps/core/components/public/js/tinymce/plugins/textpattern/plugin.min.js +1 -0
  391. data/apps/core/components/public/js/tinymce/plugins/visualblocks/css/visualblocks.css +135 -0
  392. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/address.gif +0 -0
  393. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/article.gif +0 -0
  394. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/aside.gif +0 -0
  395. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/blockquote.gif +0 -0
  396. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/div.gif +0 -0
  397. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/dl.gif +0 -0
  398. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/figure.gif +0 -0
  399. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/h1.gif +0 -0
  400. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/h2.gif +0 -0
  401. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/h3.gif +0 -0
  402. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/h4.gif +0 -0
  403. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/h5.gif +0 -0
  404. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/h6.gif +0 -0
  405. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/hgroup.gif +0 -0
  406. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/ol.gif +0 -0
  407. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/p.gif +0 -0
  408. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/pre.gif +0 -0
  409. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/section.gif +0 -0
  410. data/apps/core/components/public/js/tinymce/plugins/visualblocks/img/ul.gif +0 -0
  411. data/apps/core/components/public/js/tinymce/plugins/visualblocks/plugin.js +86 -0
  412. data/apps/core/components/public/js/tinymce/plugins/visualblocks/plugin.min.js +1 -0
  413. data/apps/core/components/public/js/tinymce/plugins/visualchars/plugin.js +123 -0
  414. data/apps/core/components/public/js/tinymce/plugins/visualchars/plugin.min.js +1 -0
  415. data/apps/core/components/public/js/tinymce/plugins/wordcount/plugin.js +69 -0
  416. data/apps/core/components/public/js/tinymce/plugins/wordcount/plugin.min.js +1 -0
  417. data/apps/core/components/public/js/tinymce/skins/lightgray/AbsoluteLayout.less +17 -0
  418. data/apps/core/components/public/js/tinymce/skins/lightgray/Animations.less +10 -0
  419. data/apps/core/components/public/js/tinymce/skins/lightgray/Button.less +172 -0
  420. data/apps/core/components/public/js/tinymce/skins/lightgray/ButtonGroup.less +71 -0
  421. data/apps/core/components/public/js/tinymce/skins/lightgray/Checkbox.less +49 -0
  422. data/apps/core/components/public/js/tinymce/skins/lightgray/ColorBox.less +6 -0
  423. data/apps/core/components/public/js/tinymce/skins/lightgray/ColorButton.less +72 -0
  424. data/apps/core/components/public/js/tinymce/skins/lightgray/ColorPicker.less +80 -0
  425. data/apps/core/components/public/js/tinymce/skins/lightgray/ComboBox.less +39 -0
  426. data/apps/core/components/public/js/tinymce/skins/lightgray/Container.less +9 -0
  427. data/apps/core/components/public/js/tinymce/skins/lightgray/Content.Inline.less +4 -0
  428. data/apps/core/components/public/js/tinymce/skins/lightgray/Content.Objects.less +166 -0
  429. data/apps/core/components/public/js/tinymce/skins/lightgray/Content.less +27 -0
  430. data/apps/core/components/public/js/tinymce/skins/lightgray/CropRect.less +54 -0
  431. data/apps/core/components/public/js/tinymce/skins/lightgray/FieldSet.less +15 -0
  432. data/apps/core/components/public/js/tinymce/skins/lightgray/FitLayout.less +9 -0
  433. data/apps/core/components/public/js/tinymce/skins/lightgray/FloatPanel.less +69 -0
  434. data/apps/core/components/public/js/tinymce/skins/lightgray/FlowLayout.less +36 -0
  435. data/apps/core/components/public/js/tinymce/skins/lightgray/Icons.Ie7.less +136 -0
  436. data/apps/core/components/public/js/tinymce/skins/lightgray/Icons.less +180 -0
  437. data/apps/core/components/public/js/tinymce/skins/lightgray/Iframe.less +6 -0
  438. data/apps/core/components/public/js/tinymce/skins/lightgray/ImagePanel.less +20 -0
  439. data/apps/core/components/public/js/tinymce/skins/lightgray/InfoBox.less +71 -0
  440. data/apps/core/components/public/js/tinymce/skins/lightgray/Label.less +38 -0
  441. data/apps/core/components/public/js/tinymce/skins/lightgray/ListBox.less +26 -0
  442. data/apps/core/components/public/js/tinymce/skins/lightgray/Menu.less +34 -0
  443. data/apps/core/components/public/js/tinymce/skins/lightgray/MenuBar.less +32 -0
  444. data/apps/core/components/public/js/tinymce/skins/lightgray/MenuButton.less +34 -0
  445. data/apps/core/components/public/js/tinymce/skins/lightgray/MenuItem.less +142 -0
  446. data/apps/core/components/public/js/tinymce/skins/lightgray/Mixins.less +54 -0
  447. data/apps/core/components/public/js/tinymce/skins/lightgray/Notification.less +144 -0
  448. data/apps/core/components/public/js/tinymce/skins/lightgray/Panel.less +7 -0
  449. data/apps/core/components/public/js/tinymce/skins/lightgray/Path.less +45 -0
  450. data/apps/core/components/public/js/tinymce/skins/lightgray/Progress.less +34 -0
  451. data/apps/core/components/public/js/tinymce/skins/lightgray/Radio.less +1 -0
  452. data/apps/core/components/public/js/tinymce/skins/lightgray/Reset.less +32 -0
  453. data/apps/core/components/public/js/tinymce/skins/lightgray/ResizeHandle.less +18 -0
  454. data/apps/core/components/public/js/tinymce/skins/lightgray/Scrollable.less +44 -0
  455. data/apps/core/components/public/js/tinymce/skins/lightgray/SelectBox.less +6 -0
  456. data/apps/core/components/public/js/tinymce/skins/lightgray/Slider.less +29 -0
  457. data/apps/core/components/public/js/tinymce/skins/lightgray/Spacer.less +5 -0
  458. data/apps/core/components/public/js/tinymce/skins/lightgray/SplitButton.less +49 -0
  459. data/apps/core/components/public/js/tinymce/skins/lightgray/StackLayout.less +5 -0
  460. data/apps/core/components/public/js/tinymce/skins/lightgray/TabPanel.less +44 -0
  461. data/apps/core/components/public/js/tinymce/skins/lightgray/TextBox.less +41 -0
  462. data/apps/core/components/public/js/tinymce/skins/lightgray/Throbber.less +19 -0
  463. data/apps/core/components/public/js/tinymce/skins/lightgray/TinyMCE.less +159 -0
  464. data/apps/core/components/public/js/tinymce/skins/lightgray/ToolTip.less +129 -0
  465. data/apps/core/components/public/js/tinymce/skins/lightgray/Variables.less +214 -0
  466. data/apps/core/components/public/js/tinymce/skins/lightgray/Window.less +127 -0
  467. data/apps/core/components/public/js/tinymce/skins/lightgray/content.inline.min.css +1 -0
  468. data/apps/core/components/public/js/tinymce/skins/lightgray/content.min.css +1 -0
  469. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/readme.md +1 -0
  470. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce-small.eot +0 -0
  471. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce-small.json +1277 -0
  472. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce-small.svg +63 -0
  473. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce-small.ttf +0 -0
  474. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce-small.woff +0 -0
  475. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce.eot +0 -0
  476. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce.json +3381 -0
  477. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce.svg +129 -0
  478. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce.ttf +0 -0
  479. data/apps/core/components/public/js/tinymce/skins/lightgray/fonts/tinymce.woff +0 -0
  480. data/apps/core/components/public/js/tinymce/skins/lightgray/img/anchor.gif +0 -0
  481. data/apps/core/components/public/js/tinymce/skins/lightgray/img/loader.gif +0 -0
  482. data/apps/core/components/public/js/tinymce/skins/lightgray/img/object.gif +0 -0
  483. data/apps/core/components/public/js/tinymce/skins/lightgray/img/trans.gif +0 -0
  484. data/apps/core/components/public/js/tinymce/skins/lightgray/skin.dev.less +46 -0
  485. data/apps/core/components/public/js/tinymce/skins/lightgray/skin.ie7.dev.less +46 -0
  486. data/apps/core/components/public/js/tinymce/skins/lightgray/skin.ie7.less +2542 -0
  487. data/apps/core/components/public/js/tinymce/skins/lightgray/skin.ie7.min.css +1 -0
  488. data/apps/core/components/public/js/tinymce/skins/lightgray/skin.less +2586 -0
  489. data/apps/core/components/public/js/tinymce/skins/lightgray/skin.min.css +1 -0
  490. data/apps/core/components/public/js/tinymce/themes/modern/theme.js +878 -0
  491. data/apps/core/components/public/js/tinymce/themes/modern/theme.min.js +1 -0
  492. data/apps/core/components/public/js/tinymce/tinymce.dev.js +286 -0
  493. data/apps/core/components/public/js/tinymce/tinymce.js +45811 -0
  494. data/apps/core/components/public/js/tinymce/tinymce.min.js +13 -0
  495. data/apps/core/forms/widgets/form/form.rb +3 -1
  496. data/apps/core/forms/widgets/form/form.shtml +1 -0
  497. data/apps/core/forms/widgets/inputs/search_select/search_select.rb +1 -1
  498. data/apps/core/forms/widgets/inputs/select/select.rb +1 -1
  499. data/apps/core/forms/widgets/inputs/select/select.shtml +0 -1
  500. data/apps/messenger/backends/sms/skebby.rb +1 -1
  501. data/apps/messenger/controllers/mixins/messenger_helper.rb +23 -5
  502. data/lib/spiderfw/config/options/spider.rb +1 -1
  503. data/lib/spiderfw/controller/mixins/visual.rb +2 -0
  504. data/lib/spiderfw/http/adapters/rack.rb +10 -5
  505. data/lib/spiderfw/http/http.rb +4 -2
  506. data/lib/spiderfw/model/base_model.rb +4 -4
  507. data/lib/spiderfw/model/mappers/db_mapper.rb +4 -2
  508. data/lib/spiderfw/model/storage/db/adapters/mysql.rb +2 -1
  509. data/lib/spiderfw/model/storage/db/db_storage.rb +4 -0
  510. data/lib/spiderfw/spider.rb +6 -0
  511. data/lib/spiderfw/templates/layout.rb +1 -1
  512. data/lib/spiderfw/utils/monkey/object.rb +3 -0
  513. data/spider.gemspec +6 -2
  514. metadata +539 -42
  515. data/blueprints/.DS_Store +0 -0
@@ -0,0 +1,2221 @@
1
+ /**
2
+ * Editor.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
+ /*jshint scripturl:true */
12
+
13
+ /**
14
+ * Include the base event class documentation.
15
+ *
16
+ * @include ../../../tools/docs/tinymce.Event.js
17
+ */
18
+
19
+ /**
20
+ * This class contains the core logic for a TinyMCE editor.
21
+ *
22
+ * @class tinymce.Editor
23
+ * @mixes tinymce.util.Observable
24
+ * @example
25
+ * // Add a class to all paragraphs in the editor.
26
+ * tinymce.activeEditor.dom.addClass(tinymce.activeEditor.dom.select('p'), 'someclass');
27
+ *
28
+ * // Gets the current editors selection as text
29
+ * tinymce.activeEditor.selection.getContent({format: 'text'});
30
+ *
31
+ * // Creates a new editor instance
32
+ * var ed = new tinymce.Editor('textareaid', {
33
+ * some_setting: 1
34
+ * }, tinymce.EditorManager);
35
+ *
36
+ * // Select each item the user clicks on
37
+ * ed.on('click', function(e) {
38
+ * ed.selection.select(e.target);
39
+ * });
40
+ *
41
+ * ed.render();
42
+ */
43
+ define("tinymce/Editor", [
44
+ "tinymce/dom/DOMUtils",
45
+ "tinymce/dom/DomQuery",
46
+ "tinymce/AddOnManager",
47
+ "tinymce/NodeChange",
48
+ "tinymce/html/Node",
49
+ "tinymce/dom/Serializer",
50
+ "tinymce/html/Serializer",
51
+ "tinymce/dom/Selection",
52
+ "tinymce/Formatter",
53
+ "tinymce/UndoManager",
54
+ "tinymce/EnterKey",
55
+ "tinymce/ForceBlocks",
56
+ "tinymce/EditorCommands",
57
+ "tinymce/util/URI",
58
+ "tinymce/dom/ScriptLoader",
59
+ "tinymce/dom/EventUtils",
60
+ "tinymce/WindowManager",
61
+ "tinymce/NotificationManager",
62
+ "tinymce/html/Schema",
63
+ "tinymce/html/DomParser",
64
+ "tinymce/util/Quirks",
65
+ "tinymce/Env",
66
+ "tinymce/util/Tools",
67
+ "tinymce/util/Delay",
68
+ "tinymce/EditorObservable",
69
+ "tinymce/Mode",
70
+ "tinymce/Shortcuts",
71
+ "tinymce/EditorUpload",
72
+ "tinymce/SelectionOverrides"
73
+ ], function(
74
+ DOMUtils, DomQuery, AddOnManager, NodeChange, Node, DomSerializer, Serializer,
75
+ Selection, Formatter, UndoManager, EnterKey, ForceBlocks, EditorCommands,
76
+ URI, ScriptLoader, EventUtils, WindowManager, NotificationManager,
77
+ Schema, DomParser, Quirks, Env, Tools, Delay, EditorObservable, Mode, Shortcuts, EditorUpload,
78
+ SelectionOverrides
79
+ ) {
80
+ // Shorten these names
81
+ var DOM = DOMUtils.DOM, ThemeManager = AddOnManager.ThemeManager, PluginManager = AddOnManager.PluginManager;
82
+ var extend = Tools.extend, each = Tools.each, explode = Tools.explode;
83
+ var inArray = Tools.inArray, trim = Tools.trim, resolve = Tools.resolve;
84
+ var Event = EventUtils.Event;
85
+ var isGecko = Env.gecko, ie = Env.ie;
86
+
87
+ /**
88
+ * Include documentation for all the events.
89
+ *
90
+ * @include ../../../tools/docs/tinymce.Editor.js
91
+ */
92
+
93
+ /**
94
+ * Constructs a editor instance by id.
95
+ *
96
+ * @constructor
97
+ * @method Editor
98
+ * @param {String} id Unique id for the editor.
99
+ * @param {Object} settings Settings for the editor.
100
+ * @param {tinymce.EditorManager} editorManager EditorManager instance.
101
+ */
102
+ function Editor(id, settings, editorManager) {
103
+ var self = this, documentBaseUrl, baseUri;
104
+
105
+ documentBaseUrl = self.documentBaseUrl = editorManager.documentBaseURL;
106
+ baseUri = editorManager.baseURI;
107
+
108
+ /**
109
+ * Name/value collection with editor settings.
110
+ *
111
+ * @property settings
112
+ * @type Object
113
+ * @example
114
+ * // Get the value of the theme setting
115
+ * tinymce.activeEditor.windowManager.alert("You are using the " + tinymce.activeEditor.settings.theme + " theme");
116
+ */
117
+ self.settings = settings = extend({
118
+ id: id,
119
+ theme: 'modern',
120
+ delta_width: 0,
121
+ delta_height: 0,
122
+ popup_css: '',
123
+ plugins: '',
124
+ document_base_url: documentBaseUrl,
125
+ add_form_submit_trigger: true,
126
+ submit_patch: true,
127
+ add_unload_trigger: true,
128
+ convert_urls: true,
129
+ relative_urls: true,
130
+ remove_script_host: true,
131
+ object_resizing: true,
132
+ doctype: '<!DOCTYPE html>',
133
+ visual: true,
134
+ font_size_style_values: 'xx-small,x-small,small,medium,large,x-large,xx-large',
135
+
136
+ // See: http://www.w3.org/TR/CSS2/fonts.html#propdef-font-size
137
+ font_size_legacy_values: 'xx-small,small,medium,large,x-large,xx-large,300%',
138
+ forced_root_block: 'p',
139
+ hidden_input: true,
140
+ padd_empty_editor: true,
141
+ render_ui: true,
142
+ indentation: '30px',
143
+ inline_styles: true,
144
+ convert_fonts_to_spans: true,
145
+ indent: 'simple',
146
+ indent_before: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' +
147
+ 'tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist',
148
+ indent_after: 'p,h1,h2,h3,h4,h5,h6,blockquote,div,title,style,pre,script,td,th,ul,ol,li,dl,dt,dd,area,table,thead,' +
149
+ 'tfoot,tbody,tr,section,article,hgroup,aside,figure,figcaption,option,optgroup,datalist',
150
+ validate: true,
151
+ entity_encoding: 'named',
152
+ url_converter: self.convertURL,
153
+ url_converter_scope: self,
154
+ ie7_compat: true
155
+ }, editorManager.defaultSettings, settings);
156
+
157
+ AddOnManager.language = settings.language || 'en';
158
+ AddOnManager.languageLoad = settings.language_load;
159
+
160
+ AddOnManager.baseURL = editorManager.baseURL;
161
+
162
+ /**
163
+ * Editor instance id, normally the same as the div/textarea that was replaced.
164
+ *
165
+ * @property id
166
+ * @type String
167
+ */
168
+ self.id = settings.id = id;
169
+
170
+ /**
171
+ * State to force the editor to return false on a isDirty call.
172
+ *
173
+ * @property isNotDirty
174
+ * @type Boolean
175
+ * @deprecated Use editor.setDirty instead.
176
+ */
177
+ self.setDirty(false);
178
+
179
+ /**
180
+ * Name/Value object containing plugin instances.
181
+ *
182
+ * @property plugins
183
+ * @type Object
184
+ * @example
185
+ * // Execute a method inside a plugin directly
186
+ * tinymce.activeEditor.plugins.someplugin.someMethod();
187
+ */
188
+ self.plugins = {};
189
+
190
+ /**
191
+ * URI object to document configured for the TinyMCE instance.
192
+ *
193
+ * @property documentBaseURI
194
+ * @type tinymce.util.URI
195
+ * @example
196
+ * // Get relative URL from the location of document_base_url
197
+ * tinymce.activeEditor.documentBaseURI.toRelative('/somedir/somefile.htm');
198
+ *
199
+ * // Get absolute URL from the location of document_base_url
200
+ * tinymce.activeEditor.documentBaseURI.toAbsolute('somefile.htm');
201
+ */
202
+ self.documentBaseURI = new URI(settings.document_base_url || documentBaseUrl, {
203
+ base_uri: baseUri
204
+ });
205
+
206
+ /**
207
+ * URI object to current document that holds the TinyMCE editor instance.
208
+ *
209
+ * @property baseURI
210
+ * @type tinymce.util.URI
211
+ * @example
212
+ * // Get relative URL from the location of the API
213
+ * tinymce.activeEditor.baseURI.toRelative('/somedir/somefile.htm');
214
+ *
215
+ * // Get absolute URL from the location of the API
216
+ * tinymce.activeEditor.baseURI.toAbsolute('somefile.htm');
217
+ */
218
+ self.baseURI = baseUri;
219
+
220
+ /**
221
+ * Array with CSS files to load into the iframe.
222
+ *
223
+ * @property contentCSS
224
+ * @type Array
225
+ */
226
+ self.contentCSS = [];
227
+
228
+ /**
229
+ * Array of CSS styles to add to head of document when the editor loads.
230
+ *
231
+ * @property contentStyles
232
+ * @type Array
233
+ */
234
+ self.contentStyles = [];
235
+
236
+ // Creates all events like onClick, onSetContent etc see Editor.Events.js for the actual logic
237
+ self.shortcuts = new Shortcuts(self);
238
+ self.loadedCSS = {};
239
+ self.editorCommands = new EditorCommands(self);
240
+
241
+ if (settings.target) {
242
+ self.targetElm = settings.target;
243
+ }
244
+
245
+ self.suffix = editorManager.suffix;
246
+ self.editorManager = editorManager;
247
+ self.inline = settings.inline;
248
+
249
+ if (settings.cache_suffix) {
250
+ Env.cacheSuffix = settings.cache_suffix.replace(/^[\?\&]+/, '');
251
+ }
252
+
253
+ if (settings.override_viewport === false) {
254
+ Env.overrideViewPort = false;
255
+ }
256
+
257
+ // Call setup
258
+ editorManager.fire('SetupEditor', self);
259
+ self.execCallback('setup', self);
260
+
261
+ /**
262
+ * Dom query instance with default scope to the editor document and default element is the body of the editor.
263
+ *
264
+ * @property $
265
+ * @type tinymce.dom.DomQuery
266
+ * @example
267
+ * tinymce.activeEditor.$('p').css('color', 'red');
268
+ * tinymce.activeEditor.$().append('<p>new</p>');
269
+ */
270
+ self.$ = DomQuery.overrideDefaults(function() {
271
+ return {
272
+ context: self.inline ? self.getBody() : self.getDoc(),
273
+ element: self.getBody()
274
+ };
275
+ });
276
+ }
277
+
278
+ Editor.prototype = {
279
+ /**
280
+ * Renders the editor/adds it to the page.
281
+ *
282
+ * @method render
283
+ */
284
+ render: function() {
285
+ var self = this, settings = self.settings, id = self.id, suffix = self.suffix;
286
+
287
+ function readyHandler() {
288
+ DOM.unbind(window, 'ready', readyHandler);
289
+ self.render();
290
+ }
291
+
292
+ // Page is not loaded yet, wait for it
293
+ if (!Event.domLoaded) {
294
+ DOM.bind(window, 'ready', readyHandler);
295
+ return;
296
+ }
297
+
298
+ // Element not found, then skip initialization
299
+ if (!self.getElement()) {
300
+ return;
301
+ }
302
+
303
+ // No editable support old iOS versions etc
304
+ if (!Env.contentEditable) {
305
+ return;
306
+ }
307
+
308
+ // Hide target element early to prevent content flashing
309
+ if (!settings.inline) {
310
+ self.orgVisibility = self.getElement().style.visibility;
311
+ self.getElement().style.visibility = 'hidden';
312
+ } else {
313
+ self.inline = true;
314
+ }
315
+
316
+ var form = self.getElement().form || DOM.getParent(id, 'form');
317
+ if (form) {
318
+ self.formElement = form;
319
+
320
+ // Add hidden input for non input elements inside form elements
321
+ if (settings.hidden_input && !/TEXTAREA|INPUT/i.test(self.getElement().nodeName)) {
322
+ DOM.insertAfter(DOM.create('input', {type: 'hidden', name: id}), id);
323
+ self.hasHiddenInput = true;
324
+ }
325
+
326
+ // Pass submit/reset from form to editor instance
327
+ self.formEventDelegate = function(e) {
328
+ self.fire(e.type, e);
329
+ };
330
+
331
+ DOM.bind(form, 'submit reset', self.formEventDelegate);
332
+
333
+ // Reset contents in editor when the form is reset
334
+ self.on('reset', function() {
335
+ self.setContent(self.startContent, {format: 'raw'});
336
+ });
337
+
338
+ // Check page uses id="submit" or name="submit" for it's submit button
339
+ if (settings.submit_patch && !form.submit.nodeType && !form.submit.length && !form._mceOldSubmit) {
340
+ form._mceOldSubmit = form.submit;
341
+ form.submit = function() {
342
+ self.editorManager.triggerSave();
343
+ self.setDirty(false);
344
+
345
+ return form._mceOldSubmit(form);
346
+ };
347
+ }
348
+ }
349
+
350
+ /**
351
+ * Window manager reference, use this to open new windows and dialogs.
352
+ *
353
+ * @property windowManager
354
+ * @type tinymce.WindowManager
355
+ * @example
356
+ * // Shows an alert message
357
+ * tinymce.activeEditor.windowManager.alert('Hello world!');
358
+ *
359
+ * // Opens a new dialog with the file.htm file and the size 320x240
360
+ * // It also adds a custom parameter this can be retrieved by using tinyMCEPopup.getWindowArg inside the dialog.
361
+ * tinymce.activeEditor.windowManager.open({
362
+ * url: 'file.htm',
363
+ * width: 320,
364
+ * height: 240
365
+ * }, {
366
+ * custom_param: 1
367
+ * });
368
+ */
369
+ self.windowManager = new WindowManager(self);
370
+
371
+ /**
372
+ * Notification manager reference, use this to open new windows and dialogs.
373
+ *
374
+ * @property notificationManager
375
+ * @type tinymce.NotificationManager
376
+ * @example
377
+ * // Shows a notification info message.
378
+ * tinymce.activeEditor.notificationManager.open({text: 'Hello world!', type: 'info'});
379
+ */
380
+ self.notificationManager = new NotificationManager(self);
381
+
382
+ if (settings.encoding == 'xml') {
383
+ self.on('GetContent', function(e) {
384
+ if (e.save) {
385
+ e.content = DOM.encode(e.content);
386
+ }
387
+ });
388
+ }
389
+
390
+ if (settings.add_form_submit_trigger) {
391
+ self.on('submit', function() {
392
+ if (self.initialized) {
393
+ self.save();
394
+ }
395
+ });
396
+ }
397
+
398
+ if (settings.add_unload_trigger) {
399
+ self._beforeUnload = function() {
400
+ if (self.initialized && !self.destroyed && !self.isHidden()) {
401
+ self.save({format: 'raw', no_events: true, set_dirty: false});
402
+ }
403
+ };
404
+
405
+ self.editorManager.on('BeforeUnload', self._beforeUnload);
406
+ }
407
+
408
+ // Load scripts
409
+ function loadScripts() {
410
+ var scriptLoader = ScriptLoader.ScriptLoader;
411
+
412
+ if (settings.language && settings.language != 'en' && !settings.language_url) {
413
+ settings.language_url = self.editorManager.baseURL + '/langs/' + settings.language + '.js';
414
+ }
415
+
416
+ if (settings.language_url) {
417
+ scriptLoader.add(settings.language_url);
418
+ }
419
+
420
+ if (settings.theme && typeof settings.theme != "function" &&
421
+ settings.theme.charAt(0) != '-' && !ThemeManager.urls[settings.theme]) {
422
+ var themeUrl = settings.theme_url;
423
+
424
+ if (themeUrl) {
425
+ themeUrl = self.documentBaseURI.toAbsolute(themeUrl);
426
+ } else {
427
+ themeUrl = 'themes/' + settings.theme + '/theme' + suffix + '.js';
428
+ }
429
+
430
+ ThemeManager.load(settings.theme, themeUrl);
431
+ }
432
+
433
+ if (Tools.isArray(settings.plugins)) {
434
+ settings.plugins = settings.plugins.join(' ');
435
+ }
436
+
437
+ each(settings.external_plugins, function(url, name) {
438
+ PluginManager.load(name, url);
439
+ settings.plugins += ' ' + name;
440
+ });
441
+
442
+ each(settings.plugins.split(/[ ,]/), function(plugin) {
443
+ plugin = trim(plugin);
444
+
445
+ if (plugin && !PluginManager.urls[plugin]) {
446
+ if (plugin.charAt(0) == '-') {
447
+ plugin = plugin.substr(1, plugin.length);
448
+
449
+ var dependencies = PluginManager.dependencies(plugin);
450
+
451
+ each(dependencies, function(dep) {
452
+ var defaultSettings = {
453
+ prefix: 'plugins/',
454
+ resource: dep,
455
+ suffix: '/plugin' + suffix + '.js'
456
+ };
457
+
458
+ dep = PluginManager.createUrl(defaultSettings, dep);
459
+ PluginManager.load(dep.resource, dep);
460
+ });
461
+ } else {
462
+ PluginManager.load(plugin, {
463
+ prefix: 'plugins/',
464
+ resource: plugin,
465
+ suffix: '/plugin' + suffix + '.js'
466
+ });
467
+ }
468
+ }
469
+ });
470
+
471
+ scriptLoader.loadQueue(function() {
472
+ if (!self.removed) {
473
+ self.init();
474
+ }
475
+ });
476
+ }
477
+
478
+ loadScripts();
479
+ },
480
+
481
+ /**
482
+ * Initializes the editor this will be called automatically when
483
+ * all plugins/themes and language packs are loaded by the rendered method.
484
+ * This method will setup the iframe and create the theme and plugin instances.
485
+ *
486
+ * @method init
487
+ */
488
+ init: function() {
489
+ var self = this, settings = self.settings, elm = self.getElement();
490
+ var w, h, minHeight, n, o, Theme, url, bodyId, bodyClass, re, i, initializedPlugins = [];
491
+
492
+ this.editorManager.i18n.setCode(settings.language);
493
+ self.rtl = settings.rtl_ui || this.editorManager.i18n.rtl;
494
+ self.editorManager.add(self);
495
+
496
+ settings.aria_label = settings.aria_label || DOM.getAttrib(elm, 'aria-label', self.getLang('aria.rich_text_area'));
497
+
498
+ /**
499
+ * Reference to the theme instance that was used to generate the UI.
500
+ *
501
+ * @property theme
502
+ * @type tinymce.Theme
503
+ * @example
504
+ * // Executes a method on the theme directly
505
+ * tinymce.activeEditor.theme.someMethod();
506
+ */
507
+ if (settings.theme) {
508
+ if (typeof settings.theme != "function") {
509
+ settings.theme = settings.theme.replace(/-/, '');
510
+ Theme = ThemeManager.get(settings.theme);
511
+ self.theme = new Theme(self, ThemeManager.urls[settings.theme]);
512
+
513
+ if (self.theme.init) {
514
+ self.theme.init(self, ThemeManager.urls[settings.theme] || self.documentBaseUrl.replace(/\/$/, ''), self.$);
515
+ }
516
+ } else {
517
+ self.theme = settings.theme;
518
+ }
519
+ }
520
+
521
+ function initPlugin(plugin) {
522
+ var Plugin = PluginManager.get(plugin), pluginUrl, pluginInstance;
523
+
524
+ pluginUrl = PluginManager.urls[plugin] || self.documentBaseUrl.replace(/\/$/, '');
525
+ plugin = trim(plugin);
526
+ if (Plugin && inArray(initializedPlugins, plugin) === -1) {
527
+ each(PluginManager.dependencies(plugin), function(dep) {
528
+ initPlugin(dep);
529
+ });
530
+
531
+ if (self.plugins[plugin]) {
532
+ return;
533
+ }
534
+
535
+ pluginInstance = new Plugin(self, pluginUrl, self.$);
536
+
537
+ self.plugins[plugin] = pluginInstance;
538
+
539
+ if (pluginInstance.init) {
540
+ pluginInstance.init(self, pluginUrl);
541
+ initializedPlugins.push(plugin);
542
+ }
543
+ }
544
+ }
545
+
546
+ // Create all plugins
547
+ each(settings.plugins.replace(/\-/g, '').split(/[ ,]/), initPlugin);
548
+
549
+ // Measure box
550
+ if (settings.render_ui && self.theme) {
551
+ self.orgDisplay = elm.style.display;
552
+
553
+ if (typeof settings.theme != "function") {
554
+ w = settings.width || elm.style.width || elm.offsetWidth;
555
+ h = settings.height || elm.style.height || elm.offsetHeight;
556
+ minHeight = settings.min_height || 100;
557
+ re = /^[0-9\.]+(|px)$/i;
558
+
559
+ if (re.test('' + w)) {
560
+ w = Math.max(parseInt(w, 10), 100);
561
+ }
562
+
563
+ if (re.test('' + h)) {
564
+ h = Math.max(parseInt(h, 10), minHeight);
565
+ }
566
+
567
+ // Render UI
568
+ o = self.theme.renderUI({
569
+ targetNode: elm,
570
+ width: w,
571
+ height: h,
572
+ deltaWidth: settings.delta_width,
573
+ deltaHeight: settings.delta_height
574
+ });
575
+
576
+ // Resize editor
577
+ if (!settings.content_editable) {
578
+ h = (o.iframeHeight || h) + (typeof h == 'number' ? (o.deltaHeight || 0) : '');
579
+ if (h < minHeight) {
580
+ h = minHeight;
581
+ }
582
+ }
583
+ } else {
584
+ o = settings.theme(self, elm);
585
+
586
+ // Convert element type to id:s
587
+ if (o.editorContainer.nodeType) {
588
+ o.editorContainer = o.editorContainer.id = o.editorContainer.id || self.id + "_parent";
589
+ }
590
+
591
+ // Convert element type to id:s
592
+ if (o.iframeContainer.nodeType) {
593
+ o.iframeContainer = o.iframeContainer.id = o.iframeContainer.id || self.id + "_iframecontainer";
594
+ }
595
+
596
+ // Use specified iframe height or the targets offsetHeight
597
+ h = o.iframeHeight || elm.offsetHeight;
598
+ }
599
+
600
+ self.editorContainer = o.editorContainer;
601
+ }
602
+
603
+ // Load specified content CSS last
604
+ if (settings.content_css) {
605
+ each(explode(settings.content_css), function(u) {
606
+ self.contentCSS.push(self.documentBaseURI.toAbsolute(u));
607
+ });
608
+ }
609
+
610
+ // Load specified content CSS last
611
+ if (settings.content_style) {
612
+ self.contentStyles.push(settings.content_style);
613
+ }
614
+
615
+ // Content editable mode ends here
616
+ if (settings.content_editable) {
617
+ elm = n = o = null; // Fix IE leak
618
+ return self.initContentBody();
619
+ }
620
+
621
+ self.iframeHTML = settings.doctype + '<html><head>';
622
+
623
+ // We only need to override paths if we have to
624
+ // IE has a bug where it remove site absolute urls to relative ones if this is specified
625
+ if (settings.document_base_url != self.documentBaseUrl) {
626
+ self.iframeHTML += '<base href="' + self.documentBaseURI.getURI() + '" />';
627
+ }
628
+
629
+ // IE8 doesn't support carets behind images setting ie7_compat would force IE8+ to run in IE7 compat mode.
630
+ if (!Env.caretAfter && settings.ie7_compat) {
631
+ self.iframeHTML += '<meta http-equiv="X-UA-Compatible" content="IE=7" />';
632
+ }
633
+
634
+ self.iframeHTML += '<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />';
635
+
636
+ // Load the CSS by injecting them into the HTML this will reduce "flicker"
637
+ // However we can't do that on Chrome since # will scroll to the editor for some odd reason see #2427
638
+ if (!/#$/.test(document.location.href)) {
639
+ for (i = 0; i < self.contentCSS.length; i++) {
640
+ var cssUrl = self.contentCSS[i];
641
+ self.iframeHTML += (
642
+ '<link type="text/css" ' +
643
+ 'rel="stylesheet" ' +
644
+ 'href="' + Tools._addCacheSuffix(cssUrl) + '" />'
645
+ );
646
+ self.loadedCSS[cssUrl] = true;
647
+ }
648
+ }
649
+
650
+ bodyId = settings.body_id || 'tinymce';
651
+ if (bodyId.indexOf('=') != -1) {
652
+ bodyId = self.getParam('body_id', '', 'hash');
653
+ bodyId = bodyId[self.id] || bodyId;
654
+ }
655
+
656
+ bodyClass = settings.body_class || '';
657
+ if (bodyClass.indexOf('=') != -1) {
658
+ bodyClass = self.getParam('body_class', '', 'hash');
659
+ bodyClass = bodyClass[self.id] || '';
660
+ }
661
+
662
+ if (settings.content_security_policy) {
663
+ self.iframeHTML += '<meta http-equiv="Content-Security-Policy" content="' + settings.content_security_policy + '" />';
664
+ }
665
+
666
+ self.iframeHTML += '</head><body id="' + bodyId +
667
+ '" class="mce-content-body ' + bodyClass +
668
+ '" data-id="' + self.id + '"><br></body></html>';
669
+
670
+ /*eslint no-script-url:0 */
671
+ var domainRelaxUrl = 'javascript:(function(){' +
672
+ 'document.open();document.domain="' + document.domain + '";' +
673
+ 'var ed = window.parent.tinymce.get("' + self.id + '");document.write(ed.iframeHTML);' +
674
+ 'document.close();ed.initContentBody(true);})()';
675
+
676
+ // Domain relaxing is required since the user has messed around with document.domain
677
+ if (document.domain != location.hostname) {
678
+ // Edge seems to be able to handle domain relaxing
679
+ if (Env.ie && Env.ie < 12) {
680
+ url = domainRelaxUrl;
681
+ }
682
+ }
683
+
684
+ // Create iframe
685
+ // TODO: ACC add the appropriate description on this.
686
+ var ifr = DOM.create('iframe', {
687
+ id: self.id + "_ifr",
688
+ //src: url || 'javascript:""', // Workaround for HTTPS warning in IE6/7
689
+ frameBorder: '0',
690
+ allowTransparency: "true",
691
+ title: self.editorManager.translate(
692
+ "Rich Text Area. Press ALT-F9 for menu. " +
693
+ "Press ALT-F10 for toolbar. Press ALT-0 for help"
694
+ ),
695
+ style: {
696
+ width: '100%',
697
+ height: h,
698
+ display: 'block' // Important for Gecko to render the iframe correctly
699
+ }
700
+ });
701
+
702
+ ifr.onload = function() {
703
+ ifr.onload = null;
704
+ self.fire("load");
705
+ };
706
+
707
+ DOM.setAttrib(ifr, "src", url || 'javascript:""');
708
+
709
+ self.contentAreaContainer = o.iframeContainer;
710
+ self.iframeElement = ifr;
711
+
712
+ n = DOM.add(o.iframeContainer, ifr);
713
+
714
+ // Try accessing the document this will fail on IE when document.domain is set to the same as location.hostname
715
+ // Then we have to force domain relaxing using the domainRelaxUrl approach very ugly!!
716
+ if (ie) {
717
+ try {
718
+ self.getDoc();
719
+ } catch (e) {
720
+ n.src = url = domainRelaxUrl;
721
+ }
722
+ }
723
+
724
+ if (o.editorContainer) {
725
+ DOM.get(o.editorContainer).style.display = self.orgDisplay;
726
+ self.hidden = DOM.isHidden(o.editorContainer);
727
+ }
728
+
729
+ self.getElement().style.display = 'none';
730
+ DOM.setAttrib(self.id, 'aria-hidden', true);
731
+
732
+ if (!url) {
733
+ self.initContentBody();
734
+ }
735
+
736
+ elm = n = o = null; // Cleanup
737
+ },
738
+
739
+ /**
740
+ * This method get called by the init method once the iframe is loaded.
741
+ * It will fill the iframe with contents, sets up DOM and selection objects for the iframe.
742
+ *
743
+ * @method initContentBody
744
+ * @private
745
+ */
746
+ initContentBody: function(skipWrite) {
747
+ var self = this, settings = self.settings, targetElm = self.getElement(), doc = self.getDoc(), body, contentCssText;
748
+
749
+ // Restore visibility on target element
750
+ if (!settings.inline) {
751
+ self.getElement().style.visibility = self.orgVisibility;
752
+ }
753
+
754
+ // Setup iframe body
755
+ if (!skipWrite && !settings.content_editable) {
756
+ doc.open();
757
+ doc.write(self.iframeHTML);
758
+ doc.close();
759
+ }
760
+
761
+ if (settings.content_editable) {
762
+ self.on('remove', function() {
763
+ var bodyEl = this.getBody();
764
+
765
+ DOM.removeClass(bodyEl, 'mce-content-body');
766
+ DOM.removeClass(bodyEl, 'mce-edit-focus');
767
+ DOM.setAttrib(bodyEl, 'contentEditable', null);
768
+ });
769
+
770
+ DOM.addClass(targetElm, 'mce-content-body');
771
+ self.contentDocument = doc = settings.content_document || document;
772
+ self.contentWindow = settings.content_window || window;
773
+ self.bodyElement = targetElm;
774
+
775
+ // Prevent leak in IE
776
+ settings.content_document = settings.content_window = null;
777
+
778
+ // TODO: Fix this
779
+ settings.root_name = targetElm.nodeName.toLowerCase();
780
+ }
781
+
782
+ // It will not steal focus while setting contentEditable
783
+ body = self.getBody();
784
+ body.disabled = true;
785
+ self.readonly = settings.readonly;
786
+
787
+ if (!self.readonly) {
788
+ if (self.inline && DOM.getStyle(body, 'position', true) == 'static') {
789
+ body.style.position = 'relative';
790
+ }
791
+
792
+ body.contentEditable = self.getParam('content_editable_state', true);
793
+ }
794
+
795
+ body.disabled = false;
796
+
797
+ self.editorUpload = new EditorUpload(self);
798
+
799
+ /**
800
+ * Schema instance, enables you to validate elements and its children.
801
+ *
802
+ * @property schema
803
+ * @type tinymce.html.Schema
804
+ */
805
+ self.schema = new Schema(settings);
806
+
807
+ /**
808
+ * DOM instance for the editor.
809
+ *
810
+ * @property dom
811
+ * @type tinymce.dom.DOMUtils
812
+ * @example
813
+ * // Adds a class to all paragraphs within the editor
814
+ * tinymce.activeEditor.dom.addClass(tinymce.activeEditor.dom.select('p'), 'someclass');
815
+ */
816
+ self.dom = new DOMUtils(doc, {
817
+ keep_values: true,
818
+ url_converter: self.convertURL,
819
+ url_converter_scope: self,
820
+ hex_colors: settings.force_hex_style_colors,
821
+ class_filter: settings.class_filter,
822
+ update_styles: true,
823
+ root_element: self.inline ? self.getBody() : null,
824
+ collect: settings.content_editable,
825
+ schema: self.schema,
826
+ onSetAttrib: function(e) {
827
+ self.fire('SetAttrib', e);
828
+ }
829
+ });
830
+
831
+ /**
832
+ * HTML parser will be used when contents is inserted into the editor.
833
+ *
834
+ * @property parser
835
+ * @type tinymce.html.DomParser
836
+ */
837
+ self.parser = new DomParser(settings, self.schema);
838
+
839
+ // Convert src and href into data-mce-src, data-mce-href and data-mce-style
840
+ self.parser.addAttributeFilter('src,href,style,tabindex', function(nodes, name) {
841
+ var i = nodes.length, node, dom = self.dom, value, internalName;
842
+
843
+ while (i--) {
844
+ node = nodes[i];
845
+ value = node.attr(name);
846
+ internalName = 'data-mce-' + name;
847
+
848
+ // Add internal attribute if we need to we don't on a refresh of the document
849
+ if (!node.attributes.map[internalName]) {
850
+ // Don't duplicate these since they won't get modified by any browser
851
+ if (value.indexOf('data:') === 0 || value.indexOf('blob:') === 0) {
852
+ continue;
853
+ }
854
+
855
+ if (name === "style") {
856
+ value = dom.serializeStyle(dom.parseStyle(value), node.name);
857
+
858
+ if (!value.length) {
859
+ value = null;
860
+ }
861
+
862
+ node.attr(internalName, value);
863
+ node.attr(name, value);
864
+ } else if (name === "tabindex") {
865
+ node.attr(internalName, value);
866
+ node.attr(name, null);
867
+ } else {
868
+ node.attr(internalName, self.convertURL(value, name, node.name));
869
+ }
870
+ }
871
+ }
872
+ });
873
+
874
+ // Keep scripts from executing
875
+ self.parser.addNodeFilter('script', function(nodes) {
876
+ var i = nodes.length, node, type;
877
+
878
+ while (i--) {
879
+ node = nodes[i];
880
+ type = node.attr('type') || 'no/type';
881
+ if (type.indexOf('mce-') !== 0) {
882
+ node.attr('type', 'mce-' + type);
883
+ }
884
+ }
885
+ });
886
+
887
+ self.parser.addNodeFilter('#cdata', function(nodes) {
888
+ var i = nodes.length, node;
889
+
890
+ while (i--) {
891
+ node = nodes[i];
892
+ node.type = 8;
893
+ node.name = '#comment';
894
+ node.value = '[CDATA[' + node.value + ']]';
895
+ }
896
+ });
897
+
898
+ self.parser.addNodeFilter('p,h1,h2,h3,h4,h5,h6,div', function(nodes) {
899
+ var i = nodes.length, node, nonEmptyElements = self.schema.getNonEmptyElements();
900
+
901
+ while (i--) {
902
+ node = nodes[i];
903
+
904
+ if (node.isEmpty(nonEmptyElements)) {
905
+ node.append(new Node('br', 1)).shortEnded = true;
906
+ }
907
+ }
908
+ });
909
+
910
+ /**
911
+ * DOM serializer for the editor. Will be used when contents is extracted from the editor.
912
+ *
913
+ * @property serializer
914
+ * @type tinymce.dom.Serializer
915
+ * @example
916
+ * // Serializes the first paragraph in the editor into a string
917
+ * tinymce.activeEditor.serializer.serialize(tinymce.activeEditor.dom.select('p')[0]);
918
+ */
919
+ self.serializer = new DomSerializer(settings, self);
920
+
921
+ /**
922
+ * Selection instance for the editor.
923
+ *
924
+ * @property selection
925
+ * @type tinymce.dom.Selection
926
+ * @example
927
+ * // Sets some contents to the current selection in the editor
928
+ * tinymce.activeEditor.selection.setContent('Some contents');
929
+ *
930
+ * // Gets the current selection
931
+ * alert(tinymce.activeEditor.selection.getContent());
932
+ *
933
+ * // Selects the first paragraph found
934
+ * tinymce.activeEditor.selection.select(tinymce.activeEditor.dom.select('p')[0]);
935
+ */
936
+ self.selection = new Selection(self.dom, self.getWin(), self.serializer, self);
937
+
938
+ /**
939
+ * Formatter instance.
940
+ *
941
+ * @property formatter
942
+ * @type tinymce.Formatter
943
+ */
944
+ self.formatter = new Formatter(self);
945
+
946
+ /**
947
+ * Undo manager instance, responsible for handling undo levels.
948
+ *
949
+ * @property undoManager
950
+ * @type tinymce.UndoManager
951
+ * @example
952
+ * // Undoes the last modification to the editor
953
+ * tinymce.activeEditor.undoManager.undo();
954
+ */
955
+ self.undoManager = new UndoManager(self);
956
+
957
+ self.forceBlocks = new ForceBlocks(self);
958
+ self.enterKey = new EnterKey(self);
959
+ self._nodeChangeDispatcher = new NodeChange(self);
960
+ self._selectionOverrides = new SelectionOverrides(self);
961
+
962
+ self.fire('PreInit');
963
+
964
+ if (!settings.browser_spellcheck && !settings.gecko_spellcheck) {
965
+ doc.body.spellcheck = false; // Gecko
966
+ DOM.setAttrib(body, "spellcheck", "false");
967
+ }
968
+
969
+ self.fire('PostRender');
970
+
971
+ self.quirks = new Quirks(self);
972
+
973
+ if (settings.directionality) {
974
+ body.dir = settings.directionality;
975
+ }
976
+
977
+ if (settings.nowrap) {
978
+ body.style.whiteSpace = "nowrap";
979
+ }
980
+
981
+ if (settings.protect) {
982
+ self.on('BeforeSetContent', function(e) {
983
+ each(settings.protect, function(pattern) {
984
+ e.content = e.content.replace(pattern, function(str) {
985
+ return '<!--mce:protected ' + escape(str) + '-->';
986
+ });
987
+ });
988
+ });
989
+ }
990
+
991
+ self.on('SetContent', function() {
992
+ self.addVisual(self.getBody());
993
+ });
994
+
995
+ // Remove empty contents
996
+ if (settings.padd_empty_editor) {
997
+ self.on('PostProcess', function(e) {
998
+ e.content = e.content.replace(/^(<p[^>]*>(&nbsp;|&#160;|\s|\u00a0|)<\/p>[\r\n]*|<br \/>[\r\n]*)$/, '');
999
+ });
1000
+ }
1001
+
1002
+ self.load({initial: true, format: 'html'});
1003
+ self.startContent = self.getContent({format: 'raw'});
1004
+
1005
+ /**
1006
+ * Is set to true after the editor instance has been initialized
1007
+ *
1008
+ * @property initialized
1009
+ * @type Boolean
1010
+ * @example
1011
+ * function isEditorInitialized(editor) {
1012
+ * return editor && editor.initialized;
1013
+ * }
1014
+ */
1015
+ self.initialized = true;
1016
+ self.bindPendingEventDelegates();
1017
+
1018
+ self.fire('init');
1019
+ self.focus(true);
1020
+ self.nodeChanged({initial: true});
1021
+ self.execCallback('init_instance_callback', self);
1022
+
1023
+ self.on('compositionstart compositionend', function(e) {
1024
+ self.composing = e.type === 'compositionstart';
1025
+ });
1026
+
1027
+ // Add editor specific CSS styles
1028
+ if (self.contentStyles.length > 0) {
1029
+ contentCssText = '';
1030
+
1031
+ each(self.contentStyles, function(style) {
1032
+ contentCssText += style + "\r\n";
1033
+ });
1034
+
1035
+ self.dom.addStyle(contentCssText);
1036
+ }
1037
+
1038
+ // Load specified content CSS last
1039
+ each(self.contentCSS, function(cssUrl) {
1040
+ if (!self.loadedCSS[cssUrl]) {
1041
+ self.dom.loadCSS(cssUrl);
1042
+ self.loadedCSS[cssUrl] = true;
1043
+ }
1044
+ });
1045
+
1046
+ // Handle auto focus
1047
+ if (settings.auto_focus) {
1048
+ Delay.setEditorTimeout(self, function() {
1049
+ var editor;
1050
+
1051
+ if (settings.auto_focus === true) {
1052
+ editor = self;
1053
+ } else {
1054
+ editor = self.editorManager.get(settings.auto_focus);
1055
+ }
1056
+
1057
+ if (!editor.destroyed) {
1058
+ editor.focus();
1059
+ }
1060
+ }, 100);
1061
+ }
1062
+
1063
+ // Clean up references for IE
1064
+ targetElm = doc = body = null;
1065
+ },
1066
+
1067
+ /**
1068
+ * Focuses/activates the editor. This will set this editor as the activeEditor in the tinymce collection
1069
+ * it will also place DOM focus inside the editor.
1070
+ *
1071
+ * @method focus
1072
+ * @param {Boolean} skipFocus Skip DOM focus. Just set is as the active editor.
1073
+ */
1074
+ focus: function(skipFocus) {
1075
+ var self = this, selection = self.selection, contentEditable = self.settings.content_editable, rng;
1076
+ var controlElm, doc = self.getDoc(), body = self.getBody(), contentEditableHost;
1077
+
1078
+ function getContentEditableHost(node) {
1079
+ return self.dom.getParent(node, function(node) {
1080
+ return self.dom.getContentEditable(node) === "true";
1081
+ });
1082
+ }
1083
+
1084
+ if (!skipFocus) {
1085
+ // Get selected control element
1086
+ rng = selection.getRng();
1087
+ if (rng.item) {
1088
+ controlElm = rng.item(0);
1089
+ }
1090
+
1091
+ self._refreshContentEditable();
1092
+
1093
+ // Move focus to contentEditable=true child if needed
1094
+ contentEditableHost = getContentEditableHost(selection.getNode());
1095
+ if (self.$.contains(body, contentEditableHost)) {
1096
+ contentEditableHost.focus();
1097
+ selection.normalize();
1098
+ self.editorManager.setActive(self);
1099
+ return;
1100
+ }
1101
+
1102
+ // Focus the window iframe
1103
+ if (!contentEditable) {
1104
+ // WebKit needs this call to fire focusin event properly see #5948
1105
+ // But Opera pre Blink engine will produce an empty selection so skip Opera
1106
+ if (!Env.opera) {
1107
+ self.getBody().focus();
1108
+ }
1109
+
1110
+ self.getWin().focus();
1111
+ }
1112
+
1113
+ // Focus the body as well since it's contentEditable
1114
+ if (isGecko || contentEditable) {
1115
+ // Check for setActive since it doesn't scroll to the element
1116
+ if (body.setActive) {
1117
+ // IE 11 sometimes throws "Invalid function" then fallback to focus
1118
+ try {
1119
+ body.setActive();
1120
+ } catch (ex) {
1121
+ body.focus();
1122
+ }
1123
+ } else {
1124
+ body.focus();
1125
+ }
1126
+
1127
+ if (contentEditable) {
1128
+ selection.normalize();
1129
+ }
1130
+ }
1131
+
1132
+ // Restore selected control element
1133
+ // This is needed when for example an image is selected within a
1134
+ // layer a call to focus will then remove the control selection
1135
+ if (controlElm && controlElm.ownerDocument == doc) {
1136
+ rng = doc.body.createControlRange();
1137
+ rng.addElement(controlElm);
1138
+ rng.select();
1139
+ }
1140
+ }
1141
+
1142
+ self.editorManager.setActive(self);
1143
+ },
1144
+
1145
+ /**
1146
+ * Executes a legacy callback. This method is useful to call old 2.x option callbacks.
1147
+ * There new event model is a better way to add callback so this method might be removed in the future.
1148
+ *
1149
+ * @method execCallback
1150
+ * @param {String} name Name of the callback to execute.
1151
+ * @return {Object} Return value passed from callback function.
1152
+ */
1153
+ execCallback: function(name) {
1154
+ var self = this, callback = self.settings[name], scope;
1155
+
1156
+ if (!callback) {
1157
+ return;
1158
+ }
1159
+
1160
+ // Look through lookup
1161
+ if (self.callbackLookup && (scope = self.callbackLookup[name])) {
1162
+ callback = scope.func;
1163
+ scope = scope.scope;
1164
+ }
1165
+
1166
+ if (typeof callback === 'string') {
1167
+ scope = callback.replace(/\.\w+$/, '');
1168
+ scope = scope ? resolve(scope) : 0;
1169
+ callback = resolve(callback);
1170
+ self.callbackLookup = self.callbackLookup || {};
1171
+ self.callbackLookup[name] = {func: callback, scope: scope};
1172
+ }
1173
+
1174
+ return callback.apply(scope || self, Array.prototype.slice.call(arguments, 1));
1175
+ },
1176
+
1177
+ /**
1178
+ * Translates the specified string by replacing variables with language pack items it will also check if there is
1179
+ * a key mathcin the input.
1180
+ *
1181
+ * @method translate
1182
+ * @param {String} text String to translate by the language pack data.
1183
+ * @return {String} Translated string.
1184
+ */
1185
+ translate: function(text) {
1186
+ var lang = this.settings.language || 'en', i18n = this.editorManager.i18n;
1187
+
1188
+ if (!text) {
1189
+ return '';
1190
+ }
1191
+
1192
+ return i18n.data[lang + '.' + text] || text.replace(/\{\#([^\}]+)\}/g, function(a, b) {
1193
+ return i18n.data[lang + '.' + b] || '{#' + b + '}';
1194
+ });
1195
+ },
1196
+
1197
+ /**
1198
+ * Returns a language pack item by name/key.
1199
+ *
1200
+ * @method getLang
1201
+ * @param {String} name Name/key to get from the language pack.
1202
+ * @param {String} defaultVal Optional default value to retrive.
1203
+ */
1204
+ getLang: function(name, defaultVal) {
1205
+ return (
1206
+ this.editorManager.i18n.data[(this.settings.language || 'en') + '.' + name] ||
1207
+ (defaultVal !== undefined ? defaultVal : '{#' + name + '}')
1208
+ );
1209
+ },
1210
+
1211
+ /**
1212
+ * Returns a configuration parameter by name.
1213
+ *
1214
+ * @method getParam
1215
+ * @param {String} name Configruation parameter to retrive.
1216
+ * @param {String} defaultVal Optional default value to return.
1217
+ * @param {String} type Optional type parameter.
1218
+ * @return {String} Configuration parameter value or default value.
1219
+ * @example
1220
+ * // Returns a specific config value from the currently active editor
1221
+ * var someval = tinymce.activeEditor.getParam('myvalue');
1222
+ *
1223
+ * // Returns a specific config value from a specific editor instance by id
1224
+ * var someval2 = tinymce.get('my_editor').getParam('myvalue');
1225
+ */
1226
+ getParam: function(name, defaultVal, type) {
1227
+ var value = name in this.settings ? this.settings[name] : defaultVal, output;
1228
+
1229
+ if (type === 'hash') {
1230
+ output = {};
1231
+
1232
+ if (typeof value === 'string') {
1233
+ each(value.indexOf('=') > 0 ? value.split(/[;,](?![^=;,]*(?:[;,]|$))/) : value.split(','), function(value) {
1234
+ value = value.split('=');
1235
+
1236
+ if (value.length > 1) {
1237
+ output[trim(value[0])] = trim(value[1]);
1238
+ } else {
1239
+ output[trim(value[0])] = trim(value);
1240
+ }
1241
+ });
1242
+ } else {
1243
+ output = value;
1244
+ }
1245
+
1246
+ return output;
1247
+ }
1248
+
1249
+ return value;
1250
+ },
1251
+
1252
+ /**
1253
+ * Dispatches out a onNodeChange event to all observers. This method should be called when you
1254
+ * need to update the UI states or element path etc.
1255
+ *
1256
+ * @method nodeChanged
1257
+ * @param {Object} args Optional args to pass to NodeChange event handlers.
1258
+ */
1259
+ nodeChanged: function(args) {
1260
+ this._nodeChangeDispatcher.nodeChanged(args);
1261
+ },
1262
+
1263
+ /**
1264
+ * Adds a button that later gets created by the theme in the editors toolbars.
1265
+ *
1266
+ * @method addButton
1267
+ * @param {String} name Button name to add.
1268
+ * @param {Object} settings Settings object with title, cmd etc.
1269
+ * @example
1270
+ * // Adds a custom button to the editor that inserts contents when clicked
1271
+ * tinymce.init({
1272
+ * ...
1273
+ *
1274
+ * toolbar: 'example'
1275
+ *
1276
+ * setup: function(ed) {
1277
+ * ed.addButton('example', {
1278
+ * title: 'My title',
1279
+ * image: '../js/tinymce/plugins/example/img/example.gif',
1280
+ * onclick: function() {
1281
+ * ed.insertContent('Hello world!!');
1282
+ * }
1283
+ * });
1284
+ * }
1285
+ * });
1286
+ */
1287
+ addButton: function(name, settings) {
1288
+ var self = this;
1289
+
1290
+ if (settings.cmd) {
1291
+ settings.onclick = function() {
1292
+ self.execCommand(settings.cmd);
1293
+ };
1294
+ }
1295
+
1296
+ if (!settings.text && !settings.icon) {
1297
+ settings.icon = name;
1298
+ }
1299
+
1300
+ self.buttons = self.buttons || {};
1301
+ settings.tooltip = settings.tooltip || settings.title;
1302
+ self.buttons[name] = settings;
1303
+ },
1304
+
1305
+ /**
1306
+ * Adds a menu item to be used in the menus of the theme. There might be multiple instances
1307
+ * of this menu item for example it might be used in the main menus of the theme but also in
1308
+ * the context menu so make sure that it's self contained and supports multiple instances.
1309
+ *
1310
+ * @method addMenuItem
1311
+ * @param {String} name Menu item name to add.
1312
+ * @param {Object} settings Settings object with title, cmd etc.
1313
+ * @example
1314
+ * // Adds a custom menu item to the editor that inserts contents when clicked
1315
+ * // The context option allows you to add the menu item to an existing default menu
1316
+ * tinymce.init({
1317
+ * ...
1318
+ *
1319
+ * setup: function(ed) {
1320
+ * ed.addMenuItem('example', {
1321
+ * text: 'My menu item',
1322
+ * context: 'tools',
1323
+ * onclick: function() {
1324
+ * ed.insertContent('Hello world!!');
1325
+ * }
1326
+ * });
1327
+ * }
1328
+ * });
1329
+ */
1330
+ addMenuItem: function(name, settings) {
1331
+ var self = this;
1332
+
1333
+ if (settings.cmd) {
1334
+ settings.onclick = function() {
1335
+ self.execCommand(settings.cmd);
1336
+ };
1337
+ }
1338
+
1339
+ self.menuItems = self.menuItems || {};
1340
+ self.menuItems[name] = settings;
1341
+ },
1342
+
1343
+ /**
1344
+ * Adds a contextual toolbar to be rendered when the selector matches.
1345
+ *
1346
+ * @method addContextToolbar
1347
+ * @param {function/string} predicate Predicate that needs to return true if provided strings get converted into CSS predicates.
1348
+ * @param {String/Array} items String or array with items to add to the context toolbar.
1349
+ */
1350
+ addContextToolbar: function(predicate, items) {
1351
+ var self = this, selector;
1352
+
1353
+ self.contextToolbars = self.contextToolbars || [];
1354
+
1355
+ // Convert selector to predicate
1356
+ if (typeof predicate == "string") {
1357
+ selector = predicate;
1358
+ predicate = function(elm) {
1359
+ return self.dom.is(elm, selector);
1360
+ };
1361
+ }
1362
+
1363
+ self.contextToolbars.push({
1364
+ predicate: predicate,
1365
+ items: items
1366
+ });
1367
+ },
1368
+
1369
+ /**
1370
+ * Adds a custom command to the editor, you can also override existing commands with this method.
1371
+ * The command that you add can be executed with execCommand.
1372
+ *
1373
+ * @method addCommand
1374
+ * @param {String} name Command name to add/override.
1375
+ * @param {addCommandCallback} callback Function to execute when the command occurs.
1376
+ * @param {Object} scope Optional scope to execute the function in.
1377
+ * @example
1378
+ * // Adds a custom command that later can be executed using execCommand
1379
+ * tinymce.init({
1380
+ * ...
1381
+ *
1382
+ * setup: function(ed) {
1383
+ * // Register example command
1384
+ * ed.addCommand('mycommand', function(ui, v) {
1385
+ * ed.windowManager.alert('Hello world!! Selection: ' + ed.selection.getContent({format: 'text'}));
1386
+ * });
1387
+ * }
1388
+ * });
1389
+ */
1390
+ addCommand: function(name, callback, scope) {
1391
+ /**
1392
+ * Callback function that gets called when a command is executed.
1393
+ *
1394
+ * @callback addCommandCallback
1395
+ * @param {Boolean} ui Display UI state true/false.
1396
+ * @param {Object} value Optional value for command.
1397
+ * @return {Boolean} True/false state if the command was handled or not.
1398
+ */
1399
+ this.editorCommands.addCommand(name, callback, scope);
1400
+ },
1401
+
1402
+ /**
1403
+ * Adds a custom query state command to the editor, you can also override existing commands with this method.
1404
+ * The command that you add can be executed with queryCommandState function.
1405
+ *
1406
+ * @method addQueryStateHandler
1407
+ * @param {String} name Command name to add/override.
1408
+ * @param {addQueryStateHandlerCallback} callback Function to execute when the command state retrieval occurs.
1409
+ * @param {Object} scope Optional scope to execute the function in.
1410
+ */
1411
+ addQueryStateHandler: function(name, callback, scope) {
1412
+ /**
1413
+ * Callback function that gets called when a queryCommandState is executed.
1414
+ *
1415
+ * @callback addQueryStateHandlerCallback
1416
+ * @return {Boolean} True/false state if the command is enabled or not like is it bold.
1417
+ */
1418
+ this.editorCommands.addQueryStateHandler(name, callback, scope);
1419
+ },
1420
+
1421
+ /**
1422
+ * Adds a custom query value command to the editor, you can also override existing commands with this method.
1423
+ * The command that you add can be executed with queryCommandValue function.
1424
+ *
1425
+ * @method addQueryValueHandler
1426
+ * @param {String} name Command name to add/override.
1427
+ * @param {addQueryValueHandlerCallback} callback Function to execute when the command value retrieval occurs.
1428
+ * @param {Object} scope Optional scope to execute the function in.
1429
+ */
1430
+ addQueryValueHandler: function(name, callback, scope) {
1431
+ /**
1432
+ * Callback function that gets called when a queryCommandValue is executed.
1433
+ *
1434
+ * @callback addQueryValueHandlerCallback
1435
+ * @return {Object} Value of the command or undefined.
1436
+ */
1437
+ this.editorCommands.addQueryValueHandler(name, callback, scope);
1438
+ },
1439
+
1440
+ /**
1441
+ * Adds a keyboard shortcut for some command or function.
1442
+ *
1443
+ * @method addShortcut
1444
+ * @param {String} pattern Shortcut pattern. Like for example: ctrl+alt+o.
1445
+ * @param {String} desc Text description for the command.
1446
+ * @param {String/Function} cmdFunc Command name string or function to execute when the key is pressed.
1447
+ * @param {Object} sc Optional scope to execute the function in.
1448
+ * @return {Boolean} true/false state if the shortcut was added or not.
1449
+ */
1450
+ addShortcut: function(pattern, desc, cmdFunc, scope) {
1451
+ this.shortcuts.add(pattern, desc, cmdFunc, scope);
1452
+ },
1453
+
1454
+ /**
1455
+ * Executes a command on the current instance. These commands can be TinyMCE internal commands prefixed with "mce" or
1456
+ * they can be build in browser commands such as "Bold". A compleate list of browser commands is available on MSDN or Mozilla.org.
1457
+ * This function will dispatch the execCommand function on each plugin, theme or the execcommand_callback option if none of these
1458
+ * return true it will handle the command as a internal browser command.
1459
+ *
1460
+ * @method execCommand
1461
+ * @param {String} cmd Command name to execute, for example mceLink or Bold.
1462
+ * @param {Boolean} ui True/false state if a UI (dialog) should be presented or not.
1463
+ * @param {mixed} value Optional command value, this can be anything.
1464
+ * @param {Object} args Optional arguments object.
1465
+ */
1466
+ execCommand: function(cmd, ui, value, args) {
1467
+ return this.editorCommands.execCommand(cmd, ui, value, args);
1468
+ },
1469
+
1470
+ /**
1471
+ * Returns a command specific state, for example if bold is enabled or not.
1472
+ *
1473
+ * @method queryCommandState
1474
+ * @param {string} cmd Command to query state from.
1475
+ * @return {Boolean} Command specific state, for example if bold is enabled or not.
1476
+ */
1477
+ queryCommandState: function(cmd) {
1478
+ return this.editorCommands.queryCommandState(cmd);
1479
+ },
1480
+
1481
+ /**
1482
+ * Returns a command specific value, for example the current font size.
1483
+ *
1484
+ * @method queryCommandValue
1485
+ * @param {string} cmd Command to query value from.
1486
+ * @return {Object} Command specific value, for example the current font size.
1487
+ */
1488
+ queryCommandValue: function(cmd) {
1489
+ return this.editorCommands.queryCommandValue(cmd);
1490
+ },
1491
+
1492
+ /**
1493
+ * Returns true/false if the command is supported or not.
1494
+ *
1495
+ * @method queryCommandSupported
1496
+ * @param {String} cmd Command that we check support for.
1497
+ * @return {Boolean} true/false if the command is supported or not.
1498
+ */
1499
+ queryCommandSupported: function(cmd) {
1500
+ return this.editorCommands.queryCommandSupported(cmd);
1501
+ },
1502
+
1503
+ /**
1504
+ * Shows the editor and hides any textarea/div that the editor is supposed to replace.
1505
+ *
1506
+ * @method show
1507
+ */
1508
+ show: function() {
1509
+ var self = this;
1510
+
1511
+ if (self.hidden) {
1512
+ self.hidden = false;
1513
+
1514
+ if (self.inline) {
1515
+ self.getBody().contentEditable = true;
1516
+ } else {
1517
+ DOM.show(self.getContainer());
1518
+ DOM.hide(self.id);
1519
+ }
1520
+
1521
+ self.load();
1522
+ self.fire('show');
1523
+ }
1524
+ },
1525
+
1526
+ /**
1527
+ * Hides the editor and shows any textarea/div that the editor is supposed to replace.
1528
+ *
1529
+ * @method hide
1530
+ */
1531
+ hide: function() {
1532
+ var self = this, doc = self.getDoc();
1533
+
1534
+ if (!self.hidden) {
1535
+ // Fixed bug where IE has a blinking cursor left from the editor
1536
+ if (ie && doc && !self.inline) {
1537
+ doc.execCommand('SelectAll');
1538
+ }
1539
+
1540
+ // We must save before we hide so Safari doesn't crash
1541
+ self.save();
1542
+
1543
+ if (self.inline) {
1544
+ self.getBody().contentEditable = false;
1545
+
1546
+ // Make sure the editor gets blurred
1547
+ if (self == self.editorManager.focusedEditor) {
1548
+ self.editorManager.focusedEditor = null;
1549
+ }
1550
+ } else {
1551
+ DOM.hide(self.getContainer());
1552
+ DOM.setStyle(self.id, 'display', self.orgDisplay);
1553
+ }
1554
+
1555
+ self.hidden = true;
1556
+ self.fire('hide');
1557
+ }
1558
+ },
1559
+
1560
+ /**
1561
+ * Returns true/false if the editor is hidden or not.
1562
+ *
1563
+ * @method isHidden
1564
+ * @return {Boolean} True/false if the editor is hidden or not.
1565
+ */
1566
+ isHidden: function() {
1567
+ return !!this.hidden;
1568
+ },
1569
+
1570
+ /**
1571
+ * Sets the progress state, this will display a throbber/progess for the editor.
1572
+ * This is ideal for asynchronous operations like an AJAX save call.
1573
+ *
1574
+ * @method setProgressState
1575
+ * @param {Boolean} state Boolean state if the progress should be shown or hidden.
1576
+ * @param {Number} time Optional time to wait before the progress gets shown.
1577
+ * @return {Boolean} Same as the input state.
1578
+ * @example
1579
+ * // Show progress for the active editor
1580
+ * tinymce.activeEditor.setProgressState(true);
1581
+ *
1582
+ * // Hide progress for the active editor
1583
+ * tinymce.activeEditor.setProgressState(false);
1584
+ *
1585
+ * // Show progress after 3 seconds
1586
+ * tinymce.activeEditor.setProgressState(true, 3000);
1587
+ */
1588
+ setProgressState: function(state, time) {
1589
+ this.fire('ProgressState', {state: state, time: time});
1590
+ },
1591
+
1592
+ /**
1593
+ * Loads contents from the textarea or div element that got converted into an editor instance.
1594
+ * This method will move the contents from that textarea or div into the editor by using setContent
1595
+ * so all events etc that method has will get dispatched as well.
1596
+ *
1597
+ * @method load
1598
+ * @param {Object} args Optional content object, this gets passed around through the whole load process.
1599
+ * @return {String} HTML string that got set into the editor.
1600
+ */
1601
+ load: function(args) {
1602
+ var self = this, elm = self.getElement(), html;
1603
+
1604
+ if (elm) {
1605
+ args = args || {};
1606
+ args.load = true;
1607
+
1608
+ html = self.setContent(elm.value !== undefined ? elm.value : elm.innerHTML, args);
1609
+ args.element = elm;
1610
+
1611
+ if (!args.no_events) {
1612
+ self.fire('LoadContent', args);
1613
+ }
1614
+
1615
+ args.element = elm = null;
1616
+
1617
+ return html;
1618
+ }
1619
+ },
1620
+
1621
+ /**
1622
+ * Saves the contents from a editor out to the textarea or div element that got converted into an editor instance.
1623
+ * This method will move the HTML contents from the editor into that textarea or div by getContent
1624
+ * so all events etc that method has will get dispatched as well.
1625
+ *
1626
+ * @method save
1627
+ * @param {Object} args Optional content object, this gets passed around through the whole save process.
1628
+ * @return {String} HTML string that got set into the textarea/div.
1629
+ */
1630
+ save: function(args) {
1631
+ var self = this, elm = self.getElement(), html, form;
1632
+
1633
+ if (!elm || !self.initialized) {
1634
+ return;
1635
+ }
1636
+
1637
+ args = args || {};
1638
+ args.save = true;
1639
+
1640
+ args.element = elm;
1641
+ html = args.content = self.getContent(args);
1642
+
1643
+ if (!args.no_events) {
1644
+ self.fire('SaveContent', args);
1645
+ }
1646
+
1647
+ // Always run this internal event
1648
+ if (args.format == 'raw') {
1649
+ self.fire('RawSaveContent', args);
1650
+ }
1651
+
1652
+ html = args.content;
1653
+
1654
+ if (!/TEXTAREA|INPUT/i.test(elm.nodeName)) {
1655
+ // Update DIV element when not in inline mode
1656
+ if (!self.inline) {
1657
+ elm.innerHTML = html;
1658
+ }
1659
+
1660
+ // Update hidden form element
1661
+ if ((form = DOM.getParent(self.id, 'form'))) {
1662
+ each(form.elements, function(elm) {
1663
+ if (elm.name == self.id) {
1664
+ elm.value = html;
1665
+ return false;
1666
+ }
1667
+ });
1668
+ }
1669
+ } else {
1670
+ elm.value = html;
1671
+ }
1672
+
1673
+ args.element = elm = null;
1674
+
1675
+ if (args.set_dirty !== false) {
1676
+ self.setDirty(false);
1677
+ }
1678
+
1679
+ return html;
1680
+ },
1681
+
1682
+ /**
1683
+ * Sets the specified content to the editor instance, this will cleanup the content before it gets set using
1684
+ * the different cleanup rules options.
1685
+ *
1686
+ * @method setContent
1687
+ * @param {String} content Content to set to editor, normally HTML contents but can be other formats as well.
1688
+ * @param {Object} args Optional content object, this gets passed around through the whole set process.
1689
+ * @return {String} HTML string that got set into the editor.
1690
+ * @example
1691
+ * // Sets the HTML contents of the activeEditor editor
1692
+ * tinymce.activeEditor.setContent('<span>some</span> html');
1693
+ *
1694
+ * // Sets the raw contents of the activeEditor editor
1695
+ * tinymce.activeEditor.setContent('<span>some</span> html', {format: 'raw'});
1696
+ *
1697
+ * // Sets the content of a specific editor (my_editor in this example)
1698
+ * tinymce.get('my_editor').setContent(data);
1699
+ *
1700
+ * // Sets the bbcode contents of the activeEditor editor if the bbcode plugin was added
1701
+ * tinymce.activeEditor.setContent('[b]some[/b] html', {format: 'bbcode'});
1702
+ */
1703
+ setContent: function(content, args) {
1704
+ var self = this, body = self.getBody(), forcedRootBlockName, padd;
1705
+
1706
+ // Setup args object
1707
+ args = args || {};
1708
+ args.format = args.format || 'html';
1709
+ args.set = true;
1710
+ args.content = content;
1711
+
1712
+ // Do preprocessing
1713
+ if (!args.no_events) {
1714
+ self.fire('BeforeSetContent', args);
1715
+ }
1716
+
1717
+ content = args.content;
1718
+
1719
+ // Padd empty content in Gecko and Safari. Commands will otherwise fail on the content
1720
+ // It will also be impossible to place the caret in the editor unless there is a BR element present
1721
+ if (content.length === 0 || /^\s+$/.test(content)) {
1722
+ padd = ie && ie < 11 ? '' : '<br data-mce-bogus="1">';
1723
+
1724
+ // Todo: There is a lot more root elements that need special padding
1725
+ // so separate this and add all of them at some point.
1726
+ if (body.nodeName == 'TABLE') {
1727
+ content = '<tr><td>' + padd + '</td></tr>';
1728
+ } else if (/^(UL|OL)$/.test(body.nodeName)) {
1729
+ content = '<li>' + padd + '</li>';
1730
+ }
1731
+
1732
+ forcedRootBlockName = self.settings.forced_root_block;
1733
+
1734
+ // Check if forcedRootBlock is configured and that the block is a valid child of the body
1735
+ if (forcedRootBlockName && self.schema.isValidChild(body.nodeName.toLowerCase(), forcedRootBlockName.toLowerCase())) {
1736
+ // Padd with bogus BR elements on modern browsers and IE 7 and 8 since they don't render empty P tags properly
1737
+ content = padd;
1738
+ content = self.dom.createHTML(forcedRootBlockName, self.settings.forced_root_block_attrs, content);
1739
+ } else if (!ie && !content) {
1740
+ // We need to add a BR when forced_root_block is disabled on non IE browsers to place the caret
1741
+ content = '<br data-mce-bogus="1">';
1742
+ }
1743
+
1744
+ self.dom.setHTML(body, content);
1745
+
1746
+ self.fire('SetContent', args);
1747
+ } else {
1748
+ // Parse and serialize the html
1749
+ if (args.format !== 'raw') {
1750
+ content = new Serializer({
1751
+ validate: self.validate
1752
+ }, self.schema).serialize(
1753
+ self.parser.parse(content, {isRootContent: true})
1754
+ );
1755
+ }
1756
+
1757
+ // Set the new cleaned contents to the editor
1758
+ args.content = trim(content);
1759
+ self.dom.setHTML(body, args.content);
1760
+
1761
+ // Do post processing
1762
+ if (!args.no_events) {
1763
+ self.fire('SetContent', args);
1764
+ }
1765
+
1766
+ // Don't normalize selection if the focused element isn't the body in
1767
+ // content editable mode since it will steal focus otherwise
1768
+ /*if (!self.settings.content_editable || document.activeElement === self.getBody()) {
1769
+ self.selection.normalize();
1770
+ }*/
1771
+ }
1772
+
1773
+ return args.content;
1774
+ },
1775
+
1776
+ /**
1777
+ * Gets the content from the editor instance, this will cleanup the content before it gets returned using
1778
+ * the different cleanup rules options.
1779
+ *
1780
+ * @method getContent
1781
+ * @param {Object} args Optional content object, this gets passed around through the whole get process.
1782
+ * @return {String} Cleaned content string, normally HTML contents.
1783
+ * @example
1784
+ * // Get the HTML contents of the currently active editor
1785
+ * console.debug(tinymce.activeEditor.getContent());
1786
+ *
1787
+ * // Get the raw contents of the currently active editor
1788
+ * tinymce.activeEditor.getContent({format: 'raw'});
1789
+ *
1790
+ * // Get content of a specific editor:
1791
+ * tinymce.get('content id').getContent()
1792
+ */
1793
+ getContent: function(args) {
1794
+ var self = this, content, body = self.getBody();
1795
+
1796
+ // Setup args object
1797
+ args = args || {};
1798
+ args.format = args.format || 'html';
1799
+ args.get = true;
1800
+ args.getInner = true;
1801
+
1802
+ // Do preprocessing
1803
+ if (!args.no_events) {
1804
+ self.fire('BeforeGetContent', args);
1805
+ }
1806
+
1807
+ // Get raw contents or by default the cleaned contents
1808
+ if (args.format == 'raw') {
1809
+ content = self.serializer.getTrimmedContent();
1810
+ } else if (args.format == 'text') {
1811
+ content = body.innerText || body.textContent;
1812
+ } else {
1813
+ content = self.serializer.serialize(body, args);
1814
+ }
1815
+
1816
+ // Trim whitespace in beginning/end of HTML
1817
+ if (args.format != 'text') {
1818
+ args.content = trim(content);
1819
+ } else {
1820
+ args.content = content;
1821
+ }
1822
+
1823
+ // Do post processing
1824
+ if (!args.no_events) {
1825
+ self.fire('GetContent', args);
1826
+ }
1827
+
1828
+ return args.content;
1829
+ },
1830
+
1831
+ /**
1832
+ * Inserts content at caret position.
1833
+ *
1834
+ * @method insertContent
1835
+ * @param {String} content Content to insert.
1836
+ * @param {Object} args Optional args to pass to insert call.
1837
+ */
1838
+ insertContent: function(content, args) {
1839
+ if (args) {
1840
+ content = extend({content: content}, args);
1841
+ }
1842
+
1843
+ this.execCommand('mceInsertContent', false, content);
1844
+ },
1845
+
1846
+ /**
1847
+ * Returns true/false if the editor is dirty or not. It will get dirty if the user has made modifications to the contents.
1848
+ *
1849
+ * The dirty state is automatically set to true if you do modifications to the content in other
1850
+ * words when new undo levels is created or if you undo/redo to update the contents of the editor. It will also be set
1851
+ * to false if you call editor.save().
1852
+ *
1853
+ * @method isDirty
1854
+ * @return {Boolean} True/false if the editor is dirty or not. It will get dirty if the user has made modifications to the contents.
1855
+ * @example
1856
+ * if (tinymce.activeEditor.isDirty())
1857
+ * alert("You must save your contents.");
1858
+ */
1859
+ isDirty: function() {
1860
+ return !this.isNotDirty;
1861
+ },
1862
+
1863
+ /**
1864
+ * Explicitly sets the dirty state. This will fire the dirty event if the editor dirty state is changed from false to true
1865
+ * by invoking this method.
1866
+ *
1867
+ * @method setDirty
1868
+ * @param {Boolean} state True/false if the editor is considered dirty.
1869
+ * @example
1870
+ * function ajaxSave() {
1871
+ * var editor = tinymce.get('elm1');
1872
+ *
1873
+ * // Save contents using some XHR call
1874
+ * alert(editor.getContent());
1875
+ *
1876
+ * editor.setDirty(false); // Force not dirty state
1877
+ * }
1878
+ */
1879
+ setDirty: function(state) {
1880
+ var oldState = !this.isNotDirty;
1881
+
1882
+ this.isNotDirty = !state;
1883
+
1884
+ if (state && state != oldState) {
1885
+ this.fire('dirty');
1886
+ }
1887
+ },
1888
+
1889
+ /**
1890
+ * Sets the editor mode. Mode can be for example "design", "code" or "readonly".
1891
+ *
1892
+ * @method setMode
1893
+ * @param {String} mode Mode to set the editor in.
1894
+ */
1895
+ setMode: function(mode) {
1896
+ Mode.setMode(this, mode);
1897
+ },
1898
+
1899
+ /**
1900
+ * Returns the editors container element. The container element wrappes in
1901
+ * all the elements added to the page for the editor. Such as UI, iframe etc.
1902
+ *
1903
+ * @method getContainer
1904
+ * @return {Element} HTML DOM element for the editor container.
1905
+ */
1906
+ getContainer: function() {
1907
+ var self = this;
1908
+
1909
+ if (!self.container) {
1910
+ self.container = DOM.get(self.editorContainer || self.id + '_parent');
1911
+ }
1912
+
1913
+ return self.container;
1914
+ },
1915
+
1916
+ /**
1917
+ * Returns the editors content area container element. The this element is the one who
1918
+ * holds the iframe or the editable element.
1919
+ *
1920
+ * @method getContentAreaContainer
1921
+ * @return {Element} HTML DOM element for the editor area container.
1922
+ */
1923
+ getContentAreaContainer: function() {
1924
+ return this.contentAreaContainer;
1925
+ },
1926
+
1927
+ /**
1928
+ * Returns the target element/textarea that got replaced with a TinyMCE editor instance.
1929
+ *
1930
+ * @method getElement
1931
+ * @return {Element} HTML DOM element for the replaced element.
1932
+ */
1933
+ getElement: function() {
1934
+ if (!this.targetElm) {
1935
+ this.targetElm = DOM.get(this.id);
1936
+ }
1937
+
1938
+ return this.targetElm;
1939
+ },
1940
+
1941
+ /**
1942
+ * Returns the iframes window object.
1943
+ *
1944
+ * @method getWin
1945
+ * @return {Window} Iframe DOM window object.
1946
+ */
1947
+ getWin: function() {
1948
+ var self = this, elm;
1949
+
1950
+ if (!self.contentWindow) {
1951
+ elm = self.iframeElement;
1952
+
1953
+ if (elm) {
1954
+ self.contentWindow = elm.contentWindow;
1955
+ }
1956
+ }
1957
+
1958
+ return self.contentWindow;
1959
+ },
1960
+
1961
+ /**
1962
+ * Returns the iframes document object.
1963
+ *
1964
+ * @method getDoc
1965
+ * @return {Document} Iframe DOM document object.
1966
+ */
1967
+ getDoc: function() {
1968
+ var self = this, win;
1969
+
1970
+ if (!self.contentDocument) {
1971
+ win = self.getWin();
1972
+
1973
+ if (win) {
1974
+ self.contentDocument = win.document;
1975
+ }
1976
+ }
1977
+
1978
+ return self.contentDocument;
1979
+ },
1980
+
1981
+ /**
1982
+ * Returns the root element of the editable area.
1983
+ * For a non-inline iframe-based editor, returns the iframe's body element.
1984
+ *
1985
+ * @method getBody
1986
+ * @return {Element} The root element of the editable area.
1987
+ */
1988
+ getBody: function() {
1989
+ return this.bodyElement || this.getDoc().body;
1990
+ },
1991
+
1992
+ /**
1993
+ * URL converter function this gets executed each time a user adds an img, a or
1994
+ * any other element that has a URL in it. This will be called both by the DOM and HTML
1995
+ * manipulation functions.
1996
+ *
1997
+ * @method convertURL
1998
+ * @param {string} url URL to convert.
1999
+ * @param {string} name Attribute name src, href etc.
2000
+ * @param {string/HTMLElement} elm Tag name or HTML DOM element depending on HTML or DOM insert.
2001
+ * @return {string} Converted URL string.
2002
+ */
2003
+ convertURL: function(url, name, elm) {
2004
+ var self = this, settings = self.settings;
2005
+
2006
+ // Use callback instead
2007
+ if (settings.urlconverter_callback) {
2008
+ return self.execCallback('urlconverter_callback', url, elm, true, name);
2009
+ }
2010
+
2011
+ // Don't convert link href since thats the CSS files that gets loaded into the editor also skip local file URLs
2012
+ if (!settings.convert_urls || (elm && elm.nodeName == 'LINK') || url.indexOf('file:') === 0 || url.length === 0) {
2013
+ return url;
2014
+ }
2015
+
2016
+ // Convert to relative
2017
+ if (settings.relative_urls) {
2018
+ return self.documentBaseURI.toRelative(url);
2019
+ }
2020
+
2021
+ // Convert to absolute
2022
+ url = self.documentBaseURI.toAbsolute(url, settings.remove_script_host);
2023
+
2024
+ return url;
2025
+ },
2026
+
2027
+ /**
2028
+ * Adds visual aid for tables, anchors etc so they can be more easily edited inside the editor.
2029
+ *
2030
+ * @method addVisual
2031
+ * @param {Element} elm Optional root element to loop though to find tables etc that needs the visual aid.
2032
+ */
2033
+ addVisual: function(elm) {
2034
+ var self = this, settings = self.settings, dom = self.dom, cls;
2035
+
2036
+ elm = elm || self.getBody();
2037
+
2038
+ if (self.hasVisual === undefined) {
2039
+ self.hasVisual = settings.visual;
2040
+ }
2041
+
2042
+ each(dom.select('table,a', elm), function(elm) {
2043
+ var value;
2044
+
2045
+ switch (elm.nodeName) {
2046
+ case 'TABLE':
2047
+ cls = settings.visual_table_class || 'mce-item-table';
2048
+ value = dom.getAttrib(elm, 'border');
2049
+
2050
+ if ((!value || value == '0') && self.hasVisual) {
2051
+ dom.addClass(elm, cls);
2052
+ } else {
2053
+ dom.removeClass(elm, cls);
2054
+ }
2055
+
2056
+ return;
2057
+
2058
+ case 'A':
2059
+ if (!dom.getAttrib(elm, 'href', false)) {
2060
+ value = dom.getAttrib(elm, 'name') || elm.id;
2061
+ cls = settings.visual_anchor_class || 'mce-item-anchor';
2062
+
2063
+ if (value && self.hasVisual) {
2064
+ dom.addClass(elm, cls);
2065
+ } else {
2066
+ dom.removeClass(elm, cls);
2067
+ }
2068
+ }
2069
+
2070
+ return;
2071
+ }
2072
+ });
2073
+
2074
+ self.fire('VisualAid', {element: elm, hasVisual: self.hasVisual});
2075
+ },
2076
+
2077
+ /**
2078
+ * Removes the editor from the dom and tinymce collection.
2079
+ *
2080
+ * @method remove
2081
+ */
2082
+ remove: function() {
2083
+ var self = this;
2084
+
2085
+ if (!self.removed) {
2086
+ self.save();
2087
+ self.removed = 1;
2088
+ self.unbindAllNativeEvents();
2089
+
2090
+ // Remove any hidden input
2091
+ if (self.hasHiddenInput) {
2092
+ DOM.remove(self.getElement().nextSibling);
2093
+ }
2094
+
2095
+ if (!self.inline) {
2096
+ // IE 9 has a bug where the selection stops working if you place the
2097
+ // caret inside the editor then remove the iframe
2098
+ if (ie && ie < 10) {
2099
+ self.getDoc().execCommand('SelectAll', false, null);
2100
+ }
2101
+
2102
+ DOM.setStyle(self.id, 'display', self.orgDisplay);
2103
+ self.getBody().onload = null; // Prevent #6816
2104
+ }
2105
+
2106
+ self.fire('remove');
2107
+
2108
+ self.editorManager.remove(self);
2109
+ DOM.remove(self.getContainer());
2110
+ self._selectionOverrides.destroy();
2111
+ self.editorUpload.destroy();
2112
+ self.destroy();
2113
+ }
2114
+ },
2115
+
2116
+ /**
2117
+ * Destroys the editor instance by removing all events, element references or other resources
2118
+ * that could leak memory. This method will be called automatically when the page is unloaded
2119
+ * but you can also call it directly if you know what you are doing.
2120
+ *
2121
+ * @method destroy
2122
+ * @param {Boolean} automatic Optional state if the destroy is an automatic destroy or user called one.
2123
+ */
2124
+ destroy: function(automatic) {
2125
+ var self = this, form;
2126
+
2127
+ // One time is enough
2128
+ if (self.destroyed) {
2129
+ return;
2130
+ }
2131
+
2132
+ // If user manually calls destroy and not remove
2133
+ // Users seems to have logic that calls destroy instead of remove
2134
+ if (!automatic && !self.removed) {
2135
+ self.remove();
2136
+ return;
2137
+ }
2138
+
2139
+ if (!automatic) {
2140
+ self.editorManager.off('beforeunload', self._beforeUnload);
2141
+
2142
+ // Manual destroy
2143
+ if (self.theme && self.theme.destroy) {
2144
+ self.theme.destroy();
2145
+ }
2146
+
2147
+ // Destroy controls, selection and dom
2148
+ self.selection.destroy();
2149
+ self.dom.destroy();
2150
+ }
2151
+
2152
+ form = self.formElement;
2153
+ if (form) {
2154
+ if (form._mceOldSubmit) {
2155
+ form.submit = form._mceOldSubmit;
2156
+ form._mceOldSubmit = null;
2157
+ }
2158
+
2159
+ DOM.unbind(form, 'submit reset', self.formEventDelegate);
2160
+ }
2161
+
2162
+ self.contentAreaContainer = self.formElement = self.container = self.editorContainer = null;
2163
+ self.bodyElement = self.contentDocument = self.contentWindow = null;
2164
+ self.iframeElement = self.targetElm = null;
2165
+
2166
+ if (self.selection) {
2167
+ self.selection = self.selection.win = self.selection.dom = self.selection.dom.doc = null;
2168
+ }
2169
+
2170
+ self.destroyed = 1;
2171
+ },
2172
+
2173
+ /**
2174
+ * Uploads all data uri/blob uri images in the editor contents to server.
2175
+ *
2176
+ * @method uploadImages
2177
+ * @param {function} callback Optional callback with images and status for each image.
2178
+ * @return {tinymce.util.Promise} Promise instance.
2179
+ */
2180
+ uploadImages: function(callback) {
2181
+ return this.editorUpload.uploadImages(callback);
2182
+ },
2183
+
2184
+ // Internal functions
2185
+
2186
+ _scanForImages: function() {
2187
+ return this.editorUpload.scanForImages();
2188
+ },
2189
+
2190
+ _refreshContentEditable: function() {
2191
+ var self = this, body, parent;
2192
+
2193
+ // Check if the editor was hidden and the re-initialize contentEditable mode by removing and adding the body again
2194
+ if (self._isHidden()) {
2195
+ body = self.getBody();
2196
+ parent = body.parentNode;
2197
+
2198
+ parent.removeChild(body);
2199
+ parent.appendChild(body);
2200
+
2201
+ body.focus();
2202
+ }
2203
+ },
2204
+
2205
+ _isHidden: function() {
2206
+ var sel;
2207
+
2208
+ if (!isGecko) {
2209
+ return 0;
2210
+ }
2211
+
2212
+ // Weird, wheres that cursor selection?
2213
+ sel = this.selection.getSel();
2214
+ return (!sel || !sel.rangeCount || sel.rangeCount === 0);
2215
+ }
2216
+ };
2217
+
2218
+ extend(Editor.prototype, EditorObservable);
2219
+
2220
+ return Editor;
2221
+ });