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