spiderfw 0.6.38 → 0.6.39

Sign up to get free protection for your applications and to get access to all the features.
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,36 @@
1
+ /**
2
+ * Utils.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
+ /**
12
+ * Various utility functions.
13
+ *
14
+ * @class tinymce.tableplugin.Utils
15
+ * @private
16
+ */
17
+ define("tinymce/tableplugin/Utils", [
18
+ "tinymce/Env"
19
+ ], function(Env) {
20
+ function getSpanVal(td, name) {
21
+ return parseInt(td.getAttribute(name) || 1, 10);
22
+ }
23
+
24
+ function paddCell(cell) {
25
+ if (!Env.ie || Env.ie > 9) {
26
+ if (!cell.hasChildNodes()) {
27
+ cell.innerHTML = '<br data-mce-bogus="1" />';
28
+ }
29
+ }
30
+ }
31
+
32
+ return {
33
+ getSpanVal: getSpanVal,
34
+ paddCell: paddCell
35
+ };
36
+ });
@@ -0,0 +1,142 @@
1
+ /**
2
+ * Inline development version. Only to be used while developing since it uses document.write to load scripts.
3
+ */
4
+
5
+ /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
6
+ /*globals $code */
7
+
8
+ (function(exports) {
9
+ "use strict";
10
+
11
+ var html = "", baseDir;
12
+ var modules = {}, exposedModules = [], moduleCount = 0;
13
+
14
+ var scripts = document.getElementsByTagName('script');
15
+ for (var i = 0; i < scripts.length; i++) {
16
+ var src = scripts[i].src;
17
+
18
+ if (src.indexOf('/plugin.dev.js') != -1) {
19
+ baseDir = src.substring(0, src.lastIndexOf('/'));
20
+ }
21
+ }
22
+
23
+ function require(ids, callback) {
24
+ var module, defs = [];
25
+
26
+ for (var i = 0; i < ids.length; ++i) {
27
+ module = modules[ids[i]] || resolve(ids[i]);
28
+ if (!module) {
29
+ throw 'module definition dependecy not found: ' + ids[i];
30
+ }
31
+
32
+ defs.push(module);
33
+ }
34
+
35
+ callback.apply(null, defs);
36
+ }
37
+
38
+ function resolve(id) {
39
+ if (exports.privateModules && id in exports.privateModules) {
40
+ return;
41
+ }
42
+
43
+ var target = exports;
44
+ var fragments = id.split(/[.\/]/);
45
+
46
+ for (var fi = 0; fi < fragments.length; ++fi) {
47
+ if (!target[fragments[fi]]) {
48
+ return;
49
+ }
50
+
51
+ target = target[fragments[fi]];
52
+ }
53
+
54
+ return target;
55
+ }
56
+
57
+ function register(id) {
58
+ var target = exports;
59
+ var fragments = id.split(/[.\/]/);
60
+
61
+ for (var fi = 0; fi < fragments.length - 1; ++fi) {
62
+ if (target[fragments[fi]] === undefined) {
63
+ target[fragments[fi]] = {};
64
+ }
65
+
66
+ target = target[fragments[fi]];
67
+ }
68
+
69
+ target[fragments[fragments.length - 1]] = modules[id];
70
+ }
71
+
72
+ function define(id, dependencies, definition) {
73
+ var privateModules, i;
74
+
75
+ if (typeof id !== 'string') {
76
+ throw 'invalid module definition, module id must be defined and be a string';
77
+ }
78
+
79
+ if (dependencies === undefined) {
80
+ throw 'invalid module definition, dependencies must be specified';
81
+ }
82
+
83
+ if (definition === undefined) {
84
+ throw 'invalid module definition, definition function must be specified';
85
+ }
86
+
87
+ require(dependencies, function() {
88
+ modules[id] = definition.apply(null, arguments);
89
+ });
90
+
91
+ if (--moduleCount === 0) {
92
+ for (i = 0; i < exposedModules.length; i++) {
93
+ register(exposedModules[i]);
94
+ }
95
+ }
96
+
97
+ // Expose private modules for unit tests
98
+ if (exports.AMDLC_TESTS) {
99
+ privateModules = exports.privateModules || {};
100
+
101
+ for (id in modules) {
102
+ privateModules[id] = modules[id];
103
+ }
104
+
105
+ for (i = 0; i < exposedModules.length; i++) {
106
+ delete privateModules[exposedModules[i]];
107
+ }
108
+
109
+ exports.privateModules = privateModules;
110
+ }
111
+
112
+ }
113
+
114
+ function expose(ids) {
115
+ exposedModules = ids;
116
+ }
117
+
118
+ function writeScripts() {
119
+ document.write(html);
120
+ }
121
+
122
+ function load(path) {
123
+ html += '<script type="text/javascript" src="' + baseDir + '/' + path + '"></script>\n';
124
+ moduleCount++;
125
+ }
126
+
127
+ // Expose globally
128
+ exports.define = define;
129
+ exports.require = require;
130
+
131
+ load('classes/Utils.js');
132
+ load('classes/TableGrid.js');
133
+ load('classes/Quirks.js');
134
+ load('classes/CellSelection.js');
135
+ load('classes/Dialogs.js');
136
+ load('classes/ResizeBars.js');
137
+ load('classes/Plugin.js');
138
+
139
+ writeScripts();
140
+ })(this);
141
+
142
+ // $hash: 8d12904abe82bdf2c2a32cb4509ee238
@@ -0,0 +1,4106 @@
1
+ /**
2
+ * Compiled inline version. (Library mode)
3
+ */
4
+
5
+ /*jshint smarttabs:true, undef:true, latedef:true, curly:true, bitwise:true, camelcase:true */
6
+ /*globals $code */
7
+
8
+ (function(exports, undefined) {
9
+ "use strict";
10
+
11
+ var modules = {};
12
+
13
+ function require(ids, callback) {
14
+ var module, defs = [];
15
+
16
+ for (var i = 0; i < ids.length; ++i) {
17
+ module = modules[ids[i]] || resolve(ids[i]);
18
+ if (!module) {
19
+ throw 'module definition dependecy not found: ' + ids[i];
20
+ }
21
+
22
+ defs.push(module);
23
+ }
24
+
25
+ callback.apply(null, defs);
26
+ }
27
+
28
+ function define(id, dependencies, definition) {
29
+ if (typeof id !== 'string') {
30
+ throw 'invalid module definition, module id must be defined and be a string';
31
+ }
32
+
33
+ if (dependencies === undefined) {
34
+ throw 'invalid module definition, dependencies must be specified';
35
+ }
36
+
37
+ if (definition === undefined) {
38
+ throw 'invalid module definition, definition function must be specified';
39
+ }
40
+
41
+ require(dependencies, function() {
42
+ modules[id] = definition.apply(null, arguments);
43
+ });
44
+ }
45
+
46
+ function defined(id) {
47
+ return !!modules[id];
48
+ }
49
+
50
+ function resolve(id) {
51
+ var target = exports;
52
+ var fragments = id.split(/[.\/]/);
53
+
54
+ for (var fi = 0; fi < fragments.length; ++fi) {
55
+ if (!target[fragments[fi]]) {
56
+ return;
57
+ }
58
+
59
+ target = target[fragments[fi]];
60
+ }
61
+
62
+ return target;
63
+ }
64
+
65
+ function expose(ids) {
66
+ var i, target, id, fragments, privateModules;
67
+
68
+ for (i = 0; i < ids.length; i++) {
69
+ target = exports;
70
+ id = ids[i];
71
+ fragments = id.split(/[.\/]/);
72
+
73
+ for (var fi = 0; fi < fragments.length - 1; ++fi) {
74
+ if (target[fragments[fi]] === undefined) {
75
+ target[fragments[fi]] = {};
76
+ }
77
+
78
+ target = target[fragments[fi]];
79
+ }
80
+
81
+ target[fragments[fragments.length - 1]] = modules[id];
82
+ }
83
+
84
+ // Expose private modules for unit tests
85
+ if (exports.AMDLC_TESTS) {
86
+ privateModules = exports.privateModules || {};
87
+
88
+ for (id in modules) {
89
+ privateModules[id] = modules[id];
90
+ }
91
+
92
+ for (i = 0; i < ids.length; i++) {
93
+ delete privateModules[ids[i]];
94
+ }
95
+
96
+ exports.privateModules = privateModules;
97
+ }
98
+ }
99
+
100
+ // Included from: js/tinymce/plugins/table/classes/Utils.js
101
+
102
+ /**
103
+ * Utils.js
104
+ *
105
+ * Released under LGPL License.
106
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
107
+ *
108
+ * License: http://www.tinymce.com/license
109
+ * Contributing: http://www.tinymce.com/contributing
110
+ */
111
+
112
+ /**
113
+ * Various utility functions.
114
+ *
115
+ * @class tinymce.tableplugin.Utils
116
+ * @private
117
+ */
118
+ define("tinymce/tableplugin/Utils", [
119
+ "tinymce/Env"
120
+ ], function(Env) {
121
+ function getSpanVal(td, name) {
122
+ return parseInt(td.getAttribute(name) || 1, 10);
123
+ }
124
+
125
+ function paddCell(cell) {
126
+ if (!Env.ie || Env.ie > 9) {
127
+ if (!cell.hasChildNodes()) {
128
+ cell.innerHTML = '<br data-mce-bogus="1" />';
129
+ }
130
+ }
131
+ }
132
+
133
+ return {
134
+ getSpanVal: getSpanVal,
135
+ paddCell: paddCell
136
+ };
137
+ });
138
+
139
+ // Included from: js/tinymce/plugins/table/classes/TableGrid.js
140
+
141
+ /**
142
+ * TableGrid.js
143
+ *
144
+ * Released under LGPL License.
145
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
146
+ *
147
+ * License: http://www.tinymce.com/license
148
+ * Contributing: http://www.tinymce.com/contributing
149
+ */
150
+
151
+ /**
152
+ * This class creates a grid out of a table element. This
153
+ * makes it a whole lot easier to handle complex tables with
154
+ * col/row spans.
155
+ *
156
+ * @class tinymce.tableplugin.TableGrid
157
+ * @private
158
+ */
159
+ define("tinymce/tableplugin/TableGrid", [
160
+ "tinymce/util/Tools",
161
+ "tinymce/Env",
162
+ "tinymce/tableplugin/Utils"
163
+ ], function(Tools, Env, Utils) {
164
+ var each = Tools.each, getSpanVal = Utils.getSpanVal;
165
+
166
+ return function(editor, table, selectedCell) {
167
+ var grid, gridWidth, startPos, endPos, selection = editor.selection, dom = selection.dom;
168
+
169
+ function removeCellSelection() {
170
+ editor.$('td[data-mce-selected],th[data-mce-selected]').removeAttr('data-mce-selected');
171
+ }
172
+
173
+ function isEditorBody(node) {
174
+ return node === editor.getBody();
175
+ }
176
+
177
+ function getChildrenByName(node, names) {
178
+ if (!node) {
179
+ return [];
180
+ }
181
+
182
+ names = Tools.map(names.split(','), function(name) {
183
+ return name.toLowerCase();
184
+ });
185
+
186
+ return Tools.grep(node.childNodes, function(node) {
187
+ return Tools.inArray(names, node.nodeName.toLowerCase()) !== -1;
188
+ });
189
+ }
190
+
191
+ function buildGrid() {
192
+ var startY = 0;
193
+
194
+ grid = [];
195
+ gridWidth = 0;
196
+
197
+ each(['thead', 'tbody', 'tfoot'], function(part) {
198
+ var partElm = getChildrenByName(table, part)[0];
199
+ var rows = getChildrenByName(partElm, 'tr');
200
+
201
+ each(rows, function(tr, y) {
202
+ y += startY;
203
+
204
+ each(getChildrenByName(tr, 'td,th'), function(td, x) {
205
+ var x2, y2, rowspan, colspan;
206
+
207
+ // Skip over existing cells produced by rowspan
208
+ if (grid[y]) {
209
+ while (grid[y][x]) {
210
+ x++;
211
+ }
212
+ }
213
+
214
+ // Get col/rowspan from cell
215
+ rowspan = getSpanVal(td, 'rowspan');
216
+ colspan = getSpanVal(td, 'colspan');
217
+
218
+ // Fill out rowspan/colspan right and down
219
+ for (y2 = y; y2 < y + rowspan; y2++) {
220
+ if (!grid[y2]) {
221
+ grid[y2] = [];
222
+ }
223
+
224
+ for (x2 = x; x2 < x + colspan; x2++) {
225
+ grid[y2][x2] = {
226
+ part: part,
227
+ real: y2 == y && x2 == x,
228
+ elm: td,
229
+ rowspan: rowspan,
230
+ colspan: colspan
231
+ };
232
+ }
233
+ }
234
+
235
+ gridWidth = Math.max(gridWidth, x + 1);
236
+ });
237
+ });
238
+
239
+ startY += rows.length;
240
+ });
241
+ }
242
+
243
+ function fireNewRow(node) {
244
+ editor.fire('newrow', {
245
+ node: node
246
+ });
247
+
248
+ return node;
249
+ }
250
+
251
+ function fireNewCell(node) {
252
+ editor.fire('newcell', {
253
+ node: node
254
+ });
255
+
256
+ return node;
257
+ }
258
+
259
+ function cloneNode(node, children) {
260
+ node = node.cloneNode(children);
261
+ node.removeAttribute('id');
262
+
263
+ return node;
264
+ }
265
+
266
+ function getCell(x, y) {
267
+ var row;
268
+
269
+ row = grid[y];
270
+ if (row) {
271
+ return row[x];
272
+ }
273
+ }
274
+
275
+ function setSpanVal(td, name, val) {
276
+ if (td) {
277
+ val = parseInt(val, 10);
278
+
279
+ if (val === 1) {
280
+ td.removeAttribute(name, 1);
281
+ } else {
282
+ td.setAttribute(name, val, 1);
283
+ }
284
+ }
285
+ }
286
+
287
+ function isCellSelected(cell) {
288
+ return cell && (!!dom.getAttrib(cell.elm, 'data-mce-selected') || cell == selectedCell);
289
+ }
290
+
291
+ function getSelectedRows() {
292
+ var rows = [];
293
+
294
+ each(table.rows, function(row) {
295
+ each(row.cells, function(cell) {
296
+ if (dom.getAttrib(cell, 'data-mce-selected') || (selectedCell && cell == selectedCell.elm)) {
297
+ rows.push(row);
298
+ return false;
299
+ }
300
+ });
301
+ });
302
+
303
+ return rows;
304
+ }
305
+
306
+ function deleteTable() {
307
+ var rng = dom.createRng();
308
+
309
+ if (isEditorBody(table)) {
310
+ return;
311
+ }
312
+
313
+ rng.setStartAfter(table);
314
+ rng.setEndAfter(table);
315
+
316
+ selection.setRng(rng);
317
+
318
+ dom.remove(table);
319
+ }
320
+
321
+ function cloneCell(cell) {
322
+ var formatNode, cloneFormats = {};
323
+
324
+ if (editor.settings.table_clone_elements !== false) {
325
+ cloneFormats = Tools.makeMap(
326
+ (editor.settings.table_clone_elements || 'strong em b i span font h1 h2 h3 h4 h5 h6 p div').toUpperCase(),
327
+ /[ ,]/
328
+ );
329
+ }
330
+
331
+ // Clone formats
332
+ Tools.walk(cell, function(node) {
333
+ var curNode;
334
+
335
+ if (node.nodeType == 3) {
336
+ each(dom.getParents(node.parentNode, null, cell).reverse(), function(node) {
337
+ if (!cloneFormats[node.nodeName]) {
338
+ return;
339
+ }
340
+
341
+ node = cloneNode(node, false);
342
+
343
+ if (!formatNode) {
344
+ formatNode = curNode = node;
345
+ } else if (curNode) {
346
+ curNode.appendChild(node);
347
+ }
348
+
349
+ curNode = node;
350
+ });
351
+
352
+ // Add something to the inner node
353
+ if (curNode) {
354
+ curNode.innerHTML = Env.ie && Env.ie < 10 ? '&nbsp;' : '<br data-mce-bogus="1" />';
355
+ }
356
+
357
+ return false;
358
+ }
359
+ }, 'childNodes');
360
+
361
+ cell = cloneNode(cell, false);
362
+ fireNewCell(cell);
363
+
364
+ setSpanVal(cell, 'rowSpan', 1);
365
+ setSpanVal(cell, 'colSpan', 1);
366
+
367
+ if (formatNode) {
368
+ cell.appendChild(formatNode);
369
+ } else {
370
+ Utils.paddCell(cell);
371
+ }
372
+
373
+ return cell;
374
+ }
375
+
376
+ function cleanup() {
377
+ var rng = dom.createRng(), row;
378
+
379
+ // Empty rows
380
+ each(dom.select('tr', table), function(tr) {
381
+ if (tr.cells.length === 0) {
382
+ dom.remove(tr);
383
+ }
384
+ });
385
+
386
+ // Empty table
387
+ if (dom.select('tr', table).length === 0) {
388
+ rng.setStartBefore(table);
389
+ rng.setEndBefore(table);
390
+ selection.setRng(rng);
391
+ dom.remove(table);
392
+ return;
393
+ }
394
+
395
+ // Empty header/body/footer
396
+ each(dom.select('thead,tbody,tfoot', table), function(part) {
397
+ if (part.rows.length === 0) {
398
+ dom.remove(part);
399
+ }
400
+ });
401
+
402
+ // Restore selection to start position if it still exists
403
+ buildGrid();
404
+
405
+ // If we have a valid startPos object
406
+ if (startPos) {
407
+ // Restore the selection to the closest table position
408
+ row = grid[Math.min(grid.length - 1, startPos.y)];
409
+ if (row) {
410
+ selection.select(row[Math.min(row.length - 1, startPos.x)].elm, true);
411
+ selection.collapse(true);
412
+ }
413
+ }
414
+ }
415
+
416
+ function fillLeftDown(x, y, rows, cols) {
417
+ var tr, x2, r, c, cell;
418
+
419
+ tr = grid[y][x].elm.parentNode;
420
+ for (r = 1; r <= rows; r++) {
421
+ tr = dom.getNext(tr, 'tr');
422
+
423
+ if (tr) {
424
+ // Loop left to find real cell
425
+ for (x2 = x; x2 >= 0; x2--) {
426
+ cell = grid[y + r][x2].elm;
427
+
428
+ if (cell.parentNode == tr) {
429
+ // Append clones after
430
+ for (c = 1; c <= cols; c++) {
431
+ dom.insertAfter(cloneCell(cell), cell);
432
+ }
433
+
434
+ break;
435
+ }
436
+ }
437
+
438
+ if (x2 == -1) {
439
+ // Insert nodes before first cell
440
+ for (c = 1; c <= cols; c++) {
441
+ tr.insertBefore(cloneCell(tr.cells[0]), tr.cells[0]);
442
+ }
443
+ }
444
+ }
445
+ }
446
+ }
447
+
448
+ function split() {
449
+ each(grid, function(row, y) {
450
+ each(row, function(cell, x) {
451
+ var colSpan, rowSpan, i;
452
+
453
+ if (isCellSelected(cell)) {
454
+ cell = cell.elm;
455
+ colSpan = getSpanVal(cell, 'colspan');
456
+ rowSpan = getSpanVal(cell, 'rowspan');
457
+
458
+ if (colSpan > 1 || rowSpan > 1) {
459
+ setSpanVal(cell, 'rowSpan', 1);
460
+ setSpanVal(cell, 'colSpan', 1);
461
+
462
+ // Insert cells right
463
+ for (i = 0; i < colSpan - 1; i++) {
464
+ dom.insertAfter(cloneCell(cell), cell);
465
+ }
466
+
467
+ fillLeftDown(x, y, rowSpan - 1, colSpan);
468
+ }
469
+ }
470
+ });
471
+ });
472
+ }
473
+
474
+ function merge(cell, cols, rows) {
475
+ var pos, startX, startY, endX, endY, x, y, startCell, endCell, children, count;
476
+
477
+ // Use specified cell and cols/rows
478
+ if (cell) {
479
+ pos = getPos(cell);
480
+ startX = pos.x;
481
+ startY = pos.y;
482
+ endX = startX + (cols - 1);
483
+ endY = startY + (rows - 1);
484
+ } else {
485
+ startPos = endPos = null;
486
+
487
+ // Calculate start/end pos by checking for selected cells in grid works better with context menu
488
+ each(grid, function(row, y) {
489
+ each(row, function(cell, x) {
490
+ if (isCellSelected(cell)) {
491
+ if (!startPos) {
492
+ startPos = {x: x, y: y};
493
+ }
494
+
495
+ endPos = {x: x, y: y};
496
+ }
497
+ });
498
+ });
499
+
500
+ // Use selection, but make sure startPos is valid before accessing
501
+ if (startPos) {
502
+ startX = startPos.x;
503
+ startY = startPos.y;
504
+ endX = endPos.x;
505
+ endY = endPos.y;
506
+ }
507
+ }
508
+
509
+ // Find start/end cells
510
+ startCell = getCell(startX, startY);
511
+ endCell = getCell(endX, endY);
512
+
513
+ // Check if the cells exists and if they are of the same part for example tbody = tbody
514
+ if (startCell && endCell && startCell.part == endCell.part) {
515
+ // Split and rebuild grid
516
+ split();
517
+ buildGrid();
518
+
519
+ // Set row/col span to start cell
520
+ startCell = getCell(startX, startY).elm;
521
+ setSpanVal(startCell, 'colSpan', (endX - startX) + 1);
522
+ setSpanVal(startCell, 'rowSpan', (endY - startY) + 1);
523
+
524
+ // Remove other cells and add it's contents to the start cell
525
+ for (y = startY; y <= endY; y++) {
526
+ for (x = startX; x <= endX; x++) {
527
+ if (!grid[y] || !grid[y][x]) {
528
+ continue;
529
+ }
530
+
531
+ cell = grid[y][x].elm;
532
+
533
+ /*jshint loopfunc:true */
534
+ /*eslint no-loop-func:0 */
535
+ if (cell != startCell) {
536
+ // Move children to startCell
537
+ children = Tools.grep(cell.childNodes);
538
+ each(children, function(node) {
539
+ startCell.appendChild(node);
540
+ });
541
+
542
+ // Remove bogus nodes if there is children in the target cell
543
+ if (children.length) {
544
+ children = Tools.grep(startCell.childNodes);
545
+ count = 0;
546
+ each(children, function(node) {
547
+ if (node.nodeName == 'BR' && count++ < children.length - 1) {
548
+ startCell.removeChild(node);
549
+ }
550
+ });
551
+ }
552
+
553
+ dom.remove(cell);
554
+ }
555
+ }
556
+ }
557
+
558
+ // Remove empty rows etc and restore caret location
559
+ cleanup();
560
+ }
561
+ }
562
+
563
+ function insertRow(before) {
564
+ var posY, cell, lastCell, x, rowElm, newRow, newCell, otherCell, rowSpan;
565
+
566
+ // Find first/last row
567
+ each(grid, function(row, y) {
568
+ each(row, function(cell) {
569
+ if (isCellSelected(cell)) {
570
+ cell = cell.elm;
571
+ rowElm = cell.parentNode;
572
+ newRow = fireNewRow(cloneNode(rowElm, false));
573
+ posY = y;
574
+
575
+ if (before) {
576
+ return false;
577
+ }
578
+ }
579
+ });
580
+
581
+ if (before) {
582
+ return !posY;
583
+ }
584
+ });
585
+
586
+ // If posY is undefined there is nothing for us to do here...just return to avoid crashing below
587
+ if (posY === undefined) {
588
+ return;
589
+ }
590
+
591
+ for (x = 0; x < grid[0].length; x++) {
592
+ // Cell not found could be because of an invalid table structure
593
+ if (!grid[posY][x]) {
594
+ continue;
595
+ }
596
+
597
+ cell = grid[posY][x].elm;
598
+
599
+ if (cell != lastCell) {
600
+ if (!before) {
601
+ rowSpan = getSpanVal(cell, 'rowspan');
602
+ if (rowSpan > 1) {
603
+ setSpanVal(cell, 'rowSpan', rowSpan + 1);
604
+ continue;
605
+ }
606
+ } else {
607
+ // Check if cell above can be expanded
608
+ if (posY > 0 && grid[posY - 1][x]) {
609
+ otherCell = grid[posY - 1][x].elm;
610
+ rowSpan = getSpanVal(otherCell, 'rowSpan');
611
+ if (rowSpan > 1) {
612
+ setSpanVal(otherCell, 'rowSpan', rowSpan + 1);
613
+ continue;
614
+ }
615
+ }
616
+ }
617
+
618
+ // Insert new cell into new row
619
+ newCell = cloneCell(cell);
620
+ setSpanVal(newCell, 'colSpan', cell.colSpan);
621
+
622
+ newRow.appendChild(newCell);
623
+
624
+ lastCell = cell;
625
+ }
626
+ }
627
+
628
+ if (newRow.hasChildNodes()) {
629
+ if (!before) {
630
+ dom.insertAfter(newRow, rowElm);
631
+ } else {
632
+ rowElm.parentNode.insertBefore(newRow, rowElm);
633
+ }
634
+ }
635
+ }
636
+
637
+ function insertCol(before) {
638
+ var posX, lastCell;
639
+
640
+ // Find first/last column
641
+ each(grid, function(row) {
642
+ each(row, function(cell, x) {
643
+ if (isCellSelected(cell)) {
644
+ posX = x;
645
+
646
+ if (before) {
647
+ return false;
648
+ }
649
+ }
650
+ });
651
+
652
+ if (before) {
653
+ return !posX;
654
+ }
655
+ });
656
+
657
+ each(grid, function(row, y) {
658
+ var cell, rowSpan, colSpan;
659
+
660
+ if (!row[posX]) {
661
+ return;
662
+ }
663
+
664
+ cell = row[posX].elm;
665
+ if (cell != lastCell) {
666
+ colSpan = getSpanVal(cell, 'colspan');
667
+ rowSpan = getSpanVal(cell, 'rowspan');
668
+
669
+ if (colSpan == 1) {
670
+ if (!before) {
671
+ dom.insertAfter(cloneCell(cell), cell);
672
+ fillLeftDown(posX, y, rowSpan - 1, colSpan);
673
+ } else {
674
+ cell.parentNode.insertBefore(cloneCell(cell), cell);
675
+ fillLeftDown(posX, y, rowSpan - 1, colSpan);
676
+ }
677
+ } else {
678
+ setSpanVal(cell, 'colSpan', cell.colSpan + 1);
679
+ }
680
+
681
+ lastCell = cell;
682
+ }
683
+ });
684
+ }
685
+
686
+ function getSelectedCells(grid) {
687
+ return Tools.grep(getAllCells(grid), isCellSelected);
688
+ }
689
+
690
+ function getAllCells(grid) {
691
+ var cells = [];
692
+
693
+ each(grid, function(row) {
694
+ each(row, function(cell) {
695
+ cells.push(cell);
696
+ });
697
+ });
698
+
699
+ return cells;
700
+ }
701
+
702
+ function deleteCols() {
703
+ var cols = [];
704
+
705
+ if (isEditorBody(table)) {
706
+ if (grid[0].length == 1) {
707
+ return;
708
+ }
709
+
710
+ if (getSelectedCells(grid).length == getAllCells(grid).length) {
711
+ return;
712
+ }
713
+ }
714
+
715
+ // Get selected column indexes
716
+ each(grid, function(row) {
717
+ each(row, function(cell, x) {
718
+ if (isCellSelected(cell) && Tools.inArray(cols, x) === -1) {
719
+ each(grid, function(row) {
720
+ var cell = row[x].elm, colSpan;
721
+
722
+ colSpan = getSpanVal(cell, 'colSpan');
723
+
724
+ if (colSpan > 1) {
725
+ setSpanVal(cell, 'colSpan', colSpan - 1);
726
+ } else {
727
+ dom.remove(cell);
728
+ }
729
+ });
730
+
731
+ cols.push(x);
732
+ }
733
+ });
734
+ });
735
+
736
+ cleanup();
737
+ }
738
+
739
+ function deleteRows() {
740
+ var rows;
741
+
742
+ function deleteRow(tr) {
743
+ var pos, lastCell;
744
+
745
+ // Move down row spanned cells
746
+ each(tr.cells, function(cell) {
747
+ var rowSpan = getSpanVal(cell, 'rowSpan');
748
+
749
+ if (rowSpan > 1) {
750
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
751
+ pos = getPos(cell);
752
+ fillLeftDown(pos.x, pos.y, 1, 1);
753
+ }
754
+ });
755
+
756
+ // Delete cells
757
+ pos = getPos(tr.cells[0]);
758
+ each(grid[pos.y], function(cell) {
759
+ var rowSpan;
760
+
761
+ cell = cell.elm;
762
+
763
+ if (cell != lastCell) {
764
+ rowSpan = getSpanVal(cell, 'rowSpan');
765
+
766
+ if (rowSpan <= 1) {
767
+ dom.remove(cell);
768
+ } else {
769
+ setSpanVal(cell, 'rowSpan', rowSpan - 1);
770
+ }
771
+
772
+ lastCell = cell;
773
+ }
774
+ });
775
+ }
776
+
777
+ // Get selected rows and move selection out of scope
778
+ rows = getSelectedRows();
779
+
780
+ if (isEditorBody(table) && rows.length == table.rows.length) {
781
+ return;
782
+ }
783
+
784
+ // Delete all selected rows
785
+ each(rows.reverse(), function(tr) {
786
+ deleteRow(tr);
787
+ });
788
+
789
+ cleanup();
790
+ }
791
+
792
+ function cutRows() {
793
+ var rows = getSelectedRows();
794
+
795
+ if (isEditorBody(table) && rows.length == table.rows.length) {
796
+ return;
797
+ }
798
+
799
+ dom.remove(rows);
800
+ cleanup();
801
+
802
+ return rows;
803
+ }
804
+
805
+ function copyRows() {
806
+ var rows = getSelectedRows();
807
+
808
+ each(rows, function(row, i) {
809
+ rows[i] = cloneNode(row, true);
810
+ });
811
+
812
+ return rows;
813
+ }
814
+
815
+ function pasteRows(rows, before) {
816
+ var selectedRows = getSelectedRows(),
817
+ targetRow = selectedRows[before ? 0 : selectedRows.length - 1],
818
+ targetCellCount = targetRow.cells.length;
819
+
820
+ // Nothing to paste
821
+ if (!rows) {
822
+ return;
823
+ }
824
+
825
+ // Calc target cell count
826
+ each(grid, function(row) {
827
+ var match;
828
+
829
+ targetCellCount = 0;
830
+ each(row, function(cell) {
831
+ if (cell.real) {
832
+ targetCellCount += cell.colspan;
833
+ }
834
+
835
+ if (cell.elm.parentNode == targetRow) {
836
+ match = 1;
837
+ }
838
+ });
839
+
840
+ if (match) {
841
+ return false;
842
+ }
843
+ });
844
+
845
+ if (!before) {
846
+ rows.reverse();
847
+ }
848
+
849
+ each(rows, function(row) {
850
+ var i, cellCount = row.cells.length, cell;
851
+
852
+ fireNewRow(row);
853
+
854
+ // Remove col/rowspans
855
+ for (i = 0; i < cellCount; i++) {
856
+ cell = row.cells[i];
857
+
858
+ fireNewCell(cell);
859
+ setSpanVal(cell, 'colSpan', 1);
860
+ setSpanVal(cell, 'rowSpan', 1);
861
+ }
862
+
863
+ // Needs more cells
864
+ for (i = cellCount; i < targetCellCount; i++) {
865
+ row.appendChild(fireNewCell(cloneCell(row.cells[cellCount - 1])));
866
+ }
867
+
868
+ // Needs less cells
869
+ for (i = targetCellCount; i < cellCount; i++) {
870
+ dom.remove(row.cells[i]);
871
+ }
872
+
873
+ // Add before/after
874
+ if (before) {
875
+ targetRow.parentNode.insertBefore(row, targetRow);
876
+ } else {
877
+ dom.insertAfter(row, targetRow);
878
+ }
879
+ });
880
+
881
+ removeCellSelection();
882
+ }
883
+
884
+ function getPos(target) {
885
+ var pos;
886
+
887
+ each(grid, function(row, y) {
888
+ each(row, function(cell, x) {
889
+ if (cell.elm == target) {
890
+ pos = {x: x, y: y};
891
+ return false;
892
+ }
893
+ });
894
+
895
+ return !pos;
896
+ });
897
+
898
+ return pos;
899
+ }
900
+
901
+ function setStartCell(cell) {
902
+ startPos = getPos(cell);
903
+ }
904
+
905
+ function findEndPos() {
906
+ var maxX, maxY;
907
+
908
+ maxX = maxY = 0;
909
+
910
+ each(grid, function(row, y) {
911
+ each(row, function(cell, x) {
912
+ var colSpan, rowSpan;
913
+
914
+ if (isCellSelected(cell)) {
915
+ cell = grid[y][x];
916
+
917
+ if (x > maxX) {
918
+ maxX = x;
919
+ }
920
+
921
+ if (y > maxY) {
922
+ maxY = y;
923
+ }
924
+
925
+ if (cell.real) {
926
+ colSpan = cell.colspan - 1;
927
+ rowSpan = cell.rowspan - 1;
928
+
929
+ if (colSpan) {
930
+ if (x + colSpan > maxX) {
931
+ maxX = x + colSpan;
932
+ }
933
+ }
934
+
935
+ if (rowSpan) {
936
+ if (y + rowSpan > maxY) {
937
+ maxY = y + rowSpan;
938
+ }
939
+ }
940
+ }
941
+ }
942
+ });
943
+ });
944
+
945
+ return {x: maxX, y: maxY};
946
+ }
947
+
948
+ function setEndCell(cell) {
949
+ var startX, startY, endX, endY, maxX, maxY, colSpan, rowSpan, x, y;
950
+
951
+ endPos = getPos(cell);
952
+
953
+ if (startPos && endPos) {
954
+ // Get start/end positions
955
+ startX = Math.min(startPos.x, endPos.x);
956
+ startY = Math.min(startPos.y, endPos.y);
957
+ endX = Math.max(startPos.x, endPos.x);
958
+ endY = Math.max(startPos.y, endPos.y);
959
+
960
+ // Expand end position to include spans
961
+ maxX = endX;
962
+ maxY = endY;
963
+
964
+ // Expand startX
965
+ for (y = startY; y <= maxY; y++) {
966
+ cell = grid[y][startX];
967
+
968
+ if (!cell.real) {
969
+ if (startX - (cell.colspan - 1) < startX) {
970
+ startX -= cell.colspan - 1;
971
+ }
972
+ }
973
+ }
974
+
975
+ // Expand startY
976
+ for (x = startX; x <= maxX; x++) {
977
+ cell = grid[startY][x];
978
+
979
+ if (!cell.real) {
980
+ if (startY - (cell.rowspan - 1) < startY) {
981
+ startY -= cell.rowspan - 1;
982
+ }
983
+ }
984
+ }
985
+
986
+ // Find max X, Y
987
+ for (y = startY; y <= endY; y++) {
988
+ for (x = startX; x <= endX; x++) {
989
+ cell = grid[y][x];
990
+
991
+ if (cell.real) {
992
+ colSpan = cell.colspan - 1;
993
+ rowSpan = cell.rowspan - 1;
994
+
995
+ if (colSpan) {
996
+ if (x + colSpan > maxX) {
997
+ maxX = x + colSpan;
998
+ }
999
+ }
1000
+
1001
+ if (rowSpan) {
1002
+ if (y + rowSpan > maxY) {
1003
+ maxY = y + rowSpan;
1004
+ }
1005
+ }
1006
+ }
1007
+ }
1008
+ }
1009
+
1010
+ removeCellSelection();
1011
+
1012
+ // Add new selection
1013
+ for (y = startY; y <= maxY; y++) {
1014
+ for (x = startX; x <= maxX; x++) {
1015
+ if (grid[y][x]) {
1016
+ dom.setAttrib(grid[y][x].elm, 'data-mce-selected', '1');
1017
+ }
1018
+ }
1019
+ }
1020
+ }
1021
+ }
1022
+
1023
+ function moveRelIdx(cellElm, delta) {
1024
+ var pos, index, cell;
1025
+
1026
+ pos = getPos(cellElm);
1027
+ index = pos.y * gridWidth + pos.x;
1028
+
1029
+ do {
1030
+ index += delta;
1031
+ cell = getCell(index % gridWidth, Math.floor(index / gridWidth));
1032
+
1033
+ if (!cell) {
1034
+ break;
1035
+ }
1036
+
1037
+ if (cell.elm != cellElm) {
1038
+ selection.select(cell.elm, true);
1039
+
1040
+ if (dom.isEmpty(cell.elm)) {
1041
+ selection.collapse(true);
1042
+ }
1043
+
1044
+ return true;
1045
+ }
1046
+ } while (cell.elm == cellElm);
1047
+
1048
+ return false;
1049
+ }
1050
+
1051
+ table = table || dom.getParent(selection.getStart(true), 'table');
1052
+
1053
+ buildGrid();
1054
+
1055
+ selectedCell = selectedCell || dom.getParent(selection.getStart(true), 'th,td');
1056
+
1057
+ if (selectedCell) {
1058
+ startPos = getPos(selectedCell);
1059
+ endPos = findEndPos();
1060
+ selectedCell = getCell(startPos.x, startPos.y);
1061
+ }
1062
+
1063
+ Tools.extend(this, {
1064
+ deleteTable: deleteTable,
1065
+ split: split,
1066
+ merge: merge,
1067
+ insertRow: insertRow,
1068
+ insertCol: insertCol,
1069
+ deleteCols: deleteCols,
1070
+ deleteRows: deleteRows,
1071
+ cutRows: cutRows,
1072
+ copyRows: copyRows,
1073
+ pasteRows: pasteRows,
1074
+ getPos: getPos,
1075
+ setStartCell: setStartCell,
1076
+ setEndCell: setEndCell,
1077
+ moveRelIdx: moveRelIdx,
1078
+ refresh: buildGrid
1079
+ });
1080
+ };
1081
+ });
1082
+
1083
+ // Included from: js/tinymce/plugins/table/classes/Quirks.js
1084
+
1085
+ /**
1086
+ * Quirks.js
1087
+ *
1088
+ * Released under LGPL License.
1089
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
1090
+ *
1091
+ * License: http://www.tinymce.com/license
1092
+ * Contributing: http://www.tinymce.com/contributing
1093
+ */
1094
+
1095
+ /**
1096
+ * This class includes fixes for various browser quirks.
1097
+ *
1098
+ * @class tinymce.tableplugin.Quirks
1099
+ * @private
1100
+ */
1101
+ define("tinymce/tableplugin/Quirks", [
1102
+ "tinymce/util/VK",
1103
+ "tinymce/util/Delay",
1104
+ "tinymce/Env",
1105
+ "tinymce/util/Tools",
1106
+ "tinymce/tableplugin/Utils"
1107
+ ], function(VK, Delay, Env, Tools, Utils) {
1108
+ var each = Tools.each, getSpanVal = Utils.getSpanVal;
1109
+
1110
+ return function(editor) {
1111
+ /**
1112
+ * Fixed caret movement around tables on WebKit.
1113
+ */
1114
+ function moveWebKitSelection() {
1115
+ function eventHandler(e) {
1116
+ var key = e.keyCode;
1117
+
1118
+ function handle(upBool, sourceNode) {
1119
+ var siblingDirection = upBool ? 'previousSibling' : 'nextSibling';
1120
+ var currentRow = editor.dom.getParent(sourceNode, 'tr');
1121
+ var siblingRow = currentRow[siblingDirection];
1122
+
1123
+ if (siblingRow) {
1124
+ moveCursorToRow(editor, sourceNode, siblingRow, upBool);
1125
+ e.preventDefault();
1126
+ return true;
1127
+ }
1128
+
1129
+ var tableNode = editor.dom.getParent(currentRow, 'table');
1130
+ var middleNode = currentRow.parentNode;
1131
+ var parentNodeName = middleNode.nodeName.toLowerCase();
1132
+ if (parentNodeName === 'tbody' || parentNodeName === (upBool ? 'tfoot' : 'thead')) {
1133
+ var targetParent = getTargetParent(upBool, tableNode, middleNode, 'tbody');
1134
+ if (targetParent !== null) {
1135
+ return moveToRowInTarget(upBool, targetParent, sourceNode);
1136
+ }
1137
+ }
1138
+
1139
+ return escapeTable(upBool, currentRow, siblingDirection, tableNode);
1140
+ }
1141
+
1142
+ function getTargetParent(upBool, topNode, secondNode, nodeName) {
1143
+ var tbodies = editor.dom.select('>' + nodeName, topNode);
1144
+ var position = tbodies.indexOf(secondNode);
1145
+ if (upBool && position === 0 || !upBool && position === tbodies.length - 1) {
1146
+ return getFirstHeadOrFoot(upBool, topNode);
1147
+ } else if (position === -1) {
1148
+ var topOrBottom = secondNode.tagName.toLowerCase() === 'thead' ? 0 : tbodies.length - 1;
1149
+ return tbodies[topOrBottom];
1150
+ }
1151
+
1152
+ return tbodies[position + (upBool ? -1 : 1)];
1153
+ }
1154
+
1155
+ function getFirstHeadOrFoot(upBool, parent) {
1156
+ var tagName = upBool ? 'thead' : 'tfoot';
1157
+ var headOrFoot = editor.dom.select('>' + tagName, parent);
1158
+ return headOrFoot.length !== 0 ? headOrFoot[0] : null;
1159
+ }
1160
+
1161
+ function moveToRowInTarget(upBool, targetParent, sourceNode) {
1162
+ var targetRow = getChildForDirection(targetParent, upBool);
1163
+
1164
+ if (targetRow) {
1165
+ moveCursorToRow(editor, sourceNode, targetRow, upBool);
1166
+ }
1167
+
1168
+ e.preventDefault();
1169
+ return true;
1170
+ }
1171
+
1172
+ function escapeTable(upBool, currentRow, siblingDirection, table) {
1173
+ var tableSibling = table[siblingDirection];
1174
+
1175
+ if (tableSibling) {
1176
+ moveCursorToStartOfElement(tableSibling);
1177
+ return true;
1178
+ }
1179
+
1180
+ var parentCell = editor.dom.getParent(table, 'td,th');
1181
+ if (parentCell) {
1182
+ return handle(upBool, parentCell, e);
1183
+ }
1184
+
1185
+ var backUpSibling = getChildForDirection(currentRow, !upBool);
1186
+ moveCursorToStartOfElement(backUpSibling);
1187
+ e.preventDefault();
1188
+ return false;
1189
+ }
1190
+
1191
+ function getChildForDirection(parent, up) {
1192
+ var child = parent && parent[up ? 'lastChild' : 'firstChild'];
1193
+ // BR is not a valid table child to return in this case we return the table cell
1194
+ return child && child.nodeName === 'BR' ? editor.dom.getParent(child, 'td,th') : child;
1195
+ }
1196
+
1197
+ function moveCursorToStartOfElement(n) {
1198
+ editor.selection.setCursorLocation(n, 0);
1199
+ }
1200
+
1201
+ function isVerticalMovement() {
1202
+ return key == VK.UP || key == VK.DOWN;
1203
+ }
1204
+
1205
+ function isInTable(editor) {
1206
+ var node = editor.selection.getNode();
1207
+ var currentRow = editor.dom.getParent(node, 'tr');
1208
+ return currentRow !== null;
1209
+ }
1210
+
1211
+ function columnIndex(column) {
1212
+ var colIndex = 0;
1213
+ var c = column;
1214
+ while (c.previousSibling) {
1215
+ c = c.previousSibling;
1216
+ colIndex = colIndex + getSpanVal(c, "colspan");
1217
+ }
1218
+ return colIndex;
1219
+ }
1220
+
1221
+ function findColumn(rowElement, columnIndex) {
1222
+ var c = 0, r = 0;
1223
+
1224
+ each(rowElement.children, function(cell, i) {
1225
+ c = c + getSpanVal(cell, "colspan");
1226
+ r = i;
1227
+ if (c > columnIndex) {
1228
+ return false;
1229
+ }
1230
+ });
1231
+ return r;
1232
+ }
1233
+
1234
+ function moveCursorToRow(ed, node, row, upBool) {
1235
+ var srcColumnIndex = columnIndex(editor.dom.getParent(node, 'td,th'));
1236
+ var tgtColumnIndex = findColumn(row, srcColumnIndex);
1237
+ var tgtNode = row.childNodes[tgtColumnIndex];
1238
+ var rowCellTarget = getChildForDirection(tgtNode, upBool);
1239
+ moveCursorToStartOfElement(rowCellTarget || tgtNode);
1240
+ }
1241
+
1242
+ function shouldFixCaret(preBrowserNode) {
1243
+ var newNode = editor.selection.getNode();
1244
+ var newParent = editor.dom.getParent(newNode, 'td,th');
1245
+ var oldParent = editor.dom.getParent(preBrowserNode, 'td,th');
1246
+
1247
+ return newParent && newParent !== oldParent && checkSameParentTable(newParent, oldParent);
1248
+ }
1249
+
1250
+ function checkSameParentTable(nodeOne, NodeTwo) {
1251
+ return editor.dom.getParent(nodeOne, 'TABLE') === editor.dom.getParent(NodeTwo, 'TABLE');
1252
+ }
1253
+
1254
+ if (isVerticalMovement() && isInTable(editor)) {
1255
+ var preBrowserNode = editor.selection.getNode();
1256
+ Delay.setEditorTimeout(editor, function() {
1257
+ if (shouldFixCaret(preBrowserNode)) {
1258
+ handle(!e.shiftKey && key === VK.UP, preBrowserNode, e);
1259
+ }
1260
+ }, 0);
1261
+ }
1262
+ }
1263
+
1264
+ editor.on('KeyDown', function(e) {
1265
+ eventHandler(e);
1266
+ });
1267
+ }
1268
+
1269
+ function fixBeforeTableCaretBug() {
1270
+ // Checks if the selection/caret is at the start of the specified block element
1271
+ function isAtStart(rng, par) {
1272
+ var doc = par.ownerDocument, rng2 = doc.createRange(), elm;
1273
+
1274
+ rng2.setStartBefore(par);
1275
+ rng2.setEnd(rng.endContainer, rng.endOffset);
1276
+
1277
+ elm = doc.createElement('body');
1278
+ elm.appendChild(rng2.cloneContents());
1279
+
1280
+ // Check for text characters of other elements that should be treated as content
1281
+ return elm.innerHTML.replace(/<(br|img|object|embed|input|textarea)[^>]*>/gi, '-').replace(/<[^>]+>/g, '').length === 0;
1282
+ }
1283
+
1284
+ // Fixes an bug where it's impossible to place the caret before a table in Gecko
1285
+ // this fix solves it by detecting when the caret is at the beginning of such a table
1286
+ // and then manually moves the caret infront of the table
1287
+ editor.on('KeyDown', function(e) {
1288
+ var rng, table, dom = editor.dom;
1289
+
1290
+ // On gecko it's not possible to place the caret before a table
1291
+ if (e.keyCode == 37 || e.keyCode == 38) {
1292
+ rng = editor.selection.getRng();
1293
+ table = dom.getParent(rng.startContainer, 'table');
1294
+
1295
+ if (table && editor.getBody().firstChild == table) {
1296
+ if (isAtStart(rng, table)) {
1297
+ rng = dom.createRng();
1298
+
1299
+ rng.setStartBefore(table);
1300
+ rng.setEndBefore(table);
1301
+
1302
+ editor.selection.setRng(rng);
1303
+
1304
+ e.preventDefault();
1305
+ }
1306
+ }
1307
+ }
1308
+ });
1309
+ }
1310
+
1311
+ // Fixes an issue on Gecko where it's impossible to place the caret behind a table
1312
+ // This fix will force a paragraph element after the table but only when the forced_root_block setting is enabled
1313
+ function fixTableCaretPos() {
1314
+ editor.on('KeyDown SetContent VisualAid', function() {
1315
+ var last;
1316
+
1317
+ // Skip empty text nodes from the end
1318
+ for (last = editor.getBody().lastChild; last; last = last.previousSibling) {
1319
+ if (last.nodeType == 3) {
1320
+ if (last.nodeValue.length > 0) {
1321
+ break;
1322
+ }
1323
+ } else if (last.nodeType == 1 && (last.tagName == 'BR' || !last.getAttribute('data-mce-bogus'))) {
1324
+ break;
1325
+ }
1326
+ }
1327
+
1328
+ if (last && last.nodeName == 'TABLE') {
1329
+ if (editor.settings.forced_root_block) {
1330
+ editor.dom.add(
1331
+ editor.getBody(),
1332
+ editor.settings.forced_root_block,
1333
+ editor.settings.forced_root_block_attrs,
1334
+ Env.ie && Env.ie < 10 ? '&nbsp;' : '<br data-mce-bogus="1" />'
1335
+ );
1336
+ } else {
1337
+ editor.dom.add(editor.getBody(), 'br', {'data-mce-bogus': '1'});
1338
+ }
1339
+ }
1340
+ });
1341
+
1342
+ editor.on('PreProcess', function(o) {
1343
+ var last = o.node.lastChild;
1344
+
1345
+ if (last && (last.nodeName == "BR" || (last.childNodes.length == 1 &&
1346
+ (last.firstChild.nodeName == 'BR' || last.firstChild.nodeValue == '\u00a0'))) &&
1347
+ last.previousSibling && last.previousSibling.nodeName == "TABLE") {
1348
+ editor.dom.remove(last);
1349
+ }
1350
+ });
1351
+ }
1352
+
1353
+ // this nasty hack is here to work around some WebKit selection bugs.
1354
+ function fixTableCellSelection() {
1355
+ function tableCellSelected(ed, rng, n, currentCell) {
1356
+ // The decision of when a table cell is selected is somewhat involved. The fact that this code is
1357
+ // required is actually a pointer to the root cause of this bug. A cell is selected when the start
1358
+ // and end offsets are 0, the start container is a text, and the selection node is either a TR (most cases)
1359
+ // or the parent of the table (in the case of the selection containing the last cell of a table).
1360
+ var TEXT_NODE = 3, table = ed.dom.getParent(rng.startContainer, 'TABLE');
1361
+ var tableParent, allOfCellSelected, tableCellSelection;
1362
+
1363
+ if (table) {
1364
+ tableParent = table.parentNode;
1365
+ }
1366
+
1367
+ allOfCellSelected = rng.startContainer.nodeType == TEXT_NODE &&
1368
+ rng.startOffset === 0 &&
1369
+ rng.endOffset === 0 &&
1370
+ currentCell &&
1371
+ (n.nodeName == "TR" || n == tableParent);
1372
+
1373
+ tableCellSelection = (n.nodeName == "TD" || n.nodeName == "TH") && !currentCell;
1374
+
1375
+ return allOfCellSelected || tableCellSelection;
1376
+ }
1377
+
1378
+ function fixSelection() {
1379
+ var rng = editor.selection.getRng();
1380
+ var n = editor.selection.getNode();
1381
+ var currentCell = editor.dom.getParent(rng.startContainer, 'TD,TH');
1382
+
1383
+ if (!tableCellSelected(editor, rng, n, currentCell)) {
1384
+ return;
1385
+ }
1386
+
1387
+ if (!currentCell) {
1388
+ currentCell = n;
1389
+ }
1390
+
1391
+ // Get the very last node inside the table cell
1392
+ var end = currentCell.lastChild;
1393
+ while (end.lastChild) {
1394
+ end = end.lastChild;
1395
+ }
1396
+
1397
+ // Select the entire table cell. Nothing outside of the table cell should be selected.
1398
+ if (end.nodeType == 3) {
1399
+ rng.setEnd(end, end.data.length);
1400
+ editor.selection.setRng(rng);
1401
+ }
1402
+ }
1403
+
1404
+ editor.on('KeyDown', function() {
1405
+ fixSelection();
1406
+ });
1407
+
1408
+ editor.on('MouseDown', function(e) {
1409
+ if (e.button != 2) {
1410
+ fixSelection();
1411
+ }
1412
+ });
1413
+ }
1414
+
1415
+ /**
1416
+ * Delete table if all cells are selected.
1417
+ */
1418
+ function deleteTable() {
1419
+ function placeCaretInCell(cell) {
1420
+ editor.selection.select(cell, true);
1421
+ editor.selection.collapse(true);
1422
+ }
1423
+
1424
+ function clearCell(cell) {
1425
+ editor.$(cell).empty();
1426
+ Utils.paddCell(cell);
1427
+ }
1428
+
1429
+ editor.on('keydown', function(e) {
1430
+ if ((e.keyCode == VK.DELETE || e.keyCode == VK.BACKSPACE) && !e.isDefaultPrevented()) {
1431
+ var table, tableCells, selectedTableCells, cell;
1432
+
1433
+ table = editor.dom.getParent(editor.selection.getStart(), 'table');
1434
+ if (table) {
1435
+ tableCells = editor.dom.select('td,th', table);
1436
+ selectedTableCells = Tools.grep(tableCells, function(cell) {
1437
+ return !!editor.dom.getAttrib(cell, 'data-mce-selected');
1438
+ });
1439
+
1440
+ if (selectedTableCells.length === 0) {
1441
+ // If caret is within an empty table cell then empty it for real
1442
+ cell = editor.dom.getParent(editor.selection.getStart(), 'td,th');
1443
+ if (editor.selection.isCollapsed() && cell && editor.dom.isEmpty(cell)) {
1444
+ e.preventDefault();
1445
+ clearCell(cell);
1446
+ placeCaretInCell(cell);
1447
+ }
1448
+
1449
+ return;
1450
+ }
1451
+
1452
+ e.preventDefault();
1453
+
1454
+ editor.undoManager.transact(function() {
1455
+ if (tableCells.length == selectedTableCells.length) {
1456
+ editor.execCommand('mceTableDelete');
1457
+ } else {
1458
+ Tools.each(selectedTableCells, clearCell);
1459
+ placeCaretInCell(selectedTableCells[0]);
1460
+ }
1461
+ });
1462
+ }
1463
+ }
1464
+ });
1465
+ }
1466
+
1467
+ deleteTable();
1468
+
1469
+ if (Env.webkit) {
1470
+ moveWebKitSelection();
1471
+ fixTableCellSelection();
1472
+ }
1473
+
1474
+ if (Env.gecko) {
1475
+ fixBeforeTableCaretBug();
1476
+ fixTableCaretPos();
1477
+ }
1478
+
1479
+ if (Env.ie > 9) {
1480
+ fixBeforeTableCaretBug();
1481
+ fixTableCaretPos();
1482
+ }
1483
+ };
1484
+ });
1485
+
1486
+ // Included from: js/tinymce/plugins/table/classes/CellSelection.js
1487
+
1488
+ /**
1489
+ * CellSelection.js
1490
+ *
1491
+ * Released under LGPL License.
1492
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
1493
+ *
1494
+ * License: http://www.tinymce.com/license
1495
+ * Contributing: http://www.tinymce.com/contributing
1496
+ */
1497
+
1498
+ /**
1499
+ * This class handles table cell selection by faking it using a css class that gets applied
1500
+ * to cells when dragging the mouse from one cell to another.
1501
+ *
1502
+ * @class tinymce.tableplugin.CellSelection
1503
+ * @private
1504
+ */
1505
+ define("tinymce/tableplugin/CellSelection", [
1506
+ "tinymce/tableplugin/TableGrid",
1507
+ "tinymce/dom/TreeWalker",
1508
+ "tinymce/util/Tools"
1509
+ ], function(TableGrid, TreeWalker, Tools) {
1510
+ return function(editor) {
1511
+ var dom = editor.dom, tableGrid, startCell, startTable, lastMouseOverTarget, hasCellSelection = true, resizing;
1512
+
1513
+ function clear(force) {
1514
+ // Restore selection possibilities
1515
+ editor.getBody().style.webkitUserSelect = '';
1516
+
1517
+ if (force || hasCellSelection) {
1518
+ editor.$('td[data-mce-selected],th[data-mce-selected]').removeAttr('data-mce-selected');
1519
+ hasCellSelection = false;
1520
+ }
1521
+ }
1522
+
1523
+ function isCellInTable(table, cell) {
1524
+ if (!table || !cell) {
1525
+ return false;
1526
+ }
1527
+
1528
+ return table === dom.getParent(cell, 'table');
1529
+ }
1530
+
1531
+ function cellSelectionHandler(e) {
1532
+ var sel, target = e.target, currentCell;
1533
+
1534
+ if (resizing) {
1535
+ return;
1536
+ }
1537
+
1538
+ // Fake mouse enter by keeping track of last mouse over
1539
+ if (target === lastMouseOverTarget) {
1540
+ return;
1541
+ }
1542
+
1543
+ lastMouseOverTarget = target;
1544
+
1545
+ if (startTable && startCell) {
1546
+ currentCell = dom.getParent(target, 'td,th');
1547
+
1548
+ if (!isCellInTable(startTable, currentCell)) {
1549
+ currentCell = dom.getParent(startTable, 'td,th');
1550
+ }
1551
+
1552
+ // Selection inside first cell is normal until we have expanted
1553
+ if (startCell === currentCell && !hasCellSelection) {
1554
+ return;
1555
+ }
1556
+
1557
+ if (isCellInTable(startTable, currentCell)) {
1558
+ e.preventDefault();
1559
+
1560
+ if (!tableGrid) {
1561
+ tableGrid = new TableGrid(editor, startTable, startCell);
1562
+ editor.getBody().style.webkitUserSelect = 'none';
1563
+ }
1564
+
1565
+ tableGrid.setEndCell(currentCell);
1566
+ hasCellSelection = true;
1567
+
1568
+ // Remove current selection
1569
+ sel = editor.selection.getSel();
1570
+
1571
+ try {
1572
+ if (sel.removeAllRanges) {
1573
+ sel.removeAllRanges();
1574
+ } else {
1575
+ sel.empty();
1576
+ }
1577
+ } catch (ex) {
1578
+ // IE9 might throw errors here
1579
+ }
1580
+ }
1581
+ }
1582
+ }
1583
+
1584
+ editor.on('SelectionChange', function(e) {
1585
+ if (hasCellSelection) {
1586
+ e.stopImmediatePropagation();
1587
+ }
1588
+ }, true);
1589
+
1590
+ // Add cell selection logic
1591
+ editor.on('MouseDown', function(e) {
1592
+ if (e.button != 2 && !resizing) {
1593
+ clear();
1594
+
1595
+ startCell = dom.getParent(e.target, 'td,th');
1596
+ startTable = dom.getParent(startCell, 'table');
1597
+ }
1598
+ });
1599
+
1600
+ editor.on('mouseover', cellSelectionHandler);
1601
+
1602
+ editor.on('remove', function() {
1603
+ dom.unbind(editor.getDoc(), 'mouseover', cellSelectionHandler);
1604
+ clear();
1605
+ });
1606
+
1607
+ editor.on('MouseUp', function() {
1608
+ var rng, sel = editor.selection, selectedCells, walker, node, lastNode;
1609
+
1610
+ function setPoint(node, start) {
1611
+ var walker = new TreeWalker(node, node);
1612
+
1613
+ do {
1614
+ // Text node
1615
+ if (node.nodeType == 3 && Tools.trim(node.nodeValue).length !== 0) {
1616
+ if (start) {
1617
+ rng.setStart(node, 0);
1618
+ } else {
1619
+ rng.setEnd(node, node.nodeValue.length);
1620
+ }
1621
+
1622
+ return;
1623
+ }
1624
+
1625
+ // BR element
1626
+ if (node.nodeName == 'BR') {
1627
+ if (start) {
1628
+ rng.setStartBefore(node);
1629
+ } else {
1630
+ rng.setEndBefore(node);
1631
+ }
1632
+
1633
+ return;
1634
+ }
1635
+ } while ((node = (start ? walker.next() : walker.prev())));
1636
+ }
1637
+
1638
+ // Move selection to startCell
1639
+ if (startCell) {
1640
+ if (tableGrid) {
1641
+ editor.getBody().style.webkitUserSelect = '';
1642
+ }
1643
+
1644
+ // Try to expand text selection as much as we can only Gecko supports cell selection
1645
+ selectedCells = dom.select('td[data-mce-selected],th[data-mce-selected]');
1646
+ if (selectedCells.length > 0) {
1647
+ rng = dom.createRng();
1648
+ node = selectedCells[0];
1649
+ rng.setStartBefore(node);
1650
+ rng.setEndAfter(node);
1651
+
1652
+ setPoint(node, 1);
1653
+ walker = new TreeWalker(node, dom.getParent(selectedCells[0], 'table'));
1654
+
1655
+ do {
1656
+ if (node.nodeName == 'TD' || node.nodeName == 'TH') {
1657
+ if (!dom.getAttrib(node, 'data-mce-selected')) {
1658
+ break;
1659
+ }
1660
+
1661
+ lastNode = node;
1662
+ }
1663
+ } while ((node = walker.next()));
1664
+
1665
+ setPoint(lastNode);
1666
+
1667
+ sel.setRng(rng);
1668
+ }
1669
+
1670
+ editor.nodeChanged();
1671
+ startCell = tableGrid = startTable = lastMouseOverTarget = null;
1672
+ }
1673
+ });
1674
+
1675
+ editor.on('KeyUp Drop SetContent', function(e) {
1676
+ clear(e.type == 'setcontent');
1677
+ startCell = tableGrid = startTable = lastMouseOverTarget = null;
1678
+ resizing = false;
1679
+ });
1680
+
1681
+ editor.on('ObjectResizeStart ObjectResized', function(e) {
1682
+ resizing = e.type != 'objectresized';
1683
+ });
1684
+
1685
+ return {
1686
+ clear: clear
1687
+ };
1688
+ };
1689
+ });
1690
+
1691
+ // Included from: js/tinymce/plugins/table/classes/Dialogs.js
1692
+
1693
+ /**
1694
+ * Dialogs.js
1695
+ *
1696
+ * Released under LGPL License.
1697
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
1698
+ *
1699
+ * License: http://www.tinymce.com/license
1700
+ * Contributing: http://www.tinymce.com/contributing
1701
+ */
1702
+
1703
+ /*eslint dot-notation:0*/
1704
+
1705
+ /**
1706
+ * ...
1707
+ *
1708
+ * @class tinymce.tableplugin.Dialogs
1709
+ * @private
1710
+ */
1711
+ define("tinymce/tableplugin/Dialogs", [
1712
+ "tinymce/util/Tools",
1713
+ "tinymce/Env"
1714
+ ], function(Tools, Env) {
1715
+ var each = Tools.each;
1716
+
1717
+ return function(editor) {
1718
+ var self = this;
1719
+
1720
+ function createColorPickAction() {
1721
+ var colorPickerCallback = editor.settings.color_picker_callback;
1722
+
1723
+ if (colorPickerCallback) {
1724
+ return function() {
1725
+ var self = this;
1726
+
1727
+ colorPickerCallback.call(
1728
+ editor,
1729
+ function(value) {
1730
+ self.value(value).fire('change');
1731
+ },
1732
+ self.value()
1733
+ );
1734
+ };
1735
+ }
1736
+ }
1737
+
1738
+ function createStyleForm(dom) {
1739
+ return {
1740
+ title: 'Advanced',
1741
+ type: 'form',
1742
+ defaults: {
1743
+ onchange: function() {
1744
+ updateStyle(dom, this.parents().reverse()[0], this.name() == "style");
1745
+ }
1746
+ },
1747
+ items: [
1748
+ {
1749
+ label: 'Style',
1750
+ name: 'style',
1751
+ type: 'textbox'
1752
+ },
1753
+
1754
+ {
1755
+ type: 'form',
1756
+ padding: 0,
1757
+ formItemDefaults: {
1758
+ layout: 'grid',
1759
+ alignH: ['start', 'right']
1760
+ },
1761
+ defaults: {
1762
+ size: 7
1763
+ },
1764
+ items: [
1765
+ {
1766
+ label: 'Border color',
1767
+ type: 'colorbox',
1768
+ name: 'borderColor',
1769
+ onaction: createColorPickAction()
1770
+ },
1771
+
1772
+ {
1773
+ label: 'Background color',
1774
+ type: 'colorbox',
1775
+ name: 'backgroundColor',
1776
+ onaction: createColorPickAction()
1777
+ }
1778
+ ]
1779
+ }
1780
+ ]
1781
+ };
1782
+ }
1783
+
1784
+ function removePxSuffix(size) {
1785
+ return size ? size.replace(/px$/, '') : "";
1786
+ }
1787
+
1788
+ function addSizeSuffix(size) {
1789
+ if (/^[0-9]+$/.test(size)) {
1790
+ size += "px";
1791
+ }
1792
+
1793
+ return size;
1794
+ }
1795
+
1796
+ function unApplyAlign(elm) {
1797
+ each('left center right'.split(' '), function(name) {
1798
+ editor.formatter.remove('align' + name, {}, elm);
1799
+ });
1800
+ }
1801
+
1802
+ function unApplyVAlign(elm) {
1803
+ each('top middle bottom'.split(' '), function(name) {
1804
+ editor.formatter.remove('valign' + name, {}, elm);
1805
+ });
1806
+ }
1807
+
1808
+ function buildListItems(inputList, itemCallback, startItems) {
1809
+ function appendItems(values, output) {
1810
+ output = output || [];
1811
+
1812
+ Tools.each(values, function(item) {
1813
+ var menuItem = {text: item.text || item.title};
1814
+
1815
+ if (item.menu) {
1816
+ menuItem.menu = appendItems(item.menu);
1817
+ } else {
1818
+ menuItem.value = item.value;
1819
+
1820
+ if (itemCallback) {
1821
+ itemCallback(menuItem);
1822
+ }
1823
+ }
1824
+
1825
+ output.push(menuItem);
1826
+ });
1827
+
1828
+ return output;
1829
+ }
1830
+
1831
+ return appendItems(inputList, startItems || []);
1832
+ }
1833
+
1834
+ function updateStyle(dom, win, isStyleCtrl) {
1835
+ var data = win.toJSON();
1836
+ var css = dom.parseStyle(data.style);
1837
+
1838
+ if (isStyleCtrl) {
1839
+ win.find('#borderColor').value(css["border-color"] || '')[0].fire('change');
1840
+ win.find('#backgroundColor').value(css["background-color"] || '')[0].fire('change');
1841
+ } else {
1842
+ css["border-color"] = data.borderColor;
1843
+ css["background-color"] = data.backgroundColor;
1844
+ }
1845
+
1846
+ win.find('#style').value(dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
1847
+ }
1848
+
1849
+ function appendStylesToData(dom, data, elm) {
1850
+ var css = dom.parseStyle(dom.getAttrib(elm, 'style'));
1851
+
1852
+ if (css["border-color"]) {
1853
+ data.borderColor = css["border-color"];
1854
+ }
1855
+
1856
+ if (css["background-color"]) {
1857
+ data.backgroundColor = css["background-color"];
1858
+ }
1859
+
1860
+ data.style = dom.serializeStyle(css);
1861
+ }
1862
+
1863
+ function mergeStyles(dom, elm, styles) {
1864
+ var css = dom.parseStyle(dom.getAttrib(elm, 'style'));
1865
+
1866
+ each(styles, function(style) {
1867
+ css[style.name] = style.value;
1868
+ });
1869
+
1870
+ dom.setAttrib(elm, 'style', dom.serializeStyle(dom.parseStyle(dom.serializeStyle(css))));
1871
+ }
1872
+
1873
+ self.tableProps = function() {
1874
+ self.table(true);
1875
+ };
1876
+
1877
+ self.table = function(isProps) {
1878
+ var dom = editor.dom, tableElm, colsCtrl, rowsCtrl, classListCtrl, data = {}, generalTableForm, stylesToMerge;
1879
+
1880
+ function onSubmitTableForm() {
1881
+
1882
+ //Explore the layers of the table till we find the first layer of tds or ths
1883
+ function styleTDTH(elm, name, value) {
1884
+ if (elm.tagName === "TD" || elm.tagName === "TH") {
1885
+ dom.setStyle(elm, name, value);
1886
+ } else {
1887
+ if (elm.children) {
1888
+ for (var i = 0; i < elm.children.length; i++) {
1889
+ styleTDTH(elm.children[i], name, value);
1890
+ }
1891
+ }
1892
+ }
1893
+ }
1894
+
1895
+ var captionElm;
1896
+
1897
+ updateStyle(dom, this);
1898
+ data = Tools.extend(data, this.toJSON());
1899
+
1900
+ if (data["class"] === false) {
1901
+ delete data["class"];
1902
+ }
1903
+
1904
+ editor.undoManager.transact(function() {
1905
+ if (!tableElm) {
1906
+ tableElm = editor.plugins.table.insertTable(data.cols || 1, data.rows || 1);
1907
+ }
1908
+
1909
+ editor.dom.setAttribs(tableElm, {
1910
+ style: data.style,
1911
+ 'class': data['class']
1912
+ });
1913
+
1914
+ if (editor.settings.table_style_by_css) {
1915
+ stylesToMerge = [];
1916
+ stylesToMerge.push({name: 'border', value: data.border});
1917
+ stylesToMerge.push({name: 'border-spacing', value: addSizeSuffix(data.cellspacing)});
1918
+ mergeStyles(dom, tableElm, stylesToMerge);
1919
+ dom.setAttribs(tableElm, {
1920
+ 'data-mce-border-color': data.borderColor,
1921
+ 'data-mce-cell-padding': data.cellpadding,
1922
+ 'data-mce-border': data.border
1923
+ });
1924
+ if (tableElm.children) {
1925
+ for (var i = 0; i < tableElm.children.length; i++) {
1926
+ styleTDTH(tableElm.children[i], 'border', data.border);
1927
+ styleTDTH(tableElm.children[i], 'padding', addSizeSuffix(data.cellpadding));
1928
+ }
1929
+ }
1930
+ } else {
1931
+ editor.dom.setAttribs(tableElm, {
1932
+ border: data.border,
1933
+ cellpadding: data.cellpadding,
1934
+ cellspacing: data.cellspacing
1935
+ });
1936
+ }
1937
+
1938
+ if (dom.getAttrib(tableElm, 'width') && !editor.settings.table_style_by_css) {
1939
+ dom.setAttrib(tableElm, 'width', removePxSuffix(data.width));
1940
+ } else {
1941
+ dom.setStyle(tableElm, 'width', addSizeSuffix(data.width));
1942
+ }
1943
+
1944
+ dom.setStyle(tableElm, 'height', addSizeSuffix(data.height));
1945
+
1946
+ // Toggle caption on/off
1947
+ captionElm = dom.select('caption', tableElm)[0];
1948
+
1949
+ if (captionElm && !data.caption) {
1950
+ dom.remove(captionElm);
1951
+ }
1952
+
1953
+ if (!captionElm && data.caption) {
1954
+ captionElm = dom.create('caption');
1955
+ captionElm.innerHTML = !Env.ie ? '<br data-mce-bogus="1"/>' : '\u00a0';
1956
+ tableElm.insertBefore(captionElm, tableElm.firstChild);
1957
+ }
1958
+ unApplyAlign(tableElm);
1959
+ if (data.align) {
1960
+ editor.formatter.apply('align' + data.align, {}, tableElm);
1961
+ }
1962
+
1963
+ editor.focus();
1964
+ editor.addVisual();
1965
+ });
1966
+ }
1967
+
1968
+ function getTDTHOverallStyle(elm, name) {
1969
+ var cells = editor.dom.select("td,th", elm), firstChildStyle;
1970
+
1971
+ function checkChildren(firstChildStyle, elms) {
1972
+
1973
+ for (var i = 0; i < elms.length; i++) {
1974
+ var currentStyle = dom.getStyle(elms[i], name);
1975
+ if (typeof firstChildStyle === "undefined") {
1976
+ firstChildStyle = currentStyle;
1977
+ }
1978
+ if (firstChildStyle != currentStyle) {
1979
+ return "";
1980
+ }
1981
+ }
1982
+
1983
+ return firstChildStyle;
1984
+
1985
+ }
1986
+
1987
+ firstChildStyle = checkChildren(firstChildStyle, cells);
1988
+
1989
+ return firstChildStyle;
1990
+ }
1991
+
1992
+ if (isProps === true) {
1993
+ tableElm = dom.getParent(editor.selection.getStart(), 'table');
1994
+
1995
+ if (tableElm) {
1996
+ data = {
1997
+ width: removePxSuffix(dom.getStyle(tableElm, 'width') || dom.getAttrib(tableElm, 'width')),
1998
+ height: removePxSuffix(dom.getStyle(tableElm, 'height') || dom.getAttrib(tableElm, 'height')),
1999
+ cellspacing: removePxSuffix(dom.getStyle(tableElm, 'border-spacing') ||
2000
+ dom.getAttrib(tableElm, 'cellspacing')),
2001
+ cellpadding: dom.getAttrib(tableElm, 'data-mce-cell-padding') || dom.getAttrib(tableElm, 'cellpadding') ||
2002
+ getTDTHOverallStyle(tableElm, 'padding'),
2003
+ border: dom.getAttrib(tableElm, 'data-mce-border') || dom.getAttrib(tableElm, 'border') ||
2004
+ getTDTHOverallStyle(tableElm, 'border'),
2005
+ borderColor: dom.getAttrib(tableElm, 'data-mce-border-color'),
2006
+ caption: !!dom.select('caption', tableElm)[0],
2007
+ 'class': dom.getAttrib(tableElm, 'class')
2008
+ };
2009
+
2010
+ each('left center right'.split(' '), function(name) {
2011
+ if (editor.formatter.matchNode(tableElm, 'align' + name)) {
2012
+ data.align = name;
2013
+ }
2014
+ });
2015
+ }
2016
+ } else {
2017
+ colsCtrl = {label: 'Cols', name: 'cols'};
2018
+ rowsCtrl = {label: 'Rows', name: 'rows'};
2019
+ }
2020
+
2021
+ if (editor.settings.table_class_list) {
2022
+ if (data["class"]) {
2023
+ data["class"] = data["class"].replace(/\s*mce\-item\-table\s*/g, '');
2024
+ }
2025
+
2026
+ classListCtrl = {
2027
+ name: 'class',
2028
+ type: 'listbox',
2029
+ label: 'Class',
2030
+ values: buildListItems(
2031
+ editor.settings.table_class_list,
2032
+ function(item) {
2033
+ if (item.value) {
2034
+ item.textStyle = function() {
2035
+ return editor.formatter.getCssText({block: 'table', classes: [item.value]});
2036
+ };
2037
+ }
2038
+ }
2039
+ )
2040
+ };
2041
+ }
2042
+
2043
+ generalTableForm = {
2044
+ type: 'form',
2045
+ layout: 'flex',
2046
+ direction: 'column',
2047
+ labelGapCalc: 'children',
2048
+ padding: 0,
2049
+ items: [
2050
+ {
2051
+ type: 'form',
2052
+ labelGapCalc: false,
2053
+ padding: 0,
2054
+ layout: 'grid',
2055
+ columns: 2,
2056
+ defaults: {
2057
+ type: 'textbox',
2058
+ maxWidth: 50
2059
+ },
2060
+ items: (editor.settings.table_appearance_options !== false) ? [
2061
+ colsCtrl,
2062
+ rowsCtrl,
2063
+ {label: 'Width', name: 'width'},
2064
+ {label: 'Height', name: 'height'},
2065
+ {label: 'Cell spacing', name: 'cellspacing'},
2066
+ {label: 'Cell padding', name: 'cellpadding'},
2067
+ {label: 'Border', name: 'border'},
2068
+ {label: 'Caption', name: 'caption', type: 'checkbox'}
2069
+ ] : [
2070
+ colsCtrl,
2071
+ rowsCtrl,
2072
+ {label: 'Width', name: 'width'},
2073
+ {label: 'Height', name: 'height'}
2074
+ ]
2075
+ },
2076
+
2077
+ {
2078
+ label: 'Alignment',
2079
+ name: 'align',
2080
+ type: 'listbox',
2081
+ text: 'None',
2082
+ values: [
2083
+ {text: 'None', value: ''},
2084
+ {text: 'Left', value: 'left'},
2085
+ {text: 'Center', value: 'center'},
2086
+ {text: 'Right', value: 'right'}
2087
+ ]
2088
+ },
2089
+
2090
+ classListCtrl
2091
+ ]
2092
+ };
2093
+
2094
+ if (editor.settings.table_advtab !== false) {
2095
+ appendStylesToData(dom, data, tableElm);
2096
+
2097
+ editor.windowManager.open({
2098
+ title: "Table properties",
2099
+ data: data,
2100
+ bodyType: 'tabpanel',
2101
+ body: [
2102
+ {
2103
+ title: 'General',
2104
+ type: 'form',
2105
+ items: generalTableForm
2106
+ },
2107
+ createStyleForm(dom)
2108
+ ],
2109
+
2110
+ onsubmit: onSubmitTableForm
2111
+ });
2112
+ } else {
2113
+ editor.windowManager.open({
2114
+ title: "Table properties",
2115
+ data: data,
2116
+ body: generalTableForm,
2117
+ onsubmit: onSubmitTableForm
2118
+ });
2119
+ }
2120
+ };
2121
+
2122
+ self.merge = function(grid, cell) {
2123
+ editor.windowManager.open({
2124
+ title: "Merge cells",
2125
+ body: [
2126
+ {label: 'Cols', name: 'cols', type: 'textbox', value: '1', size: 10},
2127
+ {label: 'Rows', name: 'rows', type: 'textbox', value: '1', size: 10}
2128
+ ],
2129
+ onsubmit: function() {
2130
+ var data = this.toJSON();
2131
+
2132
+ editor.undoManager.transact(function() {
2133
+ grid.merge(cell, data.cols, data.rows);
2134
+ });
2135
+ }
2136
+ });
2137
+ };
2138
+
2139
+ self.cell = function() {
2140
+ var dom = editor.dom, cellElm, data, classListCtrl, cells = [];
2141
+
2142
+ function onSubmitCellForm() {
2143
+ updateStyle(dom, this);
2144
+ data = Tools.extend(data, this.toJSON());
2145
+
2146
+ editor.undoManager.transact(function() {
2147
+ each(cells, function(cellElm) {
2148
+ editor.dom.setAttribs(cellElm, {
2149
+ scope: data.scope,
2150
+ style: data.style,
2151
+ 'class': data['class']
2152
+ });
2153
+
2154
+ editor.dom.setStyles(cellElm, {
2155
+ width: addSizeSuffix(data.width),
2156
+ height: addSizeSuffix(data.height)
2157
+ });
2158
+
2159
+ // Switch cell type
2160
+ if (data.type && cellElm.nodeName.toLowerCase() != data.type) {
2161
+ cellElm = dom.rename(cellElm, data.type);
2162
+ }
2163
+
2164
+ // Apply/remove alignment
2165
+ unApplyAlign(cellElm);
2166
+ if (data.align) {
2167
+ editor.formatter.apply('align' + data.align, {}, cellElm);
2168
+ }
2169
+
2170
+ // Apply/remove vertical alignment
2171
+ unApplyVAlign(cellElm);
2172
+ if (data.valign) {
2173
+ editor.formatter.apply('valign' + data.valign, {}, cellElm);
2174
+ }
2175
+ });
2176
+
2177
+ editor.focus();
2178
+ });
2179
+ }
2180
+
2181
+ // Get selected cells or the current cell
2182
+ cells = editor.dom.select('td[data-mce-selected],th[data-mce-selected]');
2183
+ cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
2184
+ if (!cells.length && cellElm) {
2185
+ cells.push(cellElm);
2186
+ }
2187
+
2188
+ cellElm = cellElm || cells[0];
2189
+
2190
+ if (!cellElm) {
2191
+ // If this element is null, return now to avoid crashing.
2192
+ return;
2193
+ }
2194
+
2195
+ data = {
2196
+ width: removePxSuffix(dom.getStyle(cellElm, 'width') || dom.getAttrib(cellElm, 'width')),
2197
+ height: removePxSuffix(dom.getStyle(cellElm, 'height') || dom.getAttrib(cellElm, 'height')),
2198
+ scope: dom.getAttrib(cellElm, 'scope'),
2199
+ 'class': dom.getAttrib(cellElm, 'class')
2200
+ };
2201
+
2202
+ data.type = cellElm.nodeName.toLowerCase();
2203
+
2204
+ each('left center right'.split(' '), function(name) {
2205
+ if (editor.formatter.matchNode(cellElm, 'align' + name)) {
2206
+ data.align = name;
2207
+ }
2208
+ });
2209
+
2210
+ each('top middle bottom'.split(' '), function(name) {
2211
+ if (editor.formatter.matchNode(cellElm, 'valign' + name)) {
2212
+ data.valign = name;
2213
+ }
2214
+ });
2215
+
2216
+ if (editor.settings.table_cell_class_list) {
2217
+ classListCtrl = {
2218
+ name: 'class',
2219
+ type: 'listbox',
2220
+ label: 'Class',
2221
+ values: buildListItems(
2222
+ editor.settings.table_cell_class_list,
2223
+ function(item) {
2224
+ if (item.value) {
2225
+ item.textStyle = function() {
2226
+ return editor.formatter.getCssText({block: 'td', classes: [item.value]});
2227
+ };
2228
+ }
2229
+ }
2230
+ )
2231
+ };
2232
+ }
2233
+
2234
+ var generalCellForm = {
2235
+ type: 'form',
2236
+ layout: 'flex',
2237
+ direction: 'column',
2238
+ labelGapCalc: 'children',
2239
+ padding: 0,
2240
+ items: [
2241
+ {
2242
+ type: 'form',
2243
+ layout: 'grid',
2244
+ columns: 2,
2245
+ labelGapCalc: false,
2246
+ padding: 0,
2247
+ defaults: {
2248
+ type: 'textbox',
2249
+ maxWidth: 50
2250
+ },
2251
+ items: [
2252
+ {label: 'Width', name: 'width'},
2253
+ {label: 'Height', name: 'height'},
2254
+ {
2255
+ label: 'Cell type',
2256
+ name: 'type',
2257
+ type: 'listbox',
2258
+ text: 'None',
2259
+ minWidth: 90,
2260
+ maxWidth: null,
2261
+ values: [
2262
+ {text: 'Cell', value: 'td'},
2263
+ {text: 'Header cell', value: 'th'}
2264
+ ]
2265
+ },
2266
+ {
2267
+ label: 'Scope',
2268
+ name: 'scope',
2269
+ type: 'listbox',
2270
+ text: 'None',
2271
+ minWidth: 90,
2272
+ maxWidth: null,
2273
+ values: [
2274
+ {text: 'None', value: ''},
2275
+ {text: 'Row', value: 'row'},
2276
+ {text: 'Column', value: 'col'},
2277
+ {text: 'Row group', value: 'rowgroup'},
2278
+ {text: 'Column group', value: 'colgroup'}
2279
+ ]
2280
+ },
2281
+ {
2282
+ label: 'H Align',
2283
+ name: 'align',
2284
+ type: 'listbox',
2285
+ text: 'None',
2286
+ minWidth: 90,
2287
+ maxWidth: null,
2288
+ values: [
2289
+ {text: 'None', value: ''},
2290
+ {text: 'Left', value: 'left'},
2291
+ {text: 'Center', value: 'center'},
2292
+ {text: 'Right', value: 'right'}
2293
+ ]
2294
+ },
2295
+ {
2296
+ label: 'V Align',
2297
+ name: 'valign',
2298
+ type: 'listbox',
2299
+ text: 'None',
2300
+ minWidth: 90,
2301
+ maxWidth: null,
2302
+ values: [
2303
+ {text: 'None', value: ''},
2304
+ {text: 'Top', value: 'top'},
2305
+ {text: 'Middle', value: 'middle'},
2306
+ {text: 'Bottom', value: 'bottom'}
2307
+ ]
2308
+ }
2309
+ ]
2310
+ },
2311
+
2312
+ classListCtrl
2313
+ ]
2314
+ };
2315
+
2316
+ if (editor.settings.table_cell_advtab !== false) {
2317
+ appendStylesToData(dom, data, cellElm);
2318
+
2319
+ editor.windowManager.open({
2320
+ title: "Cell properties",
2321
+ bodyType: 'tabpanel',
2322
+ data: data,
2323
+ body: [
2324
+ {
2325
+ title: 'General',
2326
+ type: 'form',
2327
+ items: generalCellForm
2328
+ },
2329
+
2330
+ createStyleForm(dom)
2331
+ ],
2332
+
2333
+ onsubmit: onSubmitCellForm
2334
+ });
2335
+ } else {
2336
+ editor.windowManager.open({
2337
+ title: "Cell properties",
2338
+ data: data,
2339
+ body: generalCellForm,
2340
+ onsubmit: onSubmitCellForm
2341
+ });
2342
+ }
2343
+ };
2344
+
2345
+ self.row = function() {
2346
+ var dom = editor.dom, tableElm, cellElm, rowElm, classListCtrl, data, rows = [], generalRowForm;
2347
+
2348
+ function onSubmitRowForm() {
2349
+ var tableElm, oldParentElm, parentElm;
2350
+
2351
+ updateStyle(dom, this);
2352
+ data = Tools.extend(data, this.toJSON());
2353
+
2354
+ editor.undoManager.transact(function() {
2355
+ var toType = data.type;
2356
+
2357
+ each(rows, function(rowElm) {
2358
+ editor.dom.setAttribs(rowElm, {
2359
+ scope: data.scope,
2360
+ style: data.style,
2361
+ 'class': data['class']
2362
+ });
2363
+
2364
+ editor.dom.setStyles(rowElm, {
2365
+ height: addSizeSuffix(data.height)
2366
+ });
2367
+
2368
+ if (toType != rowElm.parentNode.nodeName.toLowerCase()) {
2369
+ tableElm = dom.getParent(rowElm, 'table');
2370
+
2371
+ oldParentElm = rowElm.parentNode;
2372
+ parentElm = dom.select(toType, tableElm)[0];
2373
+ if (!parentElm) {
2374
+ parentElm = dom.create(toType);
2375
+ if (tableElm.firstChild) {
2376
+ tableElm.insertBefore(parentElm, tableElm.firstChild);
2377
+ } else {
2378
+ tableElm.appendChild(parentElm);
2379
+ }
2380
+ }
2381
+
2382
+ parentElm.appendChild(rowElm);
2383
+
2384
+ if (!oldParentElm.hasChildNodes()) {
2385
+ dom.remove(oldParentElm);
2386
+ }
2387
+ }
2388
+
2389
+ // Apply/remove alignment
2390
+ unApplyAlign(rowElm);
2391
+ if (data.align) {
2392
+ editor.formatter.apply('align' + data.align, {}, rowElm);
2393
+ }
2394
+ });
2395
+
2396
+ editor.focus();
2397
+ });
2398
+ }
2399
+
2400
+ tableElm = editor.dom.getParent(editor.selection.getStart(), 'table');
2401
+ cellElm = editor.dom.getParent(editor.selection.getStart(), 'td,th');
2402
+
2403
+ each(tableElm.rows, function(row) {
2404
+ each(row.cells, function(cell) {
2405
+ if (dom.getAttrib(cell, 'data-mce-selected') || cell == cellElm) {
2406
+ rows.push(row);
2407
+ return false;
2408
+ }
2409
+ });
2410
+ });
2411
+
2412
+ rowElm = rows[0];
2413
+ if (!rowElm) {
2414
+ // If this element is null, return now to avoid crashing.
2415
+ return;
2416
+ }
2417
+
2418
+ data = {
2419
+ height: removePxSuffix(dom.getStyle(rowElm, 'height') || dom.getAttrib(rowElm, 'height')),
2420
+ scope: dom.getAttrib(rowElm, 'scope'),
2421
+ 'class': dom.getAttrib(rowElm, 'class')
2422
+ };
2423
+
2424
+ data.type = rowElm.parentNode.nodeName.toLowerCase();
2425
+
2426
+ each('left center right'.split(' '), function(name) {
2427
+ if (editor.formatter.matchNode(rowElm, 'align' + name)) {
2428
+ data.align = name;
2429
+ }
2430
+ });
2431
+
2432
+ if (editor.settings.table_row_class_list) {
2433
+ classListCtrl = {
2434
+ name: 'class',
2435
+ type: 'listbox',
2436
+ label: 'Class',
2437
+ values: buildListItems(
2438
+ editor.settings.table_row_class_list,
2439
+ function(item) {
2440
+ if (item.value) {
2441
+ item.textStyle = function() {
2442
+ return editor.formatter.getCssText({block: 'tr', classes: [item.value]});
2443
+ };
2444
+ }
2445
+ }
2446
+ )
2447
+ };
2448
+ }
2449
+
2450
+ generalRowForm = {
2451
+ type: 'form',
2452
+ columns: 2,
2453
+ padding: 0,
2454
+ defaults: {
2455
+ type: 'textbox'
2456
+ },
2457
+ items: [
2458
+ {
2459
+ type: 'listbox',
2460
+ name: 'type',
2461
+ label: 'Row type',
2462
+ text: 'None',
2463
+ maxWidth: null,
2464
+ values: [
2465
+ {text: 'Header', value: 'thead'},
2466
+ {text: 'Body', value: 'tbody'},
2467
+ {text: 'Footer', value: 'tfoot'}
2468
+ ]
2469
+ },
2470
+ {
2471
+ type: 'listbox',
2472
+ name: 'align',
2473
+ label: 'Alignment',
2474
+ text: 'None',
2475
+ maxWidth: null,
2476
+ values: [
2477
+ {text: 'None', value: ''},
2478
+ {text: 'Left', value: 'left'},
2479
+ {text: 'Center', value: 'center'},
2480
+ {text: 'Right', value: 'right'}
2481
+ ]
2482
+ },
2483
+ {label: 'Height', name: 'height'},
2484
+ classListCtrl
2485
+ ]
2486
+ };
2487
+
2488
+ if (editor.settings.table_row_advtab !== false) {
2489
+ appendStylesToData(dom, data, rowElm);
2490
+
2491
+ editor.windowManager.open({
2492
+ title: "Row properties",
2493
+ data: data,
2494
+ bodyType: 'tabpanel',
2495
+ body: [
2496
+ {
2497
+ title: 'General',
2498
+ type: 'form',
2499
+ items: generalRowForm
2500
+ },
2501
+ createStyleForm(dom)
2502
+ ],
2503
+
2504
+ onsubmit: onSubmitRowForm
2505
+ });
2506
+ } else {
2507
+ editor.windowManager.open({
2508
+ title: "Row properties",
2509
+ data: data,
2510
+ body: generalRowForm,
2511
+ onsubmit: onSubmitRowForm
2512
+ });
2513
+ }
2514
+ };
2515
+ };
2516
+ });
2517
+
2518
+ // Included from: js/tinymce/plugins/table/classes/ResizeBars.js
2519
+
2520
+ /**
2521
+ * ResizeBars.js
2522
+ *
2523
+ * Released under LGPL License.
2524
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
2525
+ *
2526
+ * License: http://www.tinymce.com/license
2527
+ * Contributing: http://www.tinymce.com/contributing
2528
+ */
2529
+
2530
+ /**
2531
+ * This class handles table column and row resizing by adding divs over the columns and rows of the table.
2532
+ * These divs are then manipulated using mouse events to resize the underlying table.
2533
+ *
2534
+ * @class tinymce.tableplugin.ResizeBars
2535
+ * @private
2536
+ */
2537
+ define("tinymce/tableplugin/ResizeBars", [
2538
+ "tinymce/util/Tools",
2539
+ "tinymce/util/VK"
2540
+ ], function(Tools, VK) {
2541
+ var hoverTable;
2542
+
2543
+ return function(editor) {
2544
+ var RESIZE_BAR_CLASS = 'mce-resize-bar',
2545
+ RESIZE_BAR_ROW_CLASS = 'mce-resize-bar-row',
2546
+ RESIZE_BAR_ROW_CURSOR_STYLE = 'row-resize',
2547
+ RESIZE_BAR_ROW_DATA_ATTRIBUTE = 'data-row',
2548
+ RESIZE_BAR_ROW_DATA_INITIAL_TOP_ATTRIBUTE = 'data-initial-top',
2549
+ RESIZE_BAR_COL_CLASS = 'mce-resize-bar-col',
2550
+ RESIZE_BAR_COL_CURSOR_STYLE = 'col-resize',
2551
+ RESIZE_BAR_COL_DATA_ATTRIBUTE = 'data-col',
2552
+ RESIZE_BAR_COL_DATA_INITIAL_LEFT_ATTRIBUTE = 'data-initial-left',
2553
+ RESIZE_BAR_THICKNESS = 4,
2554
+ RESIZE_MINIMUM_WIDTH = 10,
2555
+ RESIZE_MINIMUM_HEIGHT = 10,
2556
+ RESIZE_BAR_DRAGGING_CLASS = 'mce-resize-bar-dragging';
2557
+
2558
+ var percentageBasedSizeRegex = new RegExp(/(\d+(\.\d+)?%)/),
2559
+ pixelBasedSizeRegex = new RegExp(/px|em/);
2560
+
2561
+ var delayDrop, dragging, blockerElement, dragBar, lastX, lastY;
2562
+
2563
+ // Get the absolute position's top edge.
2564
+ function getTopEdge(index, row) {
2565
+ return {
2566
+ index: index,
2567
+ y: editor.dom.getPos(row).y
2568
+ };
2569
+ }
2570
+
2571
+ // Get the absolute position's bottom edge.
2572
+ function getBottomEdge(index, row) {
2573
+ return {
2574
+ index: index,
2575
+ y: editor.dom.getPos(row).y + row.offsetHeight
2576
+ };
2577
+ }
2578
+
2579
+ // Get the absolute position's left edge.
2580
+ function getLeftEdge(index, cell) {
2581
+ return {
2582
+ index: index,
2583
+ x: editor.dom.getPos(cell).x
2584
+ };
2585
+ }
2586
+
2587
+ // Get the absolute position's right edge.
2588
+ function getRightEdge(index, cell) {
2589
+ return {
2590
+ index: index,
2591
+ x: editor.dom.getPos(cell).x + cell.offsetWidth
2592
+ };
2593
+ }
2594
+
2595
+ function isRtl() {
2596
+ var dir = editor.getBody().dir;
2597
+ return dir === 'rtl';
2598
+ }
2599
+
2600
+ function isInline() {
2601
+ return editor.inline;
2602
+ }
2603
+
2604
+ function getBody() {
2605
+ return isInline ? editor.getBody().ownerDocument.body : editor.getBody();
2606
+ }
2607
+
2608
+ function getInnerEdge(index, cell) {
2609
+ return isRtl() ? getRightEdge(index, cell) : getLeftEdge(index, cell);
2610
+ }
2611
+
2612
+ function getOuterEdge(index, cell) {
2613
+ return isRtl() ? getLeftEdge(index, cell) : getRightEdge(index, cell);
2614
+ }
2615
+
2616
+ function getPercentageWidthFallback(element, table) {
2617
+ return getComputedStyleSize(element, 'width') / getComputedStyleSize(table, 'width') * 100;
2618
+ }
2619
+
2620
+ function getComputedStyleSize(element, property) {
2621
+ var widthString = editor.dom.getStyle(element, property, true);
2622
+ var width = parseInt(widthString, 10);
2623
+ return width;
2624
+ }
2625
+
2626
+ function getCurrentTablePercentWidth(table) {
2627
+ var tableWidth = getComputedStyleSize(table, 'width');
2628
+ var tableParentWidth = getComputedStyleSize(table.parentElement, 'width');
2629
+ return tableWidth / tableParentWidth * 100;
2630
+ }
2631
+
2632
+ function getCellPercentDelta(table, delta) {
2633
+ var tableWidth = getComputedStyleSize(table, 'width');
2634
+ return delta / tableWidth * 100;
2635
+ }
2636
+
2637
+ function getTablePercentDelta(table, delta) {
2638
+ var tableParentWidth = getComputedStyleSize(table.parentElement, 'width');
2639
+ return delta / tableParentWidth * 100;
2640
+ }
2641
+
2642
+ // Find the left/right (ltr/rtl) or top side locations of the cells to measure.
2643
+ // This is the location of the borders we need to draw over.
2644
+ function findPositions(getInner, getOuter, thingsToMeasure) {
2645
+ var tablePositions = [];
2646
+
2647
+ // Skip the first item in the array = no left (LTR), right (RTL) or top bars
2648
+ for (var i = 1; i < thingsToMeasure.length; i++) {
2649
+ // Get the element from the details
2650
+ var item = thingsToMeasure[i].element;
2651
+
2652
+ // We need to zero index this again
2653
+ tablePositions.push(getInner(i - 1, item));
2654
+ }
2655
+
2656
+ var lastTableLineToMake = thingsToMeasure[thingsToMeasure.length - 1];
2657
+ tablePositions.push(getOuter(thingsToMeasure.length - 1, lastTableLineToMake.element));
2658
+
2659
+ return tablePositions;
2660
+ }
2661
+
2662
+ // Clear the bars.
2663
+ function clearBars() {
2664
+ var bars = editor.dom.select('.' + RESIZE_BAR_CLASS, getBody());
2665
+ Tools.each(bars, function(bar) {
2666
+ editor.dom.remove(bar);
2667
+ });
2668
+ }
2669
+
2670
+ // Refresh the bars.
2671
+ function refreshBars(tableElement) {
2672
+ clearBars();
2673
+ drawBars(tableElement);
2674
+ }
2675
+
2676
+ // Generates a resize bar object for the editor to add.
2677
+ function generateBar(classToAdd, cursor, left, top, height, width, indexAttr, index) {
2678
+ var bar = {
2679
+ 'data-mce-bogus': 'all',
2680
+ 'class': RESIZE_BAR_CLASS + ' ' + classToAdd,
2681
+ 'unselectable': 'on',
2682
+ 'data-mce-resize': false,
2683
+ style: 'cursor: ' + cursor + '; ' +
2684
+ 'margin: 0; ' +
2685
+ 'padding: 0; ' +
2686
+ 'position: absolute; ' +
2687
+ 'left: ' + left + 'px; ' +
2688
+ 'top: ' + top + 'px; ' +
2689
+ 'height: ' + height + 'px; ' +
2690
+ 'width: ' + width + 'px; '
2691
+ };
2692
+
2693
+ bar[indexAttr] = index;
2694
+
2695
+ return bar;
2696
+ }
2697
+
2698
+ // Draw the row bars over the row borders.
2699
+ function drawRows(rowPositions, tableWidth, tablePosition) {
2700
+ Tools.each(rowPositions, function(rowPosition) {
2701
+ var left = tablePosition.x,
2702
+ top = rowPosition.y - RESIZE_BAR_THICKNESS / 2,
2703
+ height = RESIZE_BAR_THICKNESS,
2704
+ width = tableWidth;
2705
+
2706
+ editor.dom.add(getBody(), 'div',
2707
+ generateBar(RESIZE_BAR_ROW_CLASS, RESIZE_BAR_ROW_CURSOR_STYLE,
2708
+ left, top, height, width, RESIZE_BAR_ROW_DATA_ATTRIBUTE, rowPosition.index));
2709
+ });
2710
+ }
2711
+
2712
+ // Draw the column bars over the column borders.
2713
+ function drawCols(cellPositions, tableHeight, tablePosition) {
2714
+ Tools.each(cellPositions, function(cellPosition) {
2715
+ var left = cellPosition.x - RESIZE_BAR_THICKNESS / 2,
2716
+ top = tablePosition.y,
2717
+ height = tableHeight,
2718
+ width = RESIZE_BAR_THICKNESS;
2719
+
2720
+ editor.dom.add(getBody(), 'div',
2721
+ generateBar(RESIZE_BAR_COL_CLASS, RESIZE_BAR_COL_CURSOR_STYLE,
2722
+ left, top, height, width, RESIZE_BAR_COL_DATA_ATTRIBUTE, cellPosition.index));
2723
+ });
2724
+ }
2725
+
2726
+ // Get a matrix of the cells in each row and the rows in the table.
2727
+ function getTableDetails(table) {
2728
+ return Tools.map(table.rows, function(row) {
2729
+
2730
+ var cells = Tools.map(row.cells, function(cell) {
2731
+
2732
+ var rowspan = cell.hasAttribute('rowspan') ? parseInt(cell.getAttribute('rowspan'), 10) : 1;
2733
+ var colspan = cell.hasAttribute('colspan') ? parseInt(cell.getAttribute('colspan'), 10) : 1;
2734
+
2735
+ return {
2736
+ element: cell,
2737
+ rowspan: rowspan,
2738
+ colspan: colspan
2739
+ };
2740
+ });
2741
+
2742
+ return {
2743
+ element: row,
2744
+ cells: cells
2745
+ };
2746
+
2747
+ });
2748
+
2749
+ }
2750
+
2751
+ // Get a grid model of the table.
2752
+ function getTableGrid(tableDetails) {
2753
+ function key(rowIndex, colIndex) {
2754
+ return rowIndex + ',' + colIndex;
2755
+ }
2756
+
2757
+ function getAt(rowIndex, colIndex) {
2758
+ return access[key(rowIndex, colIndex)];
2759
+ }
2760
+
2761
+ function getAllCells() {
2762
+ var allCells = [];
2763
+ Tools.each(rows, function(row) {
2764
+ allCells = allCells.concat(row.cells);
2765
+ });
2766
+ return allCells;
2767
+ }
2768
+
2769
+ function getAllRows() {
2770
+ return rows;
2771
+ }
2772
+
2773
+ var access = {};
2774
+ var rows = [];
2775
+
2776
+ var maxRows = 0;
2777
+ var maxCols = 0;
2778
+
2779
+ Tools.each(tableDetails, function(row, rowIndex) {
2780
+ var currentRow = [];
2781
+
2782
+ Tools.each(row.cells, function(cell) {
2783
+
2784
+ var start = 0;
2785
+
2786
+ while (access[key(rowIndex, start)] !== undefined) {
2787
+ start++;
2788
+ }
2789
+
2790
+ var current = {
2791
+ element: cell.element,
2792
+ colspan: cell.colspan,
2793
+ rowspan: cell.rowspan,
2794
+ rowIndex: rowIndex,
2795
+ colIndex: start
2796
+ };
2797
+
2798
+ for (var i = 0; i < cell.colspan; i++) {
2799
+ for (var j = 0; j < cell.rowspan; j++) {
2800
+ var cr = rowIndex + j;
2801
+ var cc = start + i;
2802
+ access[key(cr, cc)] = current;
2803
+ maxRows = Math.max(maxRows, cr + 1);
2804
+ maxCols = Math.max(maxCols, cc + 1);
2805
+ }
2806
+ }
2807
+
2808
+ currentRow.push(current);
2809
+ });
2810
+
2811
+ rows.push({
2812
+ element: row.element,
2813
+ cells: currentRow
2814
+ });
2815
+ });
2816
+
2817
+ return {
2818
+ grid: {
2819
+ maxRows: maxRows,
2820
+ maxCols: maxCols
2821
+ },
2822
+ getAt: getAt,
2823
+ getAllCells: getAllCells,
2824
+ getAllRows: getAllRows
2825
+ };
2826
+ }
2827
+
2828
+ function range(start, end) {
2829
+ var r = [];
2830
+
2831
+ for (var i = start; i < end; i++) {
2832
+ r.push(i);
2833
+ }
2834
+
2835
+ return r;
2836
+ }
2837
+
2838
+ // Attempt to get a representative single block for this column.
2839
+ // If we can't find a single block, all blocks in this row/column are spanned
2840
+ // and we'll need to fallback to getting the first cell in the row/column.
2841
+ function decide(getBlock, isSingle, getFallback) {
2842
+ var inBlock = getBlock();
2843
+ var singleInBlock;
2844
+
2845
+ for (var i = 0; i < inBlock.length; i++) {
2846
+ if (isSingle(inBlock[i])) {
2847
+ singleInBlock = inBlock[i];
2848
+ }
2849
+ }
2850
+ return singleInBlock ? singleInBlock : getFallback();
2851
+ }
2852
+
2853
+ // Attempt to get representative blocks for the width of each column.
2854
+ function getColumnBlocks(tableGrid) {
2855
+ var cols = range(0, tableGrid.grid.maxCols);
2856
+ var rows = range(0, tableGrid.grid.maxRows);
2857
+
2858
+ return Tools.map(cols, function(col) {
2859
+ function getBlock() {
2860
+ var details = [];
2861
+ for (var i = 0; i < rows.length; i++) {
2862
+ var detail = tableGrid.getAt(i, col);
2863
+ if (detail && detail.colIndex === col) {
2864
+ details.push(detail);
2865
+ }
2866
+ }
2867
+
2868
+ return details;
2869
+ }
2870
+
2871
+ function isSingle(detail) {
2872
+ return detail.colspan === 1;
2873
+ }
2874
+
2875
+ function getFallback() {
2876
+ var item;
2877
+
2878
+ for (var i = 0; i < rows.length; i++) {
2879
+ item = tableGrid.getAt(i, col);
2880
+ if (item) {
2881
+ return item;
2882
+ }
2883
+ }
2884
+
2885
+ return null;
2886
+ }
2887
+
2888
+ return decide(getBlock, isSingle, getFallback);
2889
+ });
2890
+ }
2891
+
2892
+ // Attempt to get representative blocks for the height of each row.
2893
+ function getRowBlocks(tableGrid) {
2894
+ var cols = range(0, tableGrid.grid.maxCols);
2895
+ var rows = range(0, tableGrid.grid.maxRows);
2896
+
2897
+ return Tools.map(rows, function(row) {
2898
+ function getBlock() {
2899
+ var details = [];
2900
+ for (var i = 0; i < cols.length; i++) {
2901
+ var detail = tableGrid.getAt(row, i);
2902
+ if (detail && detail.rowIndex === row) {
2903
+ details.push(detail);
2904
+ }
2905
+ }
2906
+ return details;
2907
+ }
2908
+
2909
+ function isSingle(detail) {
2910
+ return detail.rowspan === 1;
2911
+ }
2912
+
2913
+ function getFallback() {
2914
+ return tableGrid.getAt(row, 0);
2915
+ }
2916
+
2917
+ return decide(getBlock, isSingle, getFallback);
2918
+ });
2919
+ }
2920
+
2921
+ // Draw resize bars over the left/right (ltr/rtl) or top side locations of the cells to measure.
2922
+ // This is the location of the borders we need to draw over.
2923
+ function drawBars(table) {
2924
+ var tableDetails = getTableDetails(table);
2925
+ var tableGrid = getTableGrid(tableDetails);
2926
+ var rows = getRowBlocks(tableGrid);
2927
+ var cols = getColumnBlocks(tableGrid);
2928
+
2929
+ var tablePosition = editor.dom.getPos(table);
2930
+ var rowPositions = rows.length > 0 ? findPositions(getTopEdge, getBottomEdge, rows) : [];
2931
+ var colPositions = cols.length > 0 ? findPositions(getInnerEdge, getOuterEdge, cols) : [];
2932
+
2933
+ drawRows(rowPositions, table.offsetWidth, tablePosition);
2934
+ drawCols(colPositions, table.offsetHeight, tablePosition);
2935
+ }
2936
+
2937
+ // Attempt to deduce the width/height of a column/row that has more than one cell spanned.
2938
+ function deduceSize(deducables, index, isPercentageBased, table) {
2939
+ if (index < 0 || index >= deducables.length - 1) {
2940
+ return "";
2941
+ }
2942
+
2943
+ var current = deducables[index];
2944
+
2945
+ if (current) {
2946
+ current = {
2947
+ value: current,
2948
+ delta: 0
2949
+ };
2950
+ } else {
2951
+ var reversedUpToIndex = deducables.slice(0, index).reverse();
2952
+ for (var i = 0; i < reversedUpToIndex.length; i++) {
2953
+ if (reversedUpToIndex[i]) {
2954
+ current = {
2955
+ value: reversedUpToIndex[i],
2956
+ delta: i + 1
2957
+ };
2958
+ }
2959
+ }
2960
+ }
2961
+
2962
+ var next = deducables[index + 1];
2963
+
2964
+ if (next) {
2965
+ next = {
2966
+ value: next,
2967
+ delta: 1
2968
+ };
2969
+ } else {
2970
+ var rest = deducables.slice(index + 1);
2971
+ for (var j = 0; j < rest.length; j++) {
2972
+ if (rest[j]) {
2973
+ next = {
2974
+ value: rest[j],
2975
+ delta: j + 1
2976
+ };
2977
+ }
2978
+ }
2979
+ }
2980
+
2981
+ var extras = next.delta - current.delta;
2982
+ var pixelWidth = Math.abs(next.value - current.value) / extras;
2983
+ return isPercentageBased ? pixelWidth / getComputedStyleSize(table, 'width') * 100 : pixelWidth;
2984
+ }
2985
+
2986
+ function getStyleOrAttrib(element, property) {
2987
+ var sizeString = editor.dom.getStyle(element, property);
2988
+ if (!sizeString) {
2989
+ sizeString = editor.dom.getAttrib(element, property);
2990
+ }
2991
+ if (!sizeString) {
2992
+ sizeString = editor.dom.getStyle(element, property, true);
2993
+ }
2994
+ return sizeString;
2995
+ }
2996
+
2997
+ function getWidth(element, isPercentageBased, table) {
2998
+ var widthString = getStyleOrAttrib(element, 'width');
2999
+
3000
+ var widthNumber = parseInt(widthString, 10);
3001
+
3002
+ var getWidthFallback = isPercentageBased ? getPercentageWidthFallback(element, table) : getComputedStyleSize(element, 'width');
3003
+
3004
+ // If this is percentage based table, but this cell isn't percentage based.
3005
+ // Or if this is a pixel based table, but this cell isn't pixel based.
3006
+ if (isPercentageBased && !isPercentageBasedSize(widthString) ||
3007
+ !isPercentageBased && !isPixelBasedSize(widthString)) {
3008
+ // set the widthnumber to 0
3009
+ widthNumber = 0;
3010
+ }
3011
+
3012
+ return !isNaN(widthNumber) && widthNumber > 0 ?
3013
+ widthNumber : getWidthFallback;
3014
+ }
3015
+
3016
+ // Attempt to get the css width from column representative cells.
3017
+ function getWidths(tableGrid, isPercentageBased, table) {
3018
+
3019
+ var cols = getColumnBlocks(tableGrid);
3020
+
3021
+ var backups = Tools.map(cols, function(col) {
3022
+ return getInnerEdge(col.colIndex, col.element).x;
3023
+ });
3024
+
3025
+ var widths = [];
3026
+
3027
+ for (var i = 0; i < cols.length; i++) {
3028
+ var span = cols[i].element.hasAttribute('colspan') ? parseInt(cols[i].element.getAttribute('colspan'), 10) : 1;
3029
+ // Deduce if the column has colspan of more than 1
3030
+ var width = span > 1 ? deduceSize(backups, i) : getWidth(cols[i].element, isPercentageBased, table);
3031
+ // If everything's failed and we still don't have a width
3032
+ width = width ? width : RESIZE_MINIMUM_WIDTH;
3033
+ widths.push(width);
3034
+ }
3035
+
3036
+ return widths;
3037
+ }
3038
+
3039
+ // Attempt to get the pixel height from a cell.
3040
+ function getPixelHeight(element) {
3041
+
3042
+ var heightString = getStyleOrAttrib(element, 'height');
3043
+
3044
+ var heightNumber = parseInt(heightString, 10);
3045
+
3046
+ if (isPercentageBasedSize(heightString)) {
3047
+ heightNumber = 0;
3048
+ }
3049
+
3050
+ return !isNaN(heightNumber) && heightNumber > 0 ?
3051
+ heightNumber : getComputedStyleSize(element, 'height');
3052
+ }
3053
+
3054
+ // Attempt to get the css height from row representative cells.
3055
+ function getPixelHeights(tableGrid) {
3056
+
3057
+ var rows = getRowBlocks(tableGrid);
3058
+
3059
+ var backups = Tools.map(rows, function(row) {
3060
+ return getTopEdge(row.rowIndex, row.element).y;
3061
+ });
3062
+
3063
+ var heights = [];
3064
+
3065
+ for (var i = 0; i < rows.length; i++) {
3066
+ var span = rows[i].element.hasAttribute('rowspan') ? parseInt(rows[i].element.getAttribute('rowspan'), 10) : 1;
3067
+
3068
+ var height = span > 1 ? deduceSize(backups, i) : getPixelHeight(rows[i].element);
3069
+
3070
+ height = height ? height : RESIZE_MINIMUM_HEIGHT;
3071
+ heights.push(height);
3072
+ }
3073
+
3074
+ return heights;
3075
+ }
3076
+
3077
+ // Determine how much each column's css width will need to change.
3078
+ // Sizes = result = pixels widths OR percentage based widths
3079
+ function determineDeltas(sizes, column, step, min, isPercentageBased) {
3080
+
3081
+ var result = sizes.slice(0);
3082
+
3083
+ function generateZeros(array) {
3084
+ return Tools.map(array, function() {
3085
+ return 0;
3086
+ });
3087
+ }
3088
+
3089
+ function onOneColumn() {
3090
+ var deltas;
3091
+ if (isPercentageBased) {
3092
+ // If we have one column in a percent based table, that column should be 100% of the width of the table.
3093
+ deltas = [100 - result[0]];
3094
+ } else {
3095
+ var newNext = Math.max(min, result[0] + step);
3096
+ deltas = [newNext - result[0]];
3097
+ }
3098
+ return deltas;
3099
+ }
3100
+
3101
+ function onLeftOrMiddle(index, next) {
3102
+
3103
+ var startZeros = generateZeros(result.slice(0, index));
3104
+ var endZeros = generateZeros(result.slice(next + 1));
3105
+ var deltas;
3106
+
3107
+ if (step >= 0) {
3108
+ var newNext = Math.max(min, result[next] - step);
3109
+ deltas = startZeros.concat([step, newNext - result[next]]).concat(endZeros);
3110
+ } else {
3111
+ var newThis = Math.max(min, result[index] + step);
3112
+ var diffx = result[index] - newThis;
3113
+ deltas = startZeros.concat([newThis - result[index], diffx]).concat(endZeros);
3114
+ }
3115
+
3116
+ return deltas;
3117
+ }
3118
+
3119
+ function onRight(previous, index) {
3120
+ var startZeros = generateZeros(result.slice(0, index));
3121
+ var deltas;
3122
+
3123
+ if (step >= 0) {
3124
+ deltas = startZeros.concat([step]);
3125
+ } else {
3126
+ var size = Math.max(min, result[index] + step);
3127
+ deltas = startZeros.concat([size - result[index]]);
3128
+ }
3129
+
3130
+ return deltas;
3131
+
3132
+ }
3133
+
3134
+ var deltas;
3135
+
3136
+ if (sizes.length === 0) { // No Columns
3137
+ deltas = [];
3138
+ } else if (sizes.length === 1) { // One Column
3139
+ deltas = onOneColumn();
3140
+ } else if (column === 0) { // Left Column
3141
+ deltas = onLeftOrMiddle(0, 1);
3142
+ } else if (column > 0 && column < sizes.length - 1) { // Middle Column
3143
+ deltas = onLeftOrMiddle(column, column + 1);
3144
+ } else if (column === sizes.length - 1) { // Right Column
3145
+ deltas = onRight(column - 1, column);
3146
+ } else {
3147
+ deltas = [];
3148
+ }
3149
+
3150
+ return deltas;
3151
+ }
3152
+
3153
+ function total(start, end, measures) {
3154
+ var r = 0;
3155
+ for (var i = start; i < end; i++) {
3156
+ r += measures[i];
3157
+ }
3158
+ return r;
3159
+ }
3160
+
3161
+ // Combine cell's css widths to determine widths of colspan'd cells.
3162
+ function recalculateWidths(tableGrid, widths) {
3163
+ var allCells = tableGrid.getAllCells();
3164
+ return Tools.map(allCells, function(cell) {
3165
+ var width = total(cell.colIndex, cell.colIndex + cell.colspan, widths);
3166
+ return {
3167
+ element: cell.element,
3168
+ width: width,
3169
+ colspan: cell.colspan
3170
+ };
3171
+ });
3172
+ }
3173
+
3174
+ // Combine cell's css heights to determine heights of rowspan'd cells.
3175
+ function recalculateCellHeights(tableGrid, heights) {
3176
+ var allCells = tableGrid.getAllCells();
3177
+ return Tools.map(allCells, function(cell) {
3178
+ var height = total(cell.rowIndex, cell.rowIndex + cell.rowspan, heights);
3179
+ return {
3180
+ element: cell.element,
3181
+ height: height,
3182
+ rowspan: cell.rowspan
3183
+ };
3184
+ });
3185
+ }
3186
+
3187
+ // Calculate row heights.
3188
+ function recalculateRowHeights(tableGrid, heights) {
3189
+ var allRows = tableGrid.getAllRows();
3190
+ return Tools.map(allRows, function(row, i) {
3191
+ return {
3192
+ element: row.element,
3193
+ height: heights[i]
3194
+ };
3195
+ });
3196
+ }
3197
+
3198
+ function isPercentageBasedSize(size) {
3199
+ return percentageBasedSizeRegex.test(size);
3200
+ }
3201
+
3202
+ function isPixelBasedSize(size) {
3203
+ return pixelBasedSizeRegex.test(size);
3204
+ }
3205
+
3206
+ // Adjust the width of the column of table at index, with delta.
3207
+ function adjustWidth(table, delta, index) {
3208
+ var tableDetails = getTableDetails(table);
3209
+ var tableGrid = getTableGrid(tableDetails);
3210
+
3211
+ function setSizes(newSizes, styleExtension) {
3212
+ Tools.each(newSizes, function(cell) {
3213
+ editor.dom.setStyle(cell.element, 'width', cell.width + styleExtension);
3214
+ editor.dom.setAttrib(cell.element, 'width', null);
3215
+ });
3216
+ }
3217
+
3218
+ function getNewTablePercentWidth() {
3219
+ return index < tableGrid.grid.maxCols - 1 ? getCurrentTablePercentWidth(table) :
3220
+ getCurrentTablePercentWidth(table) + getTablePercentDelta(table, delta);
3221
+ }
3222
+
3223
+ function getNewTablePixelWidth() {
3224
+ return index < tableGrid.grid.maxCols - 1 ? getComputedStyleSize(table, 'width') :
3225
+ getComputedStyleSize(table, 'width') + delta;
3226
+ }
3227
+
3228
+ function setTableSize(newTableWidth, styleExtension, isPercentBased) {
3229
+ if (index == tableGrid.grid.maxCols - 1 || !isPercentBased) {
3230
+ editor.dom.setStyle(table, 'width', newTableWidth + styleExtension);
3231
+ editor.dom.setAttrib(table, 'width', null);
3232
+ }
3233
+ }
3234
+
3235
+ var percentageBased = isPercentageBasedSize(table.width) ||
3236
+ isPercentageBasedSize(table.style.width);
3237
+
3238
+ var widths = getWidths(tableGrid, percentageBased, table);
3239
+
3240
+ var step = percentageBased ? getCellPercentDelta(table, delta) : delta;
3241
+ // TODO: change the min for percentage maybe?
3242
+ var deltas = determineDeltas(widths, index, step, RESIZE_MINIMUM_WIDTH, percentageBased, table);
3243
+ var newWidths = [];
3244
+
3245
+ for (var i = 0; i < deltas.length; i++) {
3246
+ newWidths.push(deltas[i] + widths[i]);
3247
+ }
3248
+
3249
+ var newSizes = recalculateWidths(tableGrid, newWidths);
3250
+ var styleExtension = percentageBased ? '%' : 'px';
3251
+ var newTableWidth = percentageBased ? getNewTablePercentWidth() :
3252
+ getNewTablePixelWidth();
3253
+
3254
+ editor.undoManager.transact(function() {
3255
+ setSizes(newSizes, styleExtension);
3256
+ setTableSize(newTableWidth, styleExtension, percentageBased);
3257
+ });
3258
+ }
3259
+
3260
+ // Adjust the height of the row of table at index, with delta.
3261
+ function adjustHeight(table, delta, index) {
3262
+ var tableDetails = getTableDetails(table);
3263
+ var tableGrid = getTableGrid(tableDetails);
3264
+
3265
+ var heights = getPixelHeights(tableGrid);
3266
+
3267
+ var newHeights = [], newTotalHeight = 0;
3268
+
3269
+ for (var i = 0; i < heights.length; i++) {
3270
+ newHeights.push(i === index ? delta + heights[i] : heights[i]);
3271
+ newTotalHeight += newTotalHeight[i];
3272
+ }
3273
+
3274
+ var newCellSizes = recalculateCellHeights(tableGrid, newHeights);
3275
+ var newRowSizes = recalculateRowHeights(tableGrid, newHeights);
3276
+
3277
+ editor.undoManager.transact(function() {
3278
+
3279
+ Tools.each(newRowSizes, function(row) {
3280
+ editor.dom.setStyle(row.element, 'height', row.height + 'px');
3281
+ editor.dom.setAttrib(row.element, 'height', null);
3282
+ });
3283
+
3284
+ Tools.each(newCellSizes, function(cell) {
3285
+ editor.dom.setStyle(cell.element, 'height', cell.height + 'px');
3286
+ editor.dom.setAttrib(cell.element, 'height', null);
3287
+ });
3288
+
3289
+ editor.dom.setStyle(table, 'height', newTotalHeight + 'px');
3290
+ editor.dom.setAttrib(table, 'height', null);
3291
+ });
3292
+ }
3293
+
3294
+ function scheduleDelayedDropEvent() {
3295
+ delayDrop = setTimeout(function() {
3296
+ drop();
3297
+ }, 200);
3298
+ }
3299
+
3300
+ function cancelDelayedDropEvent() {
3301
+ clearTimeout(delayDrop);
3302
+ }
3303
+
3304
+ function getBlockerElement() {
3305
+ var blocker = document.createElement('div');
3306
+
3307
+ blocker.setAttribute('style', 'margin: 0; ' +
3308
+ 'padding: 0; ' +
3309
+ 'position: fixed; ' +
3310
+ 'left: 0px; ' +
3311
+ 'top: 0px; ' +
3312
+ 'height: 100%; ' +
3313
+ 'width: 100%;');
3314
+ blocker.setAttribute('data-mce-bogus', 'all');
3315
+
3316
+ return blocker;
3317
+ }
3318
+
3319
+ function bindBlockerEvents(blocker, dragHandler) {
3320
+ editor.dom.bind(blocker, 'mouseup', function() {
3321
+ drop();
3322
+ });
3323
+
3324
+ editor.dom.bind(blocker, 'mousemove', function(e) {
3325
+ cancelDelayedDropEvent();
3326
+
3327
+ if (dragging) {
3328
+ dragHandler(e);
3329
+ }
3330
+ });
3331
+
3332
+ editor.dom.bind(blocker, 'mouseout', function() {
3333
+ scheduleDelayedDropEvent();
3334
+ });
3335
+
3336
+ }
3337
+
3338
+ function drop() {
3339
+ editor.dom.remove(blockerElement);
3340
+
3341
+ if (dragging) {
3342
+ editor.dom.removeClass(dragBar, RESIZE_BAR_DRAGGING_CLASS);
3343
+ dragging = false;
3344
+
3345
+ var index, delta;
3346
+
3347
+ if (isCol(dragBar)) {
3348
+ var initialLeft = parseInt(editor.dom.getAttrib(dragBar, RESIZE_BAR_COL_DATA_INITIAL_LEFT_ATTRIBUTE), 10);
3349
+ var newLeft = editor.dom.getPos(dragBar).x;
3350
+ index = parseInt(editor.dom.getAttrib(dragBar, RESIZE_BAR_COL_DATA_ATTRIBUTE), 10);
3351
+ delta = isRtl() ? initialLeft - newLeft : newLeft - initialLeft;
3352
+ adjustWidth(hoverTable, delta, index);
3353
+ } else if (isRow(dragBar)) {
3354
+ var initialTop = parseInt(editor.dom.getAttrib(dragBar, RESIZE_BAR_ROW_DATA_INITIAL_TOP_ATTRIBUTE), 10);
3355
+ var newTop = editor.dom.getPos(dragBar).y;
3356
+ index = parseInt(editor.dom.getAttrib(dragBar, RESIZE_BAR_ROW_DATA_ATTRIBUTE), 10);
3357
+ delta = newTop - initialTop;
3358
+ adjustHeight(hoverTable, delta, index);
3359
+ }
3360
+ refreshBars(hoverTable);
3361
+ editor.nodeChanged();
3362
+ }
3363
+ }
3364
+
3365
+ function setupBaseDrag(bar, dragHandler) {
3366
+ blockerElement = blockerElement ? blockerElement : getBlockerElement();
3367
+ dragging = true;
3368
+ editor.dom.addClass(bar, RESIZE_BAR_DRAGGING_CLASS);
3369
+ dragBar = bar;
3370
+ bindBlockerEvents(blockerElement, dragHandler);
3371
+ editor.dom.add(getBody(), blockerElement);
3372
+ }
3373
+
3374
+ function isCol(target) {
3375
+ return editor.dom.hasClass(target, RESIZE_BAR_COL_CLASS);
3376
+ }
3377
+
3378
+ function isRow(target) {
3379
+ return editor.dom.hasClass(target, RESIZE_BAR_ROW_CLASS);
3380
+ }
3381
+
3382
+ function colDragHandler(event) {
3383
+ lastX = lastX !== undefined ? lastX : event.clientX; // we need a firstX
3384
+ var deltaX = event.clientX - lastX;
3385
+ lastX = event.clientX;
3386
+ var oldLeft = editor.dom.getPos(dragBar).x;
3387
+ editor.dom.setStyle(dragBar, 'left', oldLeft + deltaX + 'px');
3388
+ }
3389
+
3390
+ function rowDragHandler(event) {
3391
+ lastY = lastY !== undefined ? lastY : event.clientY;
3392
+ var deltaY = event.clientY - lastY;
3393
+ lastY = event.clientY;
3394
+ var oldTop = editor.dom.getPos(dragBar).y;
3395
+ editor.dom.setStyle(dragBar, 'top', oldTop + deltaY + 'px');
3396
+ }
3397
+
3398
+ function setupColDrag(bar) {
3399
+ lastX = undefined;
3400
+ setupBaseDrag(bar, colDragHandler);
3401
+ }
3402
+
3403
+ function setupRowDrag(bar) {
3404
+ lastY = undefined;
3405
+ setupBaseDrag(bar, rowDragHandler);
3406
+ }
3407
+
3408
+ function mouseDownHandler(e) {
3409
+ var target = e.target, body = editor.getBody();
3410
+
3411
+ // Since this code is working on global events we need to work on a global hoverTable state
3412
+ // and make sure that the state is correct according to the events fired
3413
+ if (!editor.$.contains(body, hoverTable) && hoverTable !== body) {
3414
+ return;
3415
+ }
3416
+
3417
+ if (isCol(target)) {
3418
+ e.preventDefault();
3419
+ var initialLeft = editor.dom.getPos(target).x;
3420
+ editor.dom.setAttrib(target, RESIZE_BAR_COL_DATA_INITIAL_LEFT_ATTRIBUTE, initialLeft);
3421
+ setupColDrag(target);
3422
+ } else if (isRow(target)) {
3423
+ e.preventDefault();
3424
+ var initialTop = editor.dom.getPos(target).y;
3425
+ editor.dom.setAttrib(target, RESIZE_BAR_ROW_DATA_INITIAL_TOP_ATTRIBUTE, initialTop);
3426
+ setupRowDrag(target);
3427
+ }
3428
+ }
3429
+
3430
+ editor.on('init', function() {
3431
+ // Needs to be like this for inline mode, editor.on does not bind to elements in the document body otherwise
3432
+ editor.dom.bind(getBody(), 'mousedown', mouseDownHandler);
3433
+ });
3434
+
3435
+ // If we're updating the table width via the old mechanic, we need to update the constituent cells' widths/heights too.
3436
+ editor.on('ObjectResized', function(e) {
3437
+ var table = e.target;
3438
+ if (table.nodeName === 'TABLE') {
3439
+ var newCellSizes = [];
3440
+ Tools.each(table.rows, function(row) {
3441
+ Tools.each(row.cells, function(cell) {
3442
+ var width = editor.dom.getStyle(cell, 'width', true);
3443
+ newCellSizes.push({
3444
+ cell: cell,
3445
+ width: width
3446
+ });
3447
+ });
3448
+ });
3449
+ Tools.each(newCellSizes, function(newCellSize) {
3450
+ editor.dom.setStyle(newCellSize.cell, 'width', newCellSize.width);
3451
+ editor.dom.setAttrib(newCellSize.cell, 'width', null);
3452
+ });
3453
+ }
3454
+ });
3455
+
3456
+ editor.on('mouseover', function(e) {
3457
+ if (!dragging) {
3458
+ var tableElement = editor.dom.getParent(e.target, 'table');
3459
+
3460
+ if (e.target.nodeName === 'TABLE' || tableElement) {
3461
+ hoverTable = tableElement;
3462
+ refreshBars(tableElement);
3463
+ }
3464
+ }
3465
+ });
3466
+
3467
+ // Prevents the user from moving the caret inside the resize bars on Chrome
3468
+ // Only does it on arrow keys since clearBars might be an epxensive operation
3469
+ // since it's querying the DOM
3470
+ editor.on('keydown', function(e) {
3471
+ switch (e.keyCode) {
3472
+ case VK.LEFT:
3473
+ case VK.RIGHT:
3474
+ case VK.UP:
3475
+ case VK.DOWN:
3476
+ clearBars();
3477
+ break;
3478
+ }
3479
+ });
3480
+
3481
+ editor.on('remove', function() {
3482
+ clearBars();
3483
+ editor.dom.unbind(getBody(), 'mousedown', mouseDownHandler);
3484
+ });
3485
+
3486
+ return {
3487
+ adjustWidth: adjustWidth,
3488
+ adjustHeight: adjustHeight,
3489
+ clearBars: clearBars,
3490
+ drawBars: drawBars,
3491
+ determineDeltas: determineDeltas,
3492
+ getTableGrid: getTableGrid,
3493
+ getTableDetails: getTableDetails,
3494
+ getWidths: getWidths,
3495
+ getPixelHeights: getPixelHeights,
3496
+ isPercentageBasedSize: isPercentageBasedSize,
3497
+ isPixelBasedSize: isPixelBasedSize,
3498
+ recalculateWidths: recalculateWidths,
3499
+ recalculateCellHeights: recalculateCellHeights,
3500
+ recalculateRowHeights: recalculateRowHeights
3501
+ };
3502
+ };
3503
+ });
3504
+
3505
+ // Included from: js/tinymce/plugins/table/classes/Plugin.js
3506
+
3507
+ /**
3508
+ * Plugin.js
3509
+ *
3510
+ * Released under LGPL License.
3511
+ * Copyright (c) 1999-2015 Ephox Corp. All rights reserved
3512
+ *
3513
+ * License: http://www.tinymce.com/license
3514
+ * Contributing: http://www.tinymce.com/contributing
3515
+ */
3516
+
3517
+ /**
3518
+ * This class contains all core logic for the table plugin.
3519
+ *
3520
+ * @class tinymce.tableplugin.Plugin
3521
+ * @private
3522
+ */
3523
+ define("tinymce/tableplugin/Plugin", [
3524
+ "tinymce/tableplugin/TableGrid",
3525
+ "tinymce/tableplugin/Quirks",
3526
+ "tinymce/tableplugin/CellSelection",
3527
+ "tinymce/tableplugin/Dialogs",
3528
+ "tinymce/tableplugin/ResizeBars",
3529
+ "tinymce/util/Tools",
3530
+ "tinymce/dom/TreeWalker",
3531
+ "tinymce/Env",
3532
+ "tinymce/PluginManager"
3533
+ ], function(TableGrid, Quirks, CellSelection, Dialogs, ResizeBars, Tools, TreeWalker, Env, PluginManager) {
3534
+ var each = Tools.each;
3535
+
3536
+ function Plugin(editor) {
3537
+ var clipboardRows, self = this, dialogs = new Dialogs(editor), resizeBars;
3538
+
3539
+ if (editor.settings.object_resizing && editor.settings.table_resize_bars !== false &&
3540
+ (editor.settings.object_resizing === true || editor.settings.object_resizing === 'table')) {
3541
+ resizeBars = ResizeBars(editor);
3542
+ }
3543
+
3544
+ function cmd(command) {
3545
+ return function() {
3546
+ editor.execCommand(command);
3547
+ };
3548
+ }
3549
+
3550
+ function insertTable(cols, rows) {
3551
+ var y, x, html, tableElm;
3552
+
3553
+ html = '<table id="__mce"><tbody>';
3554
+
3555
+ for (y = 0; y < rows; y++) {
3556
+ html += '<tr>';
3557
+
3558
+ for (x = 0; x < cols; x++) {
3559
+ html += '<td>' + (Env.ie && Env.ie < 10 ? '&nbsp;' : '<br>') + '</td>';
3560
+ }
3561
+
3562
+ html += '</tr>';
3563
+ }
3564
+
3565
+ html += '</tbody></table>';
3566
+
3567
+ editor.undoManager.transact(function() {
3568
+ editor.insertContent(html);
3569
+
3570
+ tableElm = editor.dom.get('__mce');
3571
+ editor.dom.setAttrib(tableElm, 'id', null);
3572
+
3573
+ editor.$('tr', tableElm).each(function(index, row) {
3574
+ editor.fire('newrow', {
3575
+ node: row
3576
+ });
3577
+
3578
+ editor.$('th,td', row).each(function(index, cell) {
3579
+ editor.fire('newcell', {
3580
+ node: cell
3581
+ });
3582
+ });
3583
+ });
3584
+
3585
+ editor.dom.setAttribs(tableElm, editor.settings.table_default_attributes || {});
3586
+ editor.dom.setStyles(tableElm, editor.settings.table_default_styles || {});
3587
+ });
3588
+
3589
+ return tableElm;
3590
+ }
3591
+
3592
+ function handleDisabledState(ctrl, selector, sameParts) {
3593
+ function bindStateListener() {
3594
+ var selectedElm, selectedCells, parts = {}, sum = 0, state;
3595
+
3596
+ selectedCells = editor.dom.select('td[data-mce-selected],th[data-mce-selected]');
3597
+ selectedElm = selectedCells[0];
3598
+ if (!selectedElm) {
3599
+ selectedElm = editor.selection.getStart();
3600
+ }
3601
+
3602
+ // Make sure that we don't have a selection inside thead and tbody at the same time
3603
+ if (sameParts && selectedCells.length > 0) {
3604
+ each(selectedCells, function(cell) {
3605
+ return parts[cell.parentNode.parentNode.nodeName] = 1;
3606
+ });
3607
+
3608
+ each(parts, function(value) {
3609
+ sum += value;
3610
+ });
3611
+
3612
+ state = sum !== 1;
3613
+ } else {
3614
+ state = !editor.dom.getParent(selectedElm, selector);
3615
+ }
3616
+
3617
+ ctrl.disabled(state);
3618
+
3619
+ editor.selection.selectorChanged(selector, function(state) {
3620
+ ctrl.disabled(!state);
3621
+ });
3622
+ }
3623
+
3624
+ if (editor.initialized) {
3625
+ bindStateListener();
3626
+ } else {
3627
+ editor.on('init', bindStateListener);
3628
+ }
3629
+ }
3630
+
3631
+ function postRender() {
3632
+ /*jshint validthis:true*/
3633
+ handleDisabledState(this, 'table');
3634
+ }
3635
+
3636
+ function postRenderCell() {
3637
+ /*jshint validthis:true*/
3638
+ handleDisabledState(this, 'td,th');
3639
+ }
3640
+
3641
+ function postRenderMergeCell() {
3642
+ /*jshint validthis:true*/
3643
+ handleDisabledState(this, 'td,th', true);
3644
+ }
3645
+
3646
+ function generateTableGrid() {
3647
+ var html = '';
3648
+
3649
+ html = '<table role="grid" class="mce-grid mce-grid-border" aria-readonly="true">';
3650
+
3651
+ for (var y = 0; y < 10; y++) {
3652
+ html += '<tr>';
3653
+
3654
+ for (var x = 0; x < 10; x++) {
3655
+ html += '<td role="gridcell" tabindex="-1"><a id="mcegrid' + (y * 10 + x) + '" href="#" ' +
3656
+ 'data-mce-x="' + x + '" data-mce-y="' + y + '"></a></td>';
3657
+ }
3658
+
3659
+ html += '</tr>';
3660
+ }
3661
+
3662
+ html += '</table>';
3663
+
3664
+ html += '<div class="mce-text-center" role="presentation">1 x 1</div>';
3665
+
3666
+ return html;
3667
+ }
3668
+
3669
+ function selectGrid(tx, ty, control) {
3670
+ var table = control.getEl().getElementsByTagName('table')[0];
3671
+ var x, y, focusCell, cell, active;
3672
+ var rtl = control.isRtl() || control.parent().rel == 'tl-tr';
3673
+
3674
+ table.nextSibling.innerHTML = (tx + 1) + ' x ' + (ty + 1);
3675
+
3676
+ if (rtl) {
3677
+ tx = 9 - tx;
3678
+ }
3679
+
3680
+ for (y = 0; y < 10; y++) {
3681
+ for (x = 0; x < 10; x++) {
3682
+ cell = table.rows[y].childNodes[x].firstChild;
3683
+ active = (rtl ? x >= tx : x <= tx) && y <= ty;
3684
+
3685
+ editor.dom.toggleClass(cell, 'mce-active', active);
3686
+
3687
+ if (active) {
3688
+ focusCell = cell;
3689
+ }
3690
+ }
3691
+ }
3692
+
3693
+ return focusCell.parentNode;
3694
+ }
3695
+
3696
+ if (editor.settings.table_grid === false) {
3697
+ editor.addMenuItem('inserttable', {
3698
+ text: 'Insert table',
3699
+ icon: 'table',
3700
+ context: 'table',
3701
+ onclick: dialogs.table
3702
+ });
3703
+ } else {
3704
+ editor.addMenuItem('inserttable', {
3705
+ text: 'Insert table',
3706
+ icon: 'table',
3707
+ context: 'table',
3708
+ ariaHideMenu: true,
3709
+ onclick: function(e) {
3710
+ if (e.aria) {
3711
+ this.parent().hideAll();
3712
+ e.stopImmediatePropagation();
3713
+ dialogs.table();
3714
+ }
3715
+ },
3716
+ onshow: function() {
3717
+ selectGrid(0, 0, this.menu.items()[0]);
3718
+ },
3719
+ onhide: function() {
3720
+ var elements = this.menu.items()[0].getEl().getElementsByTagName('a');
3721
+ editor.dom.removeClass(elements, 'mce-active');
3722
+ editor.dom.addClass(elements[0], 'mce-active');
3723
+ },
3724
+ menu: [
3725
+ {
3726
+ type: 'container',
3727
+ html: generateTableGrid(),
3728
+
3729
+ onPostRender: function() {
3730
+ this.lastX = this.lastY = 0;
3731
+ },
3732
+
3733
+ onmousemove: function(e) {
3734
+ var target = e.target, x, y;
3735
+
3736
+ if (target.tagName.toUpperCase() == 'A') {
3737
+ x = parseInt(target.getAttribute('data-mce-x'), 10);
3738
+ y = parseInt(target.getAttribute('data-mce-y'), 10);
3739
+
3740
+ if (this.isRtl() || this.parent().rel == 'tl-tr') {
3741
+ x = 9 - x;
3742
+ }
3743
+
3744
+ if (x !== this.lastX || y !== this.lastY) {
3745
+ selectGrid(x, y, e.control);
3746
+
3747
+ this.lastX = x;
3748
+ this.lastY = y;
3749
+ }
3750
+ }
3751
+ },
3752
+
3753
+ onclick: function(e) {
3754
+ var self = this;
3755
+
3756
+ if (e.target.tagName.toUpperCase() == 'A') {
3757
+ e.preventDefault();
3758
+ e.stopPropagation();
3759
+ self.parent().cancel();
3760
+
3761
+ editor.undoManager.transact(function() {
3762
+ insertTable(self.lastX + 1, self.lastY + 1);
3763
+ });
3764
+
3765
+ editor.addVisual();
3766
+ }
3767
+ }
3768
+ }
3769
+ ]
3770
+ });
3771
+ }
3772
+
3773
+ editor.addMenuItem('tableprops', {
3774
+ text: 'Table properties',
3775
+ context: 'table',
3776
+ onPostRender: postRender,
3777
+ onclick: dialogs.tableProps
3778
+ });
3779
+
3780
+ editor.addMenuItem('deletetable', {
3781
+ text: 'Delete table',
3782
+ context: 'table',
3783
+ onPostRender: postRender,
3784
+ cmd: 'mceTableDelete'
3785
+ });
3786
+
3787
+ editor.addMenuItem('cell', {
3788
+ separator: 'before',
3789
+ text: 'Cell',
3790
+ context: 'table',
3791
+ menu: [
3792
+ {text: 'Cell properties', onclick: cmd('mceTableCellProps'), onPostRender: postRenderCell},
3793
+ {text: 'Merge cells', onclick: cmd('mceTableMergeCells'), onPostRender: postRenderMergeCell},
3794
+ {text: 'Split cell', onclick: cmd('mceTableSplitCells'), onPostRender: postRenderCell}
3795
+ ]
3796
+ });
3797
+
3798
+ editor.addMenuItem('row', {
3799
+ text: 'Row',
3800
+ context: 'table',
3801
+ menu: [
3802
+ {text: 'Insert row before', onclick: cmd('mceTableInsertRowBefore'), onPostRender: postRenderCell},
3803
+ {text: 'Insert row after', onclick: cmd('mceTableInsertRowAfter'), onPostRender: postRenderCell},
3804
+ {text: 'Delete row', onclick: cmd('mceTableDeleteRow'), onPostRender: postRenderCell},
3805
+ {text: 'Row properties', onclick: cmd('mceTableRowProps'), onPostRender: postRenderCell},
3806
+ {text: '-'},
3807
+ {text: 'Cut row', onclick: cmd('mceTableCutRow'), onPostRender: postRenderCell},
3808
+ {text: 'Copy row', onclick: cmd('mceTableCopyRow'), onPostRender: postRenderCell},
3809
+ {text: 'Paste row before', onclick: cmd('mceTablePasteRowBefore'), onPostRender: postRenderCell},
3810
+ {text: 'Paste row after', onclick: cmd('mceTablePasteRowAfter'), onPostRender: postRenderCell}
3811
+ ]
3812
+ });
3813
+
3814
+ editor.addMenuItem('column', {
3815
+ text: 'Column',
3816
+ context: 'table',
3817
+ menu: [
3818
+ {text: 'Insert column before', onclick: cmd('mceTableInsertColBefore'), onPostRender: postRenderCell},
3819
+ {text: 'Insert column after', onclick: cmd('mceTableInsertColAfter'), onPostRender: postRenderCell},
3820
+ {text: 'Delete column', onclick: cmd('mceTableDeleteCol'), onPostRender: postRenderCell}
3821
+ ]
3822
+ });
3823
+
3824
+ var menuItems = [];
3825
+ each("inserttable tableprops deletetable | cell row column".split(' '), function(name) {
3826
+ if (name == '|') {
3827
+ menuItems.push({text: '-'});
3828
+ } else {
3829
+ menuItems.push(editor.menuItems[name]);
3830
+ }
3831
+ });
3832
+
3833
+ editor.addButton("table", {
3834
+ type: "menubutton",
3835
+ title: "Table",
3836
+ menu: menuItems
3837
+ });
3838
+
3839
+ // Select whole table is a table border is clicked
3840
+ if (!Env.isIE) {
3841
+ editor.on('click', function(e) {
3842
+ e = e.target;
3843
+
3844
+ if (e.nodeName === 'TABLE') {
3845
+ editor.selection.select(e);
3846
+ editor.nodeChanged();
3847
+ }
3848
+ });
3849
+ }
3850
+
3851
+ self.quirks = new Quirks(editor);
3852
+
3853
+ editor.on('Init', function() {
3854
+ self.cellSelection = new CellSelection(editor);
3855
+ self.resizeBars = resizeBars;
3856
+ });
3857
+
3858
+ editor.on('PreInit', function() {
3859
+ // Remove internal data attributes
3860
+ editor.serializer.addAttributeFilter(
3861
+ 'data-mce-cell-padding,data-mce-border,data-mce-border-color',
3862
+ function(nodes, name) {
3863
+
3864
+ var i = nodes.length;
3865
+
3866
+ while (i--) {
3867
+ nodes[i].attr(name, null);
3868
+ }
3869
+ });
3870
+ });
3871
+
3872
+ // Register action commands
3873
+ each({
3874
+ mceTableSplitCells: function(grid) {
3875
+ grid.split();
3876
+ },
3877
+
3878
+ mceTableMergeCells: function(grid) {
3879
+ var cell;
3880
+
3881
+ cell = editor.dom.getParent(editor.selection.getStart(), 'th,td');
3882
+
3883
+ if (!editor.dom.select('td[data-mce-selected],th[data-mce-selected]').length) {
3884
+ dialogs.merge(grid, cell);
3885
+ } else {
3886
+ grid.merge();
3887
+ }
3888
+ },
3889
+
3890
+ mceTableInsertRowBefore: function(grid) {
3891
+ grid.insertRow(true);
3892
+ },
3893
+
3894
+ mceTableInsertRowAfter: function(grid) {
3895
+ grid.insertRow();
3896
+ },
3897
+
3898
+ mceTableInsertColBefore: function(grid) {
3899
+ grid.insertCol(true);
3900
+ },
3901
+
3902
+ mceTableInsertColAfter: function(grid) {
3903
+ grid.insertCol();
3904
+ },
3905
+
3906
+ mceTableDeleteCol: function(grid) {
3907
+ grid.deleteCols();
3908
+ },
3909
+
3910
+ mceTableDeleteRow: function(grid) {
3911
+ grid.deleteRows();
3912
+ },
3913
+
3914
+ mceTableCutRow: function(grid) {
3915
+ clipboardRows = grid.cutRows();
3916
+ },
3917
+
3918
+ mceTableCopyRow: function(grid) {
3919
+ clipboardRows = grid.copyRows();
3920
+ },
3921
+
3922
+ mceTablePasteRowBefore: function(grid) {
3923
+ grid.pasteRows(clipboardRows, true);
3924
+ },
3925
+
3926
+ mceTablePasteRowAfter: function(grid) {
3927
+ grid.pasteRows(clipboardRows);
3928
+ },
3929
+
3930
+ mceTableDelete: function(grid) {
3931
+ if (resizeBars) {
3932
+ resizeBars.clearBars();
3933
+ }
3934
+ grid.deleteTable();
3935
+ }
3936
+ }, function(func, name) {
3937
+ editor.addCommand(name, function() {
3938
+ var grid = new TableGrid(editor);
3939
+
3940
+ if (grid) {
3941
+ func(grid);
3942
+ editor.execCommand('mceRepaint');
3943
+ self.cellSelection.clear();
3944
+ }
3945
+ });
3946
+ });
3947
+
3948
+ // Register dialog commands
3949
+ each({
3950
+ mceInsertTable: dialogs.table,
3951
+ mceTableProps: function() {
3952
+ dialogs.table(true);
3953
+ },
3954
+ mceTableRowProps: dialogs.row,
3955
+ mceTableCellProps: dialogs.cell
3956
+ }, function(func, name) {
3957
+ editor.addCommand(name, function(ui, val) {
3958
+ func(val);
3959
+ });
3960
+ });
3961
+
3962
+ function addButtons() {
3963
+ editor.addButton('tableprops', {
3964
+ title: 'Table properties',
3965
+ onclick: dialogs.tableProps,
3966
+ icon: 'table'
3967
+ });
3968
+
3969
+ editor.addButton('tabledelete', {
3970
+ title: 'Delete table',
3971
+ onclick: cmd('mceTableDelete')
3972
+ });
3973
+
3974
+ editor.addButton('tablecellprops', {
3975
+ title: 'Cell properties',
3976
+ onclick: cmd('mceTableCellProps')
3977
+ });
3978
+
3979
+ editor.addButton('tablemergecells', {
3980
+ title: 'Merge cells',
3981
+ onclick: cmd('mceTableMergeCells')
3982
+ });
3983
+
3984
+ editor.addButton('tablesplitcells', {
3985
+ title: 'Split cell',
3986
+ onclick: cmd('mceTableSplitCells')
3987
+ });
3988
+
3989
+ editor.addButton('tableinsertrowbefore', {
3990
+ title: 'Insert row before',
3991
+ onclick: cmd('mceTableInsertRowBefore')
3992
+ });
3993
+
3994
+ editor.addButton('tableinsertrowafter', {
3995
+ title: 'Insert row after',
3996
+ onclick: cmd('mceTableInsertRowAfter')
3997
+ });
3998
+
3999
+ editor.addButton('tabledeleterow', {
4000
+ title: 'Delete row',
4001
+ onclick: cmd('mceTableDeleteRow')
4002
+ });
4003
+
4004
+ editor.addButton('tablerowprops', {
4005
+ title: 'Row properties',
4006
+ onclick: cmd('mceTableRowProps')
4007
+ });
4008
+
4009
+ editor.addButton('tablecutrow', {
4010
+ title: 'Cut row',
4011
+ onclick: cmd('mceTableCutRow')
4012
+ });
4013
+
4014
+ editor.addButton('tablecopyrow', {
4015
+ title: 'Copy row',
4016
+ onclick: cmd('mceTableCopyRow')
4017
+ });
4018
+
4019
+ editor.addButton('tablepasterowbefore', {
4020
+ title: 'Paste row before',
4021
+ onclick: cmd('mceTablePasteRowBefore')
4022
+ });
4023
+
4024
+ editor.addButton('tablepasterowafter', {
4025
+ title: 'Paste row after',
4026
+ onclick: cmd('mceTablePasteRowAfter')
4027
+ });
4028
+
4029
+ editor.addButton('tableinsertcolbefore', {
4030
+ title: 'Insert column before',
4031
+ onclick: cmd('mceTableInsertColBefore')
4032
+ });
4033
+
4034
+ editor.addButton('tableinsertcolafter', {
4035
+ title: 'Insert column after',
4036
+ onclick: cmd('mceTableInsertColAfter')
4037
+ });
4038
+
4039
+ editor.addButton('tabledeletecol', {
4040
+ title: 'Delete column',
4041
+ onclick: cmd('mceTableDeleteCol')
4042
+ });
4043
+
4044
+ }
4045
+
4046
+ function isTable(table) {
4047
+
4048
+ var selectorMatched = editor.dom.is(table, 'table') && editor.getBody().contains(table);
4049
+
4050
+ return selectorMatched;
4051
+ }
4052
+
4053
+ function addToolbars() {
4054
+ var toolbarItems = editor.settings.table_toolbar;
4055
+
4056
+ if (toolbarItems === '' || toolbarItems === false) {
4057
+ return;
4058
+ }
4059
+
4060
+ if (!toolbarItems) {
4061
+ toolbarItems = 'tableprops tabledelete | ' +
4062
+ 'tableinsertrowbefore tableinsertrowafter tabledeleterow | ' +
4063
+ 'tableinsertcolbefore tableinsertcolafter tabledeletecol';
4064
+ }
4065
+
4066
+ editor.addContextToolbar(
4067
+ isTable,
4068
+ toolbarItems
4069
+ );
4070
+ }
4071
+
4072
+ addButtons();
4073
+ addToolbars();
4074
+
4075
+ // Enable tab key cell navigation
4076
+ if (editor.settings.table_tab_navigation !== false) {
4077
+ editor.on('keydown', function(e) {
4078
+ var cellElm, grid, delta;
4079
+
4080
+ if (e.keyCode == 9) {
4081
+ cellElm = editor.dom.getParent(editor.selection.getStart(), 'th,td');
4082
+
4083
+ if (cellElm) {
4084
+ e.preventDefault();
4085
+
4086
+ grid = new TableGrid(editor);
4087
+ delta = e.shiftKey ? -1 : 1;
4088
+
4089
+ editor.undoManager.transact(function() {
4090
+ if (!grid.moveRelIdx(cellElm, delta) && delta > 0) {
4091
+ grid.insertRow();
4092
+ grid.refresh();
4093
+ grid.moveRelIdx(cellElm, delta);
4094
+ }
4095
+ });
4096
+ }
4097
+ }
4098
+ });
4099
+ }
4100
+
4101
+ self.insertTable = insertTable;
4102
+ }
4103
+
4104
+ PluginManager.add('table', Plugin);
4105
+ });
4106
+ })(this);