From 18480d449e889bafc18e683dca94b2ff4729dbd4 Mon Sep 17 00:00:00 2001 From: Alan Date: Tue, 22 Feb 2022 15:14:39 +0800 Subject: [PATCH] Roo/UndoManager.js Roo/bootstrap/dash/namespace.js Roo/htmleditor Roo/rtf Roo/bootstrap/namespace.js Roo/htmleditor/Block.js Roo/htmleditor/BlockFigure.js Roo/htmleditor/BlockTable.js Roo/htmleditor/BlockTd.js Roo/htmleditor/Filter.js Roo/htmleditor/FilterAttributes.js Roo/htmleditor/FilterBlack.js Roo/htmleditor/FilterBlock.js Roo/htmleditor/FilterComment.js Roo/htmleditor/FilterEmpty.js Roo/htmleditor/FilterKeepChildren.js Roo/htmleditor/FilterLongBr.js Roo/htmleditor/FilterParagraph.js Roo/htmleditor/FilterSpan.js Roo/htmleditor/FilterStyleToTag.js Roo/htmleditor/FilterTableWidth.js Roo/htmleditor/FilterWord.js Roo/htmleditor/KeyEnter.js Roo/htmleditor/TidyEntities.js Roo/htmleditor/TidySerializer.js Roo/htmleditor/TidyWriter.js Roo/htmleditor/namespace.js Roo/rtf/Ctrl.js Roo/rtf/Document.js Roo/rtf/Group.js Roo/rtf/Hex.js Roo/rtf/Paragraph.js Roo/rtf/Parser.js Roo/rtf/Span.js Roo/rtf/namespace.js Roo/form/HtmlEditor/Td.js Roo/lib/Range.js Roo/lib/Selection.js Roo/lib/UndoManager.js docs/src/Roo_bootstrap_dash_namespace.js.html docs/src/Roo_bootstrap_namespace.js.html docs/src/Roo_htmleditor_Block.js.html docs/src/Roo_htmleditor_BlockFigure.js.html docs/src/Roo_htmleditor_BlockTable.js.html docs/src/Roo_htmleditor_BlockTd.js.html docs/src/Roo_htmleditor_Filter.js.html docs/src/Roo_htmleditor_FilterAttributes.js.html docs/src/Roo_htmleditor_FilterBlack.js.html docs/src/Roo_htmleditor_FilterBlock.js.html docs/src/Roo_htmleditor_FilterComment.js.html docs/src/Roo_htmleditor_FilterKeepChildren.js.html docs/src/Roo_htmleditor_FilterLongBr.js.html docs/src/Roo_htmleditor_FilterParagraph.js.html docs/src/Roo_htmleditor_FilterSpan.js.html docs/src/Roo_htmleditor_FilterStyleToTag.js.html docs/src/Roo_htmleditor_FilterTableWidth.js.html docs/src/Roo_htmleditor_FilterWord.js.html docs/src/Roo_htmleditor_KeyEnter.js.html docs/src/Roo_htmleditor_Tidy.js.html docs/src/Roo_htmleditor_TidyEntities.js.html docs/src/Roo_htmleditor_TidySerializer.js.html docs/src/Roo_htmleditor_TidyWriter.js.html docs/src/Roo_htmleditor_namespace.js.html docs/src/Roo_lib_Range.js.html docs/src/Roo_lib_Selection.js.html docs/src/Roo_lib_UndoManager.js.html docs/src/Roo_rtf_Ctrl.js.html docs/src/Roo_rtf_Document.js.html docs/src/Roo_rtf_Group.js.html docs/src/Roo_rtf_Hex.js.html docs/src/Roo_rtf_Paragraph.js.html docs/src/Roo_rtf_Parser.js.html docs/src/Roo_rtf_Span.js.html docs/src/Roo_rtf_namespace.js.html Array.js Date.js Roo.js Roo/BasicDialog.js Roo/ContentPanel.js Roo/DomHelper.js Roo/HtmlEditorCore.js docs/symbols/Roo.MessageBox.json docs/symbols/Roo.htmleditor.Block.json docs/symbols/Roo.htmleditor.BlockFigure.json docs/symbols/Roo.htmleditor.BlockTable.json docs/symbols/Roo.htmleditor.BlockTd.json docs/symbols/Roo.htmleditor.Filter.json docs/symbols/Roo.htmleditor.FilterAttributes.json docs/symbols/Roo.htmleditor.FilterBlack.json docs/symbols/Roo.htmleditor.FilterBlock.json docs/symbols/Roo.htmleditor.FilterComment.json docs/symbols/Roo.htmleditor.FilterKeepChildren.json docs/symbols/Roo.htmleditor.FilterLongBr.json docs/symbols/Roo.htmleditor.FilterParagraph.json docs/symbols/Roo.htmleditor.FilterSpan.json docs/symbols/Roo.htmleditor.FilterStyleToTag.json docs/symbols/Roo.htmleditor.FilterTableWidth.json docs/symbols/Roo.htmleditor.FilterWord.json docs/symbols/Roo.htmleditor.KeyEnter.json docs/symbols/Roo.htmleditor.Tidy.json docs/symbols/Roo.htmleditor.TidyEntities.json docs/symbols/Roo.htmleditor.TidySerializer.json docs/symbols/Roo.htmleditor.TidyWriter.json docs/symbols/Roo.htmleditor.json docs/symbols/Roo.lib.Range.json docs/symbols/Roo.lib.Selection.json docs/symbols/Roo.lib.UndoManager.json docs/symbols/Roo.rtf.json Roo/MessageBox.js Roo/PagingToolbar.js Roo/Toolbar.js Roo/bootstrap/form/SecurePass.js Roo/data/Store.js String.js Roo/form/BasicForm.js Roo/form/DateField.js Roo/form/HtmlEditor.js Roo/form/Layout.js Roo/form/HtmlEditor/ToolbarContext.js Roo/form/HtmlEditor/ToolbarStandard.js Roo/grid/Grid.js Roo/grid/GridView.js Roo/menu/Item.js Roo/menu/Menu.js buildSDK/bundle_build.sh buildSDK/dependancy_bootstrap.txt buildSDK/dependancy_core.txt buildSDK/dependancy_ui.txt css/inline-editor.css css/toolbar.css css/undoreset.css css-bootstrap4/bootstrap.css.map css-bootstrap4/bootstrap.min.css.map css-bootstrap4/roojs-bootstrap-debug.css.map css-bootstrap4/roojs-bootstrap.css.map css-bootstrap4/sb-admin-2.css css-bootstrap4/sb-admin-2.css.map css-bootstrap4/sb-admin-2.min.css css-bootstrap4/sb-admin-2.min.css.map docs/json/roodata.json docs/src/Array.js.html docs/src/Date.js.html docs/src/Roo.js.html docs/src/Roo_BasicDialog.js.html docs/src/Roo_ContentPanel.js.html docs/src/Roo_DomHelper.js.html docs/src/Roo_HtmlEditorCore.js.html docs/src/Roo_MessageBox.js.html docs/src/Roo_PagingToolbar.js.html docs/src/Roo_Toolbar.js.html docs/src/Roo_bootstrap_form_SecurePass.js.html docs/src/Roo_data_Store.js.html docs/src/Roo_form_BasicForm.js.html docs/src/Roo_form_DateField.js.html docs/src/Roo_form_HtmlEditor.js.html docs/src/Roo_form_HtmlEditor_ToolbarContext.js.html docs/src/Roo_form_HtmlEditor_ToolbarStandard.js.html docs/src/Roo_form_Layout.js.html docs/src/Roo_grid_Grid.js.html docs/src/Roo_grid_GridView.js.html docs/src/Roo_menu_Item.js.html docs/src/Roo_menu_Menu.js.html docs/src/String.js.html roojs-all.js roojs-bootstrap-debug.js roojs-bootstrap.js roojs-core-debug.js roojs-core.js roojs-debug.js examples/form/htmledit.html examples/form/htmledit.js docs/tree.json docs/symbols/Array.json docs/symbols/Roo.BasicDialog.json docs/symbols/Roo.ContentPanel.json docs/symbols/Roo.DomHelper.json docs/symbols/Roo.GridPanel.json docs/symbols/Roo.HtmlEditorCore.json docs/symbols/Roo.NestedLayoutPanel.json docs/symbols/Roo.PagingToolbar.json docs/symbols/Roo.Toolbar.TextItem.json docs/symbols/Roo.Toolbar.json docs/symbols/Roo.TreePanel.json docs/symbols/Roo.data.JsonStore.json docs/symbols/Roo.data.SimpleStore.json docs/symbols/Roo.data.Store.json docs/symbols/Roo.form.BasicForm.json docs/symbols/Roo.form.Column.json docs/symbols/Roo.form.DateField.json docs/symbols/Roo.form.Form.json docs/symbols/Roo.form.HtmlEditor.json docs/symbols/Roo.form.Layout.json docs/symbols/Roo.form.Row.json docs/symbols/Roo.grid.Calendar.json docs/symbols/Roo.grid.EditorGrid.json docs/symbols/Roo.grid.Grid.json docs/symbols/Roo.grid.PropertyGrid.json docs/symbols/Roo.json docs/symbols/Roo.menu.CheckItem.json docs/symbols/Roo.menu.Item.json docs/symbols/Roo.menu.Menu.json docs/symbols/String.json roojs-ui-debug.js roojs-ui.js --- Array.js | 62 +- Date.js | 14 +- Roo.js | 7 +- Roo/BasicDialog.js | 1 + Roo/ContentPanel.js | 325 +- Roo/DomHelper.js | 488 +- Roo/HtmlEditorCore.js | 966 +-- Roo/MessageBox.js | 3 + Roo/PagingToolbar.js | 8 +- Roo/Toolbar.js | 20 +- Roo/bootstrap/form/SecurePass.js | 2 +- Roo/data/Store.js | 10 + Roo/form/BasicForm.js | 19 +- Roo/form/DateField.js | 22 + Roo/form/HtmlEditor.js | 57 +- Roo/form/HtmlEditor/ToolbarContext.js | 587 +- Roo/form/HtmlEditor/ToolbarStandard.js | 64 +- Roo/form/Layout.js | 5 +- Roo/grid/Grid.js | 6 +- Roo/grid/GridView.js | 19 +- Roo/menu/Item.js | 2 +- Roo/menu/Menu.js | 2 +- String.js | 10 + buildSDK/bundle_build.sh | 4 + buildSDK/dependancy_bootstrap.txt | 23 + buildSDK/dependancy_core.txt | 4 +- buildSDK/dependancy_ui.txt | 38 + css-bootstrap4/bootstrap.css.map | 2 +- css-bootstrap4/bootstrap.min.css.map | 2 +- css-bootstrap4/roojs-bootstrap-debug.css.map | 2 +- css-bootstrap4/roojs-bootstrap.css.map | 2 +- css-bootstrap4/sb-admin-2.css | 84 +- css-bootstrap4/sb-admin-2.css.map | 4 +- css-bootstrap4/sb-admin-2.min.css | 2 +- css-bootstrap4/sb-admin-2.min.css.map | 4 +- css/inline-editor.css | 17 +- css/toolbar.css | 2 +- css/undoreset.css | 9 + docs/json/roodata.json | 3636 +++++--- docs/src/Array.js.html | 54 +- docs/src/Date.js.html | 14 +- docs/src/Roo.js.html | 5 +- docs/src/Roo_BasicDialog.js.html | 1 + docs/src/Roo_ContentPanel.js.html | 325 +- docs/src/Roo_DomHelper.js.html | 470 +- docs/src/Roo_HtmlEditorCore.js.html | 970 +-- docs/src/Roo_MessageBox.js.html | 3 + docs/src/Roo_PagingToolbar.js.html | 10 +- docs/src/Roo_Toolbar.js.html | 22 +- .../src/Roo_bootstrap_form_SecurePass.js.html | 2 +- docs/src/Roo_data_Store.js.html | 10 + docs/src/Roo_form_BasicForm.js.html | 21 +- docs/src/Roo_form_DateField.js.html | 22 + docs/src/Roo_form_HtmlEditor.js.html | 55 +- ...Roo_form_HtmlEditor_ToolbarContext.js.html | 563 +- ...oo_form_HtmlEditor_ToolbarStandard.js.html | 55 +- docs/src/Roo_form_Layout.js.html | 5 +- docs/src/Roo_grid_Grid.js.html | 6 +- docs/src/Roo_grid_GridView.js.html | 19 +- docs/src/Roo_menu_Item.js.html | 2 +- docs/src/Roo_menu_Menu.js.html | 2 +- docs/src/String.js.html | 10 + docs/symbols/Array.json | 26 + docs/symbols/Roo.BasicDialog.json | 5 +- docs/symbols/Roo.ContentPanel.json | 4 +- docs/symbols/Roo.DomHelper.json | 32 + docs/symbols/Roo.GridPanel.json | 29 +- docs/symbols/Roo.HtmlEditorCore.json | 86 +- docs/symbols/Roo.NestedLayoutPanel.json | 16 +- docs/symbols/Roo.PagingToolbar.json | 28 + docs/symbols/Roo.Toolbar.TextItem.json | 20 +- docs/symbols/Roo.Toolbar.json | 2 + docs/symbols/Roo.TreePanel.json | 8 +- docs/symbols/Roo.data.JsonStore.json | 2 +- docs/symbols/Roo.data.SimpleStore.json | 2 +- docs/symbols/Roo.data.Store.json | 2 +- docs/symbols/Roo.form.BasicForm.json | 13 +- docs/symbols/Roo.form.Column.json | 31 +- docs/symbols/Roo.form.DateField.json | 6 + docs/symbols/Roo.form.Form.json | 13 +- docs/symbols/Roo.form.HtmlEditor.json | 115 +- docs/symbols/Roo.form.Layout.json | 3 +- docs/symbols/Roo.form.Row.json | 3 +- docs/symbols/Roo.grid.Calendar.json | 6 + docs/symbols/Roo.grid.EditorGrid.json | 6 + docs/symbols/Roo.grid.Grid.json | 6 + docs/symbols/Roo.grid.PropertyGrid.json | 6 + docs/symbols/Roo.json | 79 +- docs/symbols/Roo.menu.CheckItem.json | 2 +- docs/symbols/Roo.menu.Item.json | 8 +- docs/symbols/Roo.menu.Menu.json | 4 +- docs/symbols/String.json | 25 + docs/tree.json | 136 +- examples/form/htmledit.html | 19 +- examples/form/htmledit.js | 121 +- roojs-all.js | 608 +- roojs-bootstrap-debug.js | 5055 ++++++++--- roojs-bootstrap.js | 250 +- roojs-core-debug.js | 1046 ++- roojs-core.js | 72 +- roojs-debug.js | 7696 ++++++++++++++--- roojs-ui-debug.js | 6938 ++++++++++++--- roojs-ui.js | 536 +- 103 files changed, 23548 insertions(+), 8697 deletions(-) diff --git a/Array.js b/Array.js index a3b684d73e..4ede9280a2 100644 --- a/Array.js +++ b/Array.js @@ -63,27 +63,47 @@ Roo.applyIf(Array.prototype, { */ equals : function(b) { - // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript - if (this === b) { - return true; - } - if (b == null) { - return false; - } - if (this.length !== b.length) { - return false; - } - - // sort?? a.sort().equals(b.sort()); + // https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript + if (this === b) { + return true; + } + if (b == null) { + return false; + } + if (this.length !== b.length) { + return false; + } + + // sort?? a.sort().equals(b.sort()); + + for (var i = 0; i < this.length; ++i) { + if (this[i] !== b[i]) { + return false; + } + } + return true; + } + + + + +}); + +Roo.applyIf(Array, { + /** + * from + * @static + * @param {Array} o Or Array like object (eg. nodelist) + * @returns {Array} + */ + from : function(o) + { + var ret= []; + + for (var i =0; i < o.length; i++) { + ret[i] = o[i]; + } + return ret; - for (var i = 0; i < this.length; ++i) { - if (this[i] !== b[i]) { - return false; - } - } - return true; } }); - - - diff --git a/Date.js b/Date.js index 6f217a5d55..fffb3b71d1 100644 --- a/Date.js +++ b/Date.js @@ -301,17 +301,17 @@ Date.createParser = function(format) { } code += "if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0 && s >= 0)\n" - + "{v = new Date(y, m, d, h, i, s);}\n" + + "{v = new Date(y, m, d, h, i, s); v.setFullYear(y);}\n" + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0 && i >= 0)\n" - + "{v = new Date(y, m, d, h, i);}\n" + + "{v = new Date(y, m, d, h, i); v.setFullYear(y);}\n" + "else if (y >= 0 && m >= 0 && d > 0 && h >= 0)\n" - + "{v = new Date(y, m, d, h);}\n" + + "{v = new Date(y, m, d, h); v.setFullYear(y);}\n" + "else if (y >= 0 && m >= 0 && d > 0)\n" - + "{v = new Date(y, m, d);}\n" + + "{v = new Date(y, m, d); v.setFullYear(y);}\n" + "else if (y >= 0 && m >= 0)\n" - + "{v = new Date(y, m);}\n" + + "{v = new Date(y, m); v.setFullYear(y);}\n" + "else if (y >= 0)\n" - + "{v = new Date(y);}\n" + + "{v = new Date(y); v.setFullYear(y);}\n" + "}return (v && (z || o))?\n" // favour UTC offset over GMT offset + " ((z)? v.add(Date.SECOND, (v.getTimezoneOffset() * 60) + (z*1)) :\n" // reset to UTC, then add offset + " v.add(Date.HOUR, (v.getGMTOffset() / 100) + (o / -100))) : v\n" // reset to GMT, then add offset @@ -371,7 +371,7 @@ Date.formatCodeToRegex = function(character, currentGroup) { s:"(\\d{1,2})"}; // Numeric representation of a month, without leading zeros case "m": return {g:1, - c:"m = parseInt(results[" + currentGroup + "], 10) - 1;\n", + c:"m = Math.max(0,parseInt(results[" + currentGroup + "], 10) - 1);\n", s:"(\\d{2})"}; // Numeric representation of a month, with leading zeros case "t": return {g:0, diff --git a/Roo.js b/Roo.js index 08881e14bf..612a227566 100644 --- a/Roo.js +++ b/Roo.js @@ -691,7 +691,7 @@ Roo.factory(conf, Roo.data); return 'xs' } - } + } }); @@ -700,6 +700,5 @@ Roo.factory(conf, Roo.data); Roo.namespace("Roo", "Roo.util", "Roo.grid", "Roo.dd", "Roo.tree", "Roo.data", "Roo.form", "Roo.menu", "Roo.state", "Roo.lib", "Roo.layout", - "Roo.app", "Roo.ux", - "Roo.bootstrap", - "Roo.bootstrap.dash"); + "Roo.app", "Roo.ux" + ); diff --git a/Roo/BasicDialog.js b/Roo/BasicDialog.js index 0070805873..d8034fdab8 100644 --- a/Roo/BasicDialog.js +++ b/Roo/BasicDialog.js @@ -12,6 +12,7 @@ /** * @class Roo.BasicDialog * @extends Roo.util.Observable + * @parent none builder * Lightweight Dialog Class. The code below shows the creation of a typical dialog using existing HTML markup: *

 var dlg = new Roo.BasicDialog("my-dlg", {
diff --git a/Roo/ContentPanel.js b/Roo/ContentPanel.js
index 3d143999e4..0984532b54 100644
--- a/Roo/ContentPanel.js
+++ b/Roo/ContentPanel.js
@@ -12,7 +12,7 @@
  * @class Roo.ContentPanel
  * @extends Roo.util.Observable
  * @children Roo.form.Form Roo.JsonView Roo.View
- * @parent Roo.BorderLayout Roo.LayoutDialog builder-top
+ * @parent Roo.BorderLayout Roo.LayoutDialog builder
  * A basic ContentPanel element.
  * @cfg {Boolean}   fitToFrame    True for this panel to adjust its size to fit when the region resizes  (defaults to false)
  * @cfg {Boolean}   fitContainer   When using {@link #fitToFrame} and {@link #resizeEl}, you can also fit the parent container  (defaults to false)
@@ -25,7 +25,7 @@
  * @cfg {String} title          The title for this panel
  * @cfg {Array} adjustments     Values to add to the width/height when doing a {@link #fitToFrame} (default is [0, 0])
  * @cfg {String} url            Calls {@link #setUrl} with this value
- * @cfg {String} region [required]   (center|north|south|east|west) which region to put this panel on (when used with xtype constructors)
+ * @cfg {String} region (center|north|south|east|west) [required] which region to put this panel on (when used with xtype constructors)
  * @cfg {String|Object} params  When used with {@link #url}, calls {@link #setUrl} with this value
  * @cfg {Boolean} loadOnce      When used with {@link #url}, calls {@link #setUrl} with this value
  * @cfg {String}    content        Raw content to fill content panel with (uses setContent on construction.)
@@ -460,327 +460,6 @@ layout.addxtype({
     }
 });
 
-/**
- * @class Roo.GridPanel
- * @extends Roo.ContentPanel
- * @constructor
- * Create a new GridPanel.
- * @param {Roo.grid.Grid} grid The grid for this panel
- * @param {String/Object} config A string to set only the panel's title, or a config object
- */
-Roo.GridPanel = function(grid, config){
-    
-  
-    this.wrapper = Roo.DomHelper.append(document.body, // wrapper for IE7 strict & safari scroll issue
-        {tag: "div", cls: "x-layout-grid-wrapper x-layout-inactive-content"}, true);
-        
-    this.wrapper.dom.appendChild(grid.getGridEl().dom);
-    
-    Roo.GridPanel.superclass.constructor.call(this, this.wrapper, config);
-    
-    if(this.toolbar){
-        this.toolbar.el.insertBefore(this.wrapper.dom.firstChild);
-    }
-    // xtype created footer. - not sure if will work as we normally have to render first..
-    if (this.footer && !this.footer.el && this.footer.xtype) {
-        
-        this.footer.container = this.grid.getView().getFooterPanel(true);
-        this.footer.dataSource = this.grid.dataSource;
-        this.footer = Roo.factory(this.footer, Roo);
-        
-    }
-    
-    grid.monitorWindowResize = false; // turn off autosizing
-    grid.autoHeight = false;
-    grid.autoWidth = false;
-    this.grid = grid;
-    this.grid.getGridEl().replaceClass("x-layout-inactive-content", "x-layout-component-panel");
-};
-
-Roo.extend(Roo.GridPanel, Roo.ContentPanel, {
-    getId : function(){
-        return this.grid.id;
-    },
-    
-    /**
-     * Returns the grid for this panel
-     * @return {Roo.grid.Grid} 
-     */
-    getGrid : function(){
-        return this.grid;    
-    },
-    
-    setSize : function(width, height){
-        if(!this.ignoreResize(width, height)){
-            var grid = this.grid;
-            var size = this.adjustForComponents(width, height);
-            grid.getGridEl().setSize(size.width, size.height);
-            grid.autoSize();
-        }
-    },
-    
-    beforeSlide : function(){
-        this.grid.getView().scroller.clip();
-    },
-    
-    afterSlide : function(){
-        this.grid.getView().scroller.unclip();
-    },
-    
-    destroy : function(){
-        this.grid.destroy();
-        delete this.grid;
-        Roo.GridPanel.superclass.destroy.call(this); 
-    }
-});
-
-
-/**
- * @class Roo.NestedLayoutPanel
- * @extends Roo.ContentPanel
- * @constructor
- * Create a new NestedLayoutPanel.
- * 
- * 
- * @param {Roo.BorderLayout} layout [required] The layout for this panel
- * @param {String/Object} config A string to set only the title or a config object
- */
-Roo.NestedLayoutPanel = function(layout, config)
-{
-    // construct with only one argument..
-    /* FIXME - implement nicer consturctors
-    if (layout.layout) {
-        config = layout;
-        layout = config.layout;
-        delete config.layout;
-    }
-    if (layout.xtype && !layout.getEl) {
-        // then layout needs constructing..
-        layout = Roo.factory(layout, Roo);
-    }
-    */
-    
-    
-    Roo.NestedLayoutPanel.superclass.constructor.call(this, layout.getEl(), config);
-    
-    layout.monitorWindowResize = false; // turn off autosizing
-    this.layout = layout;
-    this.layout.getEl().addClass("x-layout-nested-layout");
-    
-    
-    
-    
-};
-
-Roo.extend(Roo.NestedLayoutPanel, Roo.ContentPanel, {
-
-    setSize : function(width, height){
-        if(!this.ignoreResize(width, height)){
-            var size = this.adjustForComponents(width, height);
-            var el = this.layout.getEl();
-            el.setSize(size.width, size.height);
-            var touch = el.dom.offsetWidth;
-            this.layout.layout();
-            // ie requires a double layout on the first pass
-            if(Roo.isIE && !this.initialized){
-                this.initialized = true;
-                this.layout.layout();
-            }
-        }
-    },
-    
-    // activate all subpanels if not currently active..
-    
-    setActiveState : function(active){
-        this.active = active;
-        if(!active){
-            this.fireEvent("deactivate", this);
-            return;
-        }
-        
-        this.fireEvent("activate", this);
-        // not sure if this should happen before or after..
-        if (!this.layout) {
-            return; // should not happen..
-        }
-        var reg = false;
-        for (var r in this.layout.regions) {
-            reg = this.layout.getRegion(r);
-            if (reg.getActivePanel()) {
-                //reg.showPanel(reg.getActivePanel()); // force it to activate.. 
-                reg.setActivePanel(reg.getActivePanel());
-                continue;
-            }
-            if (!reg.panels.length) {
-                continue;
-            }
-            reg.showPanel(reg.getPanel(0));
-        }
-        
-        
-        
-        
-    },
-    
-    /**
-     * Returns the nested BorderLayout for this panel
-     * @return {Roo.BorderLayout} 
-     */
-    getLayout : function(){
-        return this.layout;
-    },
-    
-     /**
-     * Adds a xtype elements to the layout of the nested panel
-     * 

-
-panel.addxtype({
-       xtype : 'ContentPanel',
-       region: 'west',
-       items: [ .... ]
-   }
-);
-
-panel.addxtype({
-        xtype : 'NestedLayoutPanel',
-        region: 'west',
-        layout: {
-           center: { },
-           west: { }   
-        },
-        items : [ ... list of content panels or nested layout panels.. ]
-   }
-);
-
- * @param {Object} cfg Xtype definition of item to add. - */ - addxtype : function(cfg) { - return this.layout.addxtype(cfg); - - } -}); - -Roo.ScrollPanel = function(el, config, content){ - config = config || {}; - config.fitToFrame = true; - Roo.ScrollPanel.superclass.constructor.call(this, el, config, content); - - this.el.dom.style.overflow = "hidden"; - var wrap = this.el.wrap({cls: "x-scroller x-layout-inactive-content"}); - this.el.removeClass("x-layout-inactive-content"); - this.el.on("mousewheel", this.onWheel, this); - - var up = wrap.createChild({cls: "x-scroller-up", html: " "}, this.el.dom); - var down = wrap.createChild({cls: "x-scroller-down", html: " "}); - up.unselectable(); down.unselectable(); - up.on("click", this.scrollUp, this); - down.on("click", this.scrollDown, this); - up.addClassOnOver("x-scroller-btn-over"); - down.addClassOnOver("x-scroller-btn-over"); - up.addClassOnClick("x-scroller-btn-click"); - down.addClassOnClick("x-scroller-btn-click"); - this.adjustments = [0, -(up.getHeight() + down.getHeight())]; - - this.resizeEl = this.el; - this.el = wrap; this.up = up; this.down = down; -}; - -Roo.extend(Roo.ScrollPanel, Roo.ContentPanel, { - increment : 100, - wheelIncrement : 5, - scrollUp : function(){ - this.resizeEl.scroll("up", this.increment, {callback: this.afterScroll, scope: this}); - }, - - scrollDown : function(){ - this.resizeEl.scroll("down", this.increment, {callback: this.afterScroll, scope: this}); - }, - - afterScroll : function(){ - var el = this.resizeEl; - var t = el.dom.scrollTop, h = el.dom.scrollHeight, ch = el.dom.clientHeight; - this.up[t == 0 ? "addClass" : "removeClass"]("x-scroller-btn-disabled"); - this.down[h - t <= ch ? "addClass" : "removeClass"]("x-scroller-btn-disabled"); - }, - - setSize : function(){ - Roo.ScrollPanel.superclass.setSize.apply(this, arguments); - this.afterScroll(); - }, - - onWheel : function(e){ - var d = e.getWheelDelta(); - this.resizeEl.dom.scrollTop -= (d*this.wheelIncrement); - this.afterScroll(); - e.stopEvent(); - }, - - setContent : function(content, loadScripts){ - this.resizeEl.update(content, loadScripts); - } - -}); - - - -/** - * @class Roo.TreePanel - * @extends Roo.ContentPanel - * Treepanel component - * - * @constructor - * Create a new TreePanel. - defaults to fit/scoll contents. - * @param {String/Object} config A string to set only the panel's title, or a config object - */ -Roo.TreePanel = function(config){ - var el = config.el; - var tree = config.tree; - delete config.tree; - delete config.el; // hopefull! - - // wrapper for IE7 strict & safari scroll issue - - var treeEl = el.createChild(); - config.resizeEl = treeEl; - - - - Roo.TreePanel.superclass.constructor.call(this, el, config); - - - this.tree = new Roo.tree.TreePanel(treeEl , tree); - //console.log(tree); - this.on('activate', function() - { - if (this.tree.rendered) { - return; - } - //console.log('render tree'); - this.tree.render(); - }); - // this should not be needed.. - it's actually the 'el' that resizes? - // actuall it breaks the containerScroll - dragging nodes auto scroll at top - - //this.on('resize', function (cp, w, h) { - // this.tree.innerCt.setWidth(w); - // this.tree.innerCt.setHeight(h); - // //this.tree.innerCt.setStyle('overflow-y', 'auto'); - //}); - - - -}; - -Roo.extend(Roo.TreePanel, Roo.ContentPanel, { - fitToFrame : true, - autoScroll : true, - /* - * @cfg {Roo.tree.TreePanel} tree [required] The tree TreePanel, with config etc. - */ - tree : false - -}); - diff --git a/Roo/DomHelper.js b/Roo/DomHelper.js index f12b8885d3..a8967880a2 100644 --- a/Roo/DomHelper.js +++ b/Roo/DomHelper.js @@ -245,211 +245,319 @@ Roo.DomHelper = function(){ el.insertBefore(node, before); return node; }; + + // this is a bit like the react update code... + // + + var updateNode = function(from, to) + { + // should we handle non-standard elements? + Roo.log(["UpdateNode" , from, to]); + if (from.nodeType != to.nodeType) { + Roo.log(["ReplaceChild - mismatch notType" , to, from ]); + from.parentNode.replaceChild(to, from); + } + + if (from.nodeType == 3) { + // assume it's text?! + if (from.data == to.data) { + return; + } + from.data = to.data; + return; + } + if (!from.parentNode) { + // not sure why this is happening? + return; + } + // assume 'to' doesnt have '1/3 nodetypes! + // not sure why, by from, parent node might not exist? + if (from.nodeType !=1 || from.tagName != to.tagName) { + Roo.log(["ReplaceChild" , from, to ]); + + from.parentNode.replaceChild(to, from); + return; + } + // compare attributes + var ar = Array.from(from.attributes); + for(var i = 0; i< ar.length;i++) { + if (to.hasAttribute(ar[i].name)) { + continue; + } + if (ar[i].name == 'id') { // always keep ids? + continue; + } + //if (ar[i].name == 'style') { + // throw "style removed?"; + //} + Roo.log("removeAttribute" + ar[i].name); + from.removeAttribute(ar[i].name); + } + ar = to.attributes; + for(var i = 0; i< ar.length;i++) { + if (from.getAttribute(ar[i].name) == to.getAttribute(ar[i].name)) { + Roo.log("skipAttribute " + ar[i].name + '=' + to.getAttribute(ar[i].name)); + continue; + } + Roo.log("updateAttribute " + ar[i].name + '=>' + to.getAttribute(ar[i].name)); + from.setAttribute(ar[i].name, to.getAttribute(ar[i].name)); + } + // children + var far = Array.from(from.childNodes); + var tar = Array.from(to.childNodes); + // if the lengths are different.. then it's probably a editable content change, rather than + // a change of the block definition.. + + // this did notwork , as our rebuilt nodes did not include ID's so did not match at all. + /*if (from.innerHTML == to.innerHTML) { + return; + } + if (far.length != tar.length) { + from.innerHTML = to.innerHTML; + return; + } + */ + + for(var i = 0; i < Math.max(tar.length, far.length); i++) { + if (i >= far.length) { + from.appendChild(tar[i]); + Roo.log(["add", tar[i]]); + + } else if ( i >= tar.length) { + from.removeChild(far[i]); + Roo.log(["remove", far[i]]); + } else { + + updateNode(far[i], tar[i]); + } + } + + + + + }; + + return { - /** True to force the use of DOM instead of html fragments @type Boolean */ - useDom : false, - - /** - * Returns the markup for the passed Element(s) config - * @param {Object} o The Dom object spec (and children) - * @return {String} - */ - markup : function(o){ - return createHtml(o); - }, - - /** - * Applies a style specification to an element - * @param {String/HTMLElement} el The element to apply styles to - * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or - * a function which returns such a specification. - */ - applyStyles : function(el, styles){ - if(styles){ - el = Roo.fly(el); - if(typeof styles == "string"){ - var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi; - var matches; - while ((matches = re.exec(styles)) != null){ - el.setStyle(matches[1], matches[2]); - } - }else if (typeof styles == "object"){ - for (var style in styles){ - el.setStyle(style, styles[style]); + /** True to force the use of DOM instead of html fragments @type Boolean */ + useDom : false, + + /** + * Returns the markup for the passed Element(s) config + * @param {Object} o The Dom object spec (and children) + * @return {String} + */ + markup : function(o){ + return createHtml(o); + }, + + /** + * Applies a style specification to an element + * @param {String/HTMLElement} el The element to apply styles to + * @param {String/Object/Function} styles A style specification string eg "width:100px", or object in the form {width:"100px"}, or + * a function which returns such a specification. + */ + applyStyles : function(el, styles){ + if(styles){ + el = Roo.fly(el); + if(typeof styles == "string"){ + var re = /\s?([a-z\-]*)\:\s?([^;]*);?/gi; + var matches; + while ((matches = re.exec(styles)) != null){ + el.setStyle(matches[1], matches[2]); + } + }else if (typeof styles == "object"){ + for (var style in styles){ + el.setStyle(style, styles[style]); + } + }else if (typeof styles == "function"){ + Roo.DomHelper.applyStyles(el, styles.call()); } - }else if (typeof styles == "function"){ - Roo.DomHelper.applyStyles(el, styles.call()); - } - } - }, - - /** - * Inserts an HTML fragment into the Dom - * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd. - * @param {HTMLElement} el The context element - * @param {String} html The HTML fragmenet - * @return {HTMLElement} The new node - */ - insertHtml : function(where, el, html){ - where = where.toLowerCase(); - if(el.insertAdjacentHTML){ - if(tableRe.test(el.tagName)){ - var rs; - if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){ - return rs; + } + }, + + /** + * Inserts an HTML fragment into the Dom + * @param {String} where Where to insert the html in relation to el - beforeBegin, afterBegin, beforeEnd, afterEnd. + * @param {HTMLElement} el The context element + * @param {String} html The HTML fragmenet + * @return {HTMLElement} The new node + */ + insertHtml : function(where, el, html){ + where = where.toLowerCase(); + if(el.insertAdjacentHTML){ + if(tableRe.test(el.tagName)){ + var rs; + if(rs = insertIntoTable(el.tagName.toLowerCase(), where, el, html)){ + return rs; + } + } + switch(where){ + case "beforebegin": + el.insertAdjacentHTML('BeforeBegin', html); + return el.previousSibling; + case "afterbegin": + el.insertAdjacentHTML('AfterBegin', html); + return el.firstChild; + case "beforeend": + el.insertAdjacentHTML('BeforeEnd', html); + return el.lastChild; + case "afterend": + el.insertAdjacentHTML('AfterEnd', html); + return el.nextSibling; } + throw 'Illegal insertion point -> "' + where + '"'; } + var range = el.ownerDocument.createRange(); + var frag; switch(where){ - case "beforebegin": - el.insertAdjacentHTML('BeforeBegin', html); + case "beforebegin": + range.setStartBefore(el); + frag = range.createContextualFragment(html); + el.parentNode.insertBefore(frag, el); return el.previousSibling; - case "afterbegin": - el.insertAdjacentHTML('AfterBegin', html); - return el.firstChild; + case "afterbegin": + if(el.firstChild){ + range.setStartBefore(el.firstChild); + frag = range.createContextualFragment(html); + el.insertBefore(frag, el.firstChild); + return el.firstChild; + }else{ + el.innerHTML = html; + return el.firstChild; + } case "beforeend": - el.insertAdjacentHTML('BeforeEnd', html); - return el.lastChild; + if(el.lastChild){ + range.setStartAfter(el.lastChild); + frag = range.createContextualFragment(html); + el.appendChild(frag); + return el.lastChild; + }else{ + el.innerHTML = html; + return el.lastChild; + } case "afterend": - el.insertAdjacentHTML('AfterEnd', html); - return el.nextSibling; - } - throw 'Illegal insertion point -> "' + where + '"'; - } - var range = el.ownerDocument.createRange(); - var frag; - switch(where){ - case "beforebegin": - range.setStartBefore(el); - frag = range.createContextualFragment(html); - el.parentNode.insertBefore(frag, el); - return el.previousSibling; - case "afterbegin": - if(el.firstChild){ - range.setStartBefore(el.firstChild); + range.setStartAfter(el); frag = range.createContextualFragment(html); - el.insertBefore(frag, el.firstChild); - return el.firstChild; - }else{ - el.innerHTML = html; - return el.firstChild; + el.parentNode.insertBefore(frag, el.nextSibling); + return el.nextSibling; } - case "beforeend": - if(el.lastChild){ - range.setStartAfter(el.lastChild); - frag = range.createContextualFragment(html); - el.appendChild(frag); - return el.lastChild; - }else{ - el.innerHTML = html; - return el.lastChild; + throw 'Illegal insertion point -> "' + where + '"'; + }, + + /** + * Creates new Dom element(s) and inserts them before el + * @param {String/HTMLElement/Element} el The context element + * @param {Object/String} o The Dom object spec (and children) or raw HTML blob + * @param {Boolean} returnElement (optional) true to return a Roo.Element + * @return {HTMLElement/Roo.Element} The new node + */ + insertBefore : function(el, o, returnElement){ + return this.doInsert(el, o, returnElement, "beforeBegin"); + }, + + /** + * Creates new Dom element(s) and inserts them after el + * @param {String/HTMLElement/Element} el The context element + * @param {Object} o The Dom object spec (and children) + * @param {Boolean} returnElement (optional) true to return a Roo.Element + * @return {HTMLElement/Roo.Element} The new node + */ + insertAfter : function(el, o, returnElement){ + return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling"); + }, + + /** + * Creates new Dom element(s) and inserts them as the first child of el + * @param {String/HTMLElement/Element} el The context element + * @param {Object/String} o The Dom object spec (and children) or raw HTML blob + * @param {Boolean} returnElement (optional) true to return a Roo.Element + * @return {HTMLElement/Roo.Element} The new node + */ + insertFirst : function(el, o, returnElement){ + return this.doInsert(el, o, returnElement, "afterBegin"); + }, + + // private + doInsert : function(el, o, returnElement, pos, sibling){ + el = Roo.getDom(el); + var newNode; + if(this.useDom || o.ns){ + newNode = createDom(o, null); + el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el); + }else{ + var html = createHtml(o); + newNode = this.insertHtml(pos, el, html); + } + return returnElement ? Roo.get(newNode, true) : newNode; + }, + + /** + * Creates new Dom element(s) and appends them to el + * @param {String/HTMLElement/Element} el The context element + * @param {Object/String} o The Dom object spec (and children) or raw HTML blob + * @param {Boolean} returnElement (optional) true to return a Roo.Element + * @return {HTMLElement/Roo.Element} The new node + */ + append : function(el, o, returnElement){ + el = Roo.getDom(el); + var newNode; + if(this.useDom || o.ns){ + newNode = createDom(o, null); + el.appendChild(newNode); + }else{ + var html = createHtml(o); + newNode = this.insertHtml("beforeEnd", el, html); + } + return returnElement ? Roo.get(newNode, true) : newNode; + }, + + /** + * Creates new Dom element(s) and overwrites the contents of el with them + * @param {String/HTMLElement/Element} el The context element + * @param {Object/String} o The Dom object spec (and children) or raw HTML blob + * @param {Boolean} returnElement (optional) true to return a Roo.Element + * @return {HTMLElement/Roo.Element} The new node + */ + overwrite : function(el, o, returnElement) + { + el = Roo.getDom(el); + if (o.ns) { + + while (el.childNodes.length) { + el.removeChild(el.firstChild); } - case "afterend": - range.setStartAfter(el); - frag = range.createContextualFragment(html); - el.parentNode.insertBefore(frag, el.nextSibling); - return el.nextSibling; + createDom(o, el); + } else { + el.innerHTML = createHtml(o); } - throw 'Illegal insertion point -> "' + where + '"'; - }, - - /** - * Creates new Dom element(s) and inserts them before el - * @param {String/HTMLElement/Element} el The context element - * @param {Object/String} o The Dom object spec (and children) or raw HTML blob - * @param {Boolean} returnElement (optional) true to return a Roo.Element - * @return {HTMLElement/Roo.Element} The new node - */ - insertBefore : function(el, o, returnElement){ - return this.doInsert(el, o, returnElement, "beforeBegin"); - }, - - /** - * Creates new Dom element(s) and inserts them after el - * @param {String/HTMLElement/Element} el The context element - * @param {Object} o The Dom object spec (and children) - * @param {Boolean} returnElement (optional) true to return a Roo.Element - * @return {HTMLElement/Roo.Element} The new node - */ - insertAfter : function(el, o, returnElement){ - return this.doInsert(el, o, returnElement, "afterEnd", "nextSibling"); - }, - - /** - * Creates new Dom element(s) and inserts them as the first child of el - * @param {String/HTMLElement/Element} el The context element - * @param {Object/String} o The Dom object spec (and children) or raw HTML blob - * @param {Boolean} returnElement (optional) true to return a Roo.Element - * @return {HTMLElement/Roo.Element} The new node - */ - insertFirst : function(el, o, returnElement){ - return this.doInsert(el, o, returnElement, "afterBegin"); - }, - - // private - doInsert : function(el, o, returnElement, pos, sibling){ - el = Roo.getDom(el); - var newNode; - if(this.useDom || o.ns){ - newNode = createDom(o, null); - el.parentNode.insertBefore(newNode, sibling ? el[sibling] : el); - }else{ - var html = createHtml(o); - newNode = this.insertHtml(pos, el, html); - } - return returnElement ? Roo.get(newNode, true) : newNode; - }, - - /** - * Creates new Dom element(s) and appends them to el - * @param {String/HTMLElement/Element} el The context element - * @param {Object/String} o The Dom object spec (and children) or raw HTML blob - * @param {Boolean} returnElement (optional) true to return a Roo.Element - * @return {HTMLElement/Roo.Element} The new node - */ - append : function(el, o, returnElement){ - el = Roo.getDom(el); - var newNode; - if(this.useDom || o.ns){ - newNode = createDom(o, null); - el.appendChild(newNode); - }else{ + + return returnElement ? Roo.get(el.firstChild, true) : el.firstChild; + }, + + /** + * Creates a new Roo.DomHelper.Template from the Dom object spec + * @param {Object} o The Dom object spec (and children) + * @return {Roo.DomHelper.Template} The new template + */ + createTemplate : function(o){ var html = createHtml(o); - newNode = this.insertHtml("beforeEnd", el, html); - } - return returnElement ? Roo.get(newNode, true) : newNode; - }, - - /** - * Creates new Dom element(s) and overwrites the contents of el with them - * @param {String/HTMLElement/Element} el The context element - * @param {Object/String} o The Dom object spec (and children) or raw HTML blob - * @param {Boolean} returnElement (optional) true to return a Roo.Element - * @return {HTMLElement/Roo.Element} The new node - */ - overwrite : function(el, o, returnElement){ - el = Roo.getDom(el); - if (o.ns) { - - while (el.childNodes.length) { - el.removeChild(el.firstChild); - } - createDom(o, el); - } else { - el.innerHTML = createHtml(o); + return new Roo.Template(html); + }, + /** + * Updates the first element with the spec from the o (replacing if necessary) + * This iterates through the children, and updates attributes / children etc.. + * @param {String/HTMLElement/Element} el The context element + * @param {Object/String} o The Dom object spec (and children) or raw HTML blob + */ + + update : function(el, o) + { + updateNode(Roo.getDom(el), createDom(o)); + } - return returnElement ? Roo.get(el.firstChild, true) : el.firstChild; - }, - - /** - * Creates a new Roo.DomHelper.Template from the Dom object spec - * @param {Object} o The Dom object spec (and children) - * @return {Roo.DomHelper.Template} The new template - */ - createTemplate : function(o){ - var html = createHtml(o); - return new Roo.Template(html); - } + }; }(); diff --git a/Roo/HtmlEditorCore.js b/Roo/HtmlEditorCore.js index e17b9985f4..e682312230 100644 --- a/Roo/HtmlEditorCore.js +++ b/Roo/HtmlEditorCore.js @@ -71,7 +71,8 @@ Roo.HtmlEditorCore = function(config){ * Fires when on any editor (mouse up/down cursor movement etc.) - used for toolbar hooks. * @param {Roo.HtmlEditorCore} this */ - editorevent: true + editorevent: true + }); @@ -107,15 +108,30 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { * @cfg {Number} width (in pixels) */ width: 500, + /** + * @cfg {boolean} autoClean - default true - loading and saving will remove quite a bit of formating, + * if you are doing an email editor, this probably needs disabling, it's designed + */ + autoClean: true, + /** + * @cfg {boolean} enableBlocks - default true - if the block editor (table and figure should be enabled) + */ + enableBlocks : true, /** * @cfg {Array} stylesheets url of stylesheets. set to [] to disable stylesheets. * */ stylesheets: false, + /** + * @cfg {String} language default en - language of text (usefull for rtl languages) + * + */ + language: 'en', /** - * @cfg {boolean} allowComments - default false - allow comments in HTML source - by default they are stripped - if you are editing email you may need this. + * @cfg {boolean} allowComments - default false - allow comments in HTML source + * - by default they are stripped - if you are editing email you may need this. */ allowComments: false, // id of frame.. @@ -139,6 +155,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { bodyCls : '', + + undoManager : false, /** * Protected method that will not generally be called directly. It * is called when the editor initializes the iframe with HTML contents. Override this method if you @@ -165,7 +183,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { 'body{border:0;margin:0;padding:3px;height:98%;cursor:text;}' + ''; } else { - for (var i in this.stylesheets) { + for (var i in this.stylesheets) { + if (typeof(this.stylesheets[i]) != 'string') { + continue; + } st += ''; } @@ -174,14 +195,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { st += ''; - - var cls = 'roo-htmleditor-body'; + + st += ''; + + var cls = 'notranslate roo-htmleditor-body'; if(this.bodyCls.length){ cls += ' ' + this.bodyCls; } - return '' + st + + return '' + st + //' + @@ -224,7 +247,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { this.iframe = iframe.dom; - this.assignDocWin(); + this.assignDocWin(); this.doc.designMode = 'on'; @@ -240,6 +263,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { if(this.doc.body || this.doc.readyState == 'complete'){ try { this.doc.designMode="on"; + } catch (e) { return; } @@ -287,10 +311,10 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { if(this.sourceEditMode){ - Roo.get(this.iframe).addClass(['x-hidden','hide']); //FIXME - what's the BS styles for these + Roo.get(this.iframe).addClass(['x-hidden','hide', 'd-none']); //FIXME - what's the BS styles for these }else{ - Roo.get(this.iframe).removeClass(['x-hidden','hide']); + Roo.get(this.iframe).removeClass(['x-hidden','hide', 'd-none']); //this.iframe.className = ''; this.deferFocus(); } @@ -307,7 +331,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { * @param {String} html The HTML to be cleaned * return {String} The cleaned HTML */ - cleanHtml : function(html){ + cleanHtml : function(html) + { html = String(html); if(html.length > 5){ if(Roo.isSafari){ // strip safari nonsense @@ -325,11 +350,38 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { * Protected method that will not generally be called directly. Syncs the contents * of the editor iframe with the textarea. */ - syncValue : function(){ + syncValue : function() + { + //Roo.log("HtmlEditorCore:syncValue (EDITOR->TEXT)"); if(this.initialized){ + + this.undoManager.addEvent(); + + var bd = (this.doc.body || this.doc.documentElement); - //this.cleanUpPaste(); -- this is done else where and causes havoc.. - var html = bd.innerHTML; + + + var sel = this.win.getSelection(); + + var div = document.createElement('div'); + div.innerHTML = bd.innerHTML; + var gtx = div.getElementsByClassName('gtx-trans-icon'); // google translate - really annoying and difficult to get rid of. + if (gtx.length > 0) { + var rm = gtx.item(0).parentNode; + rm.parentNode.removeChild(rm); + } + + + if (this.enableBlocks) { + new Roo.htmleditor.FilterBlock({ node : div }); + } + //?? tidy? + var tidy = new Roo.htmleditor.TidySerializer({ + inner: true + }); + var html = tidy.serialize(div); + + if(Roo.isSafari){ var bs = bd.getAttribute('style'); // Safari puts text-align styles on the body element! var m = bs ? bs.match(/text-align:(.*?);/i) : false; @@ -374,24 +426,41 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { }, /** + * TEXTAREA -> EDITABLE * Protected method that will not generally be called directly. Pushes the value of the textarea * into the iframe editor. */ - pushValue : function(){ + pushValue : function() + { + //Roo.log("HtmlEditorCore:pushValue (TEXT->EDITOR)"); if(this.initialized){ var v = this.el.dom.value.trim(); -// if(v.length < 1){ -// v = ' '; -// } if(this.owner.fireEvent('beforepush', this, v) !== false){ var d = (this.doc.body || this.doc.documentElement); d.innerHTML = v; - this.cleanUpPaste(); + this.el.dom.value = d.innerHTML; this.owner.fireEvent('push', this, v); } + if (this.autoClean) { + new Roo.htmleditor.FilterParagraph({node : this.doc.body}); // paragraphs + new Roo.htmleditor.FilterSpan({node : this.doc.body}); // empty spans + } + if (this.enableBlocks) { + Roo.htmleditor.Block.initAll(this.doc.body); + } + + this.updateLanguage(); + + var lc = this.doc.body.lastChild; + if (lc && lc.nodeType == 1 && lc.getAttribute("contenteditable") == "false") { + // add an extra line at the end. + this.doc.body.appendChild(this.doc.createElement('br')); + } + + } }, @@ -453,28 +522,136 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { //var ss = this.el.getStyles( 'background-image', 'background-repeat'); //ss['background-attachment'] = 'fixed'; // w3c dbody.bgProperties = 'fixed'; // ie + dbody.setAttribute("translate", "no"); + //Roo.DomHelper.applyStyles(dbody, ss); Roo.EventManager.on(this.doc, { - //'mousedown': this.onEditorEvent, + 'mouseup': this.onEditorEvent, 'dblclick': this.onEditorEvent, 'click': this.onEditorEvent, 'keyup': this.onEditorEvent, + buffer:100, scope: this }); + Roo.EventManager.on(this.doc, { + 'paste': this.onPasteEvent, + scope : this + }); if(Roo.isGecko){ Roo.EventManager.on(this.doc, 'keypress', this.mozKeyPress, this); } + //??? needed??? if(Roo.isIE || Roo.isSafari || Roo.isOpera){ Roo.EventManager.on(this.doc, 'keydown', this.fixKeys, this); } this.initialized = true; + + // initialize special key events - enter + new Roo.htmleditor.KeyEnter({core : this}); + + + this.owner.fireEvent('initialize', this); this.pushValue(); }, - + // this is to prevent a href clicks resulting in a redirect? + + onPasteEvent : function(e,v) + { + // I think we better assume paste is going to be a dirty load of rubish from word.. + + // even pasting into a 'email version' of this widget will have to clean up that mess. + var cd = (e.browserEvent.clipboardData || window.clipboardData); + + // check what type of paste - if it's an image, then handle it differently. + if (cd.files.length > 0) { + // pasting images? + var urlAPI = (window.createObjectURL && window) || + (window.URL && URL.revokeObjectURL && URL) || + (window.webkitURL && webkitURL); + + var url = urlAPI.createObjectURL( cd.files[0]); + this.insertAtCursor(''); + return false; + } + + var html = cd.getData('text/html'); // clipboard event + var parser = new Roo.rtf.Parser(cd.getData('text/rtf')); + var images = parser.doc ? parser.doc.getElementsByType('pict') : []; + Roo.log(images); + //Roo.log(imgs); + // fixme.. + images = images.filter(function(g) { return !g.path.match(/^rtf\/(head|pgdsctbl|listtable)/); }) // ignore headers + .map(function(g) { return g.toDataURL(); }) + .filter(function(g) { return g != 'about:blank'; }); + + + html = this.cleanWordChars(html); + + var d = (new DOMParser().parseFromString(html, 'text/html')).body; + + + var sn = this.getParentElement(); + // check if d contains a table, and prevent nesting?? + //Roo.log(d.getElementsByTagName('table')); + //Roo.log(sn); + //Roo.log(sn.closest('table')); + if (d.getElementsByTagName('table').length && sn && sn.closest('table')) { + e.preventDefault(); + this.insertAtCursor("You can not nest tables"); + //Roo.log("prevent?"); // fixme - + return false; + } + + if (images.length > 0) { + Roo.each(d.getElementsByTagName('img'), function(img, i) { + img.setAttribute('src', images[i]); + }); + } + if (this.autoClean) { + new Roo.htmleditor.FilterStyleToTag({ node : d }); + new Roo.htmleditor.FilterAttributes({ + node : d, + attrib_white : ['href', 'src', 'name', 'align'], + attrib_clean : ['href', 'src' ] + }); + new Roo.htmleditor.FilterBlack({ node : d, tag : this.black}); + // should be fonts.. + new Roo.htmleditor.FilterKeepChildren({node : d, tag : [ 'FONT', 'O:P' ]} ); + new Roo.htmleditor.FilterParagraph({ node : d }); + new Roo.htmleditor.FilterSpan({ node : d }); + new Roo.htmleditor.FilterLongBr({ node : d }); + } + if (this.enableBlocks) { + + Array.from(d.getElementsByTagName('img')).forEach(function(img) { + if (img.closest('figure')) { // assume!! that it's aready + return; + } + var fig = new Roo.htmleditor.BlockFigure({ + image_src : img.src + }); + fig.updateElement(img); // replace it.. + + }); + } + + + this.insertAtCursor(d.innerHTML.replace(/ /g,' ')); + if (this.enableBlocks) { + Roo.htmleditor.Block.initAll(this.doc.body); + } + + + e.preventDefault(); + return false; + // default behaveiour should be our local cleanup paste? (optional?) + // for simple editor - we want to hammer the paste and get rid of everything... - so over-rideable.. + //this.owner.fireEvent('paste', e, v); + }, // private onDestroy : function(){ @@ -496,7 +673,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { onFirstFocus : function(){ this.assignDocWin(); - + this.undoManager = new Roo.lib.UndoManager(100,(this.doc.body || this.doc.documentElement)); this.activated = true; @@ -541,10 +718,48 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { onEditorEvent : function(e) { - this.owner.fireEvent('editorevent', this, e); + + + if (e && (e.ctrlKey || e.metaKey) && e.keyCode === 90) { + return; // we do not handle this.. (undo manager does..) + } + // in theory this detects if the last element is not a br, then we try and do that. + // its so clicking in space at bottom triggers adding a br and moving the cursor. + if (e && + e.target.nodeName == 'BODY' && + e.type == "mouseup" && + this.doc.body.lastChild + ) { + var lc = this.doc.body.lastChild; + // gtx-trans is google translate plugin adding crap. + while ((lc.nodeType == 3 && lc.nodeValue == '') || lc.id == 'gtx-trans') { + lc = lc.previousSibling; + } + if (lc.nodeType == 1 && lc.nodeName != 'BR') { + // if last element is
- then dont do anything. + + var ns = this.doc.createElement('br'); + this.doc.body.appendChild(ns); + range = this.doc.createRange(); + range.setStartAfter(ns); + range.collapse(true); + var sel = this.win.getSelection(); + sel.removeAllRanges(); + sel.addRange(range); + } + } + + + + this.fireEditorEvent(e); // this.updateToolbar(); this.syncValue(); //we can not sync so often.. sync cleans, so this breaks stuff }, + + fireEditorEvent: function(e) + { + this.owner.fireEvent('editorevent', this, e); + }, insertTag : function(tg) { @@ -566,7 +781,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { } this.execCmd("formatblock", tg); - + this.undoManager.addEvent(); }, insertText : function(txt) @@ -578,6 +793,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { //alert(Sender.getAttribute('label')); range.insertNode(this.doc.createTextNode(txt)); + this.undoManager.addEvent(); } , @@ -588,7 +804,37 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { * @param {String} cmd The Midas command * @param {String/Boolean} value (optional) The value to pass to the command (defaults to null) */ - relayCmd : function(cmd, value){ + relayCmd : function(cmd, value) + { + + switch (cmd) { + case 'justifyleft': + case 'justifyright': + case 'justifycenter': + // if we are in a cell, then we will adjust the + var n = this.getParentElement(); + var td = n.closest('td'); + if (td) { + var bl = Roo.htmleditor.Block.factory(td); + bl.textAlign = cmd.replace('justify',''); + bl.updateElement(); + this.owner.fireEvent('editorevent', this); + return; + } + this.execCmd('styleWithCSS', true); // + break; + case 'bold': + case 'italic': + // if there is no selection, then we insert, and set the curson inside it.. + this.execCmd('styleWithCSS', false); + break; + + + default: + break; + } + + this.win.focus(); this.execCmd(cmd, value); this.owner.fireEvent('editorevent', this); @@ -621,20 +867,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { if(!this.activated){ return; } - /* - if(Roo.isIE){ - this.win.focus(); - var r = this.doc.selection.createRange(); - if(r){ - r.collapse(true); - r.pasteHTML(text); - this.syncValue(); - this.deferFocus(); - - } - return; - } - */ + if(Roo.isGecko || Roo.isOpera || Roo.isSafari){ this.win.focus(); @@ -644,19 +877,31 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { var win = this.win; if (win.getSelection && win.getSelection().getRangeAt) { + + // delete the existing? + + this.createRange(this.getSelection()).deleteContents(); range = win.getSelection().getRangeAt(0); node = typeof(text) == 'string' ? range.createContextualFragment(text) : text; range.insertNode(node); + range = range.cloneRange(); + range.collapse(false); + + win.getSelection().removeAllRanges(); + win.getSelection().addRange(range); + + + } else if (win.document.selection && win.document.selection.createRange) { // no firefox support var txt = typeof(text) == 'string' ? text : text.outerHTML; win.document.selection.createRange().pasteHTML(txt); + } else { // no firefox support var txt = typeof(text) == 'string' ? text : text.outerHTML; this.execCmd('InsertHTML', txt); } - this.syncValue(); this.deferFocus(); @@ -681,15 +926,17 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { cmd = 'underline'; break; - case 'v': - this.cleanUpPaste.defer(100, this); - return; + //case 'v': + // this.cleanUpPaste.defer(100, this); + // return; } if(cmd){ - this.win.focus(); - this.execCmd(cmd); - this.deferFocus(); + + this.relayCmd(cmd); + //this.win.focus(); + //this.execCmd(cmd); + //this.deferFocus(); e.preventDefault(); } @@ -699,6 +946,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { // private fixKeys : function(){ // load time branching for fastest keydown performance + + if(Roo.isIE){ return function(e){ var k = e.getKey(), r; @@ -712,23 +961,25 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { } return; } - + /// this is handled by Roo.htmleditor.KeyEnter + /* if(k == e.ENTER){ r = this.doc.selection.createRange(); if(r){ var target = r.parentElement(); if(!target || target.tagName.toLowerCase() != 'li'){ e.stopEvent(); - r.pasteHTML('
'); + r.pasteHTML('
'); r.collapse(false); r.select(); } } } - if (String.fromCharCode(k).toLowerCase() == 'v') { // paste - this.cleanUpPaste.defer(100, this); - return; - } + */ + //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste + // this.cleanUpPaste.defer(100, this); + // return; + //} }; @@ -741,10 +992,11 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { this.execCmd('InsertHTML','    '); this.deferFocus(); } - if (String.fromCharCode(k).toLowerCase() == 'v') { // paste - this.cleanUpPaste.defer(100, this); - return; - } + + //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste + // this.cleanUpPaste.defer(100, this); + // return; + //} }; }else if(Roo.isSafari){ @@ -757,10 +1009,12 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { this.deferFocus(); return; } - if (String.fromCharCode(k).toLowerCase() == 'v') { // paste - this.cleanUpPaste.defer(100, this); - return; - } + this.mozKeyPress(e); + + //if (String.fromCharCode(k).toLowerCase() == 'v') { // paste + // this.cleanUpPaste.defer(100, this); + // return; + // } }; } @@ -790,7 +1044,27 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { getSelection : function() { this.assignDocWin(); - return Roo.isIE ? this.doc.selection : this.win.getSelection(); + return Roo.lib.Selection.wrap(Roo.isIE ? this.doc.selection : this.win.getSelection(), this.doc); + }, + /** + * Select a dom node + * @param {DomElement} node the node to select + */ + selectNode : function(node, collapse) + { + var nodeRange = node.ownerDocument.createRange(); + try { + nodeRange.selectNode(node); + } catch (e) { + nodeRange.selectNodeContents(node); + } + if (collapse === true) { + nodeRange.collapse(true); + } + // + var s = this.win.getSelection(); + s.removeAllRanges(); + s.addRange(nodeRange); }, getSelectedNode: function() @@ -799,8 +1073,7 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { // should we cache this!!!! - - + var range = this.createRange(this.getSelection()).cloneRange(); @@ -864,6 +1137,8 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { return nodes[0]; }, + + createRange: function(sel) { // this has strange effects when using with @@ -981,26 +1256,21 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { // fully contined. return 3; }, - - // private? - in a new class? - cleanUpPaste : function() - { - // cleans up the whole document.. - Roo.log('cleanuppaste'); - - this.cleanUpChildren(this.doc.body); - var clean = this.cleanWordChars(this.doc.body.innerHTML); - if (clean != this.doc.body.innerHTML) { - this.doc.body.innerHTML = clean; - } - - }, - + cleanWordChars : function(input) {// change the chars to hex code - var he = Roo.HtmlEditorCore; + var swapCodes = [ + [ 8211, "–" ], + [ 8212, "—" ], + [ 8216, "'" ], + [ 8217, "'" ], + [ 8220, '"' ], + [ 8221, '"' ], + [ 8226, "*" ], + [ 8230, "..." ] + ]; var output = input; - Roo.each(he.swapCodes, function(sw) { + Roo.each(swapCodes, function(sw) { var swapper = new RegExp("\\u" + sw[0].toString(16), "g"); // hex codes output = output.replace(swapper, sw[1]); @@ -1009,487 +1279,60 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { return output; }, - - cleanUpChildren : function (n) - { - if (!n.childNodes.length) { - return; - } - for (var i = n.childNodes.length-1; i > -1 ; i--) { - this.cleanUpChild(n.childNodes[i]); - } - }, - + cleanUpChild : function (node) { - var ed = this; - //console.log(node); - if (node.nodeName == "#text") { - // clean up silly Windows -- stuff? - return; - } - if (node.nodeName == "#comment") { - if (!this.allowComments) { - node.parentNode.removeChild(node); - } - // clean up silly Windows -- stuff? - return; - } - var lcname = node.tagName.toLowerCase(); - // we ignore whitelists... ?? = not really the way to go, but we probably have not got a full - // whitelist of tags.. - - if (this.black.indexOf(lcname) > -1 && this.clearUp ) { - // remove node. - node.parentNode.removeChild(node); - return; - - } - - var remove_keep_children= Roo.HtmlEditorCore.remove.indexOf(node.tagName.toLowerCase()) > -1; - - // spans with no attributes - just remove them.. - if ((!node.attributes || !node.attributes.length) && lcname == 'span') { - remove_keep_children = true; - } - - // remove as rendering on yahoo mailer is borked with this. - // this will have to be flaged elsewhere - perhaps ablack=name... on the mailer.. - - //if (node.tagName.toLowerCase() == 'a' && !node.hasAttribute('href')) { - // remove_keep_children = true; - //} - - if (remove_keep_children) { - this.cleanUpChildren(node); - // inserts everything just before this node... - while (node.childNodes.length) { - var cn = node.childNodes[0]; - node.removeChild(cn); - node.parentNode.insertBefore(cn, node); - } - node.parentNode.removeChild(node); - return; - } - - if (!node.attributes || !node.attributes.length) { - - - - - this.cleanUpChildren(node); - return; - } - - function cleanAttr(n,v) - { - - if (v.match(/^\./) || v.match(/^\//)) { - return; - } - if (v.match(/^(http|https):\/\//) || v.match(/^mailto:/) || v.match(/^ftp:/)) { - return; - } - if (v.match(/^#/)) { - return; - } - if (v.match(/^\{/)) { // allow template editing. - return; - } -// Roo.log("(REMOVE TAG)"+ node.tagName +'.' + n + '=' + v); - node.removeAttribute(n); - - } - - var cwhite = this.cwhite; - var cblack = this.cblack; - - function cleanStyle(n,v) - { - if (v.match(/expression/)) { //XSS?? should we even bother.. - node.removeAttribute(n); - return; - } - - var parts = v.split(/;/); - var clean = []; - - Roo.each(parts, function(p) { - p = p.replace(/^\s+/g,'').replace(/\s+$/g,''); - if (!p.length) { - return true; - } - var l = p.split(':').shift().replace(/\s+/g,''); - l = l.replace(/^\s+/g,'').replace(/\s+$/g,''); - - if ( cwhite.length && cblack.indexOf(l) > -1) { -// Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v); - //node.removeAttribute(n); - return true; - } - //Roo.log() - // only allow 'c whitelisted system attributes' - if ( cwhite.length && cwhite.indexOf(l) < 0 && cwhite.indexOf(l.toLowerCase()) < 0 ) { -// Roo.log('(REMOVE CSS)' + node.tagName +'.' + n + ':'+l + '=' + v); - //node.removeAttribute(n); - return true; - } - - - - - clean.push(p); - return true; - }); - if (clean.length) { - node.setAttribute(n, clean.join(';')); - } else { - node.removeAttribute(n); - } - - } - - - for (var i = node.attributes.length-1; i > -1 ; i--) { - var a = node.attributes[i]; - //console.log(a); - - if (a.name.toLowerCase().substr(0,2)=='on') { - node.removeAttribute(a.name); - continue; - } - if (Roo.HtmlEditorCore.ablack.indexOf(a.name.toLowerCase()) > -1) { - node.removeAttribute(a.name); - continue; - } - if (Roo.HtmlEditorCore.aclean.indexOf(a.name.toLowerCase()) > -1) { - cleanAttr(a.name,a.value); // fixme.. - continue; - } - if (a.name == 'style') { - cleanStyle(a.name,a.value); - continue; - } - /// clean up MS crap.. - // tecnically this should be a list of valid class'es.. - - - if (a.name == 'class') { - if (a.value.match(/^Mso/)) { - node.removeAttribute('class'); - } - - if (a.value.match(/^body$/)) { - node.removeAttribute('class'); - } - continue; - } - - // style cleanup!? - // class cleanup? - - } - - - this.cleanUpChildren(node); + new Roo.htmleditor.FilterComment({node : node}); + new Roo.htmleditor.FilterAttributes({ + node : node, + attrib_black : this.ablack, + attrib_clean : this.aclean, + style_white : this.cwhite, + style_black : this.cblack + }); + new Roo.htmleditor.FilterBlack({ node : node, tag : this.black}); + new Roo.htmleditor.FilterKeepChildren({node : node, tag : this.tag_remove} ); + }, /** * Clean up MS wordisms... + * @deprecated - use filter directly */ cleanWord : function(node) { - if (!node) { - this.cleanWord(this.doc.body); - return; - } - - if( - node.nodeName == 'SPAN' && - !node.hasAttributes() && - node.childNodes.length == 1 && - node.firstChild.nodeName == "#text" - ) { - var textNode = node.firstChild; - node.removeChild(textNode); - if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters.. - node.parentNode.insertBefore(node.ownerDocument.createTextNode(" "), node); - } - node.parentNode.insertBefore(textNode, node); - if (node.getAttribute('lang') != 'zh-CN') { // do not space pad on chinese characters.. - node.parentNode.insertBefore(node.ownerDocument.createTextNode(" ") , node); - } - node.parentNode.removeChild(node); - } - - if (node.nodeName == "#text") { - // clean up silly Windows -- stuff? - return; - } - if (node.nodeName == "#comment") { - node.parentNode.removeChild(node); - // clean up silly Windows -- stuff? - return; - } - - if (node.tagName.toLowerCase().match(/^(style|script|applet|embed|noframes|noscript)$/)) { - node.parentNode.removeChild(node); - return; - } - //Roo.log(node.tagName); - // remove - but keep children.. - if (node.tagName.toLowerCase().match(/^(meta|link|\\?xml:|st1:|o:|v:|font)/)) { - //Roo.log('-- removed'); - while (node.childNodes.length) { - var cn = node.childNodes[0]; - node.removeChild(cn); - node.parentNode.insertBefore(cn, node); - // move node to parent - and clean it.. - this.cleanWord(cn); - } - node.parentNode.removeChild(node); - /// no need to iterate chidlren = it's got none.. - //this.iterateChildren(node, this.cleanWord); - return; - } - // clean styles - if (node.className.length) { - - var cn = node.className.split(/\W+/); - var cna = []; - Roo.each(cn, function(cls) { - if (cls.match(/Mso[a-zA-Z]+/)) { - return; - } - cna.push(cls); - }); - node.className = cna.length ? cna.join(' ') : ''; - if (!cna.length) { - node.removeAttribute("class"); - } - } - - if (node.hasAttribute("lang")) { - node.removeAttribute("lang"); - } - - if (node.hasAttribute("style")) { - - var styles = node.getAttribute("style").split(";"); - var nstyle = []; - Roo.each(styles, function(s) { - if (!s.match(/:/)) { - return; - } - var kv = s.split(":"); - if (kv[0].match(/^(mso-|line|font|background|margin|padding|color)/)) { - return; - } - // what ever is left... we allow. - nstyle.push(s); - }); - node.setAttribute("style", nstyle.length ? nstyle.join(';') : ''); - if (!nstyle.length) { - node.removeAttribute('style'); - } - } - this.iterateChildren(node, this.cleanWord); + new Roo.htmleditor.FilterWord({ node : node ? node : this.doc.body }); - - - }, - /** - * iterateChildren of a Node, calling fn each time, using this as the scole.. - * @param {DomNode} node node to iterate children of. - * @param {Function} fn method of this class to call on each item. - */ - iterateChildren : function(node, fn) - { - if (!node.childNodes.length) { - return; - } - for (var i = node.childNodes.length-1; i > -1 ; i--) { - fn.call(this, node.childNodes[i]) - } }, - + /** - * cleanTableWidths. - * - * Quite often pasting from word etc.. results in tables with column and widths. - * This does not work well on fluid HTML layouts - like emails. - so this code should hunt an destroy them.. - * + + * @deprecated - use filters */ cleanTableWidths : function(node) { - - - if (!node) { - this.cleanTableWidths(this.doc.body); - return; - } - - // ignore list... - if (node.nodeName == "#text" || node.nodeName == "#comment") { - return; - } - Roo.log(node.tagName); - if (!node.tagName.toLowerCase().match(/^(table|td|tr)$/)) { - this.iterateChildren(node, this.cleanTableWidths); - return; - } - if (node.hasAttribute('width')) { - node.removeAttribute('width'); - } - - - if (node.hasAttribute("style")) { - // pretty basic... - - var styles = node.getAttribute("style").split(";"); - var nstyle = []; - Roo.each(styles, function(s) { - if (!s.match(/:/)) { - return; - } - var kv = s.split(":"); - if (kv[0].match(/^\s*(width|min-width)\s*$/)) { - return; - } - // what ever is left... we allow. - nstyle.push(s); - }); - node.setAttribute("style", nstyle.length ? nstyle.join(';') : ''); - if (!nstyle.length) { - node.removeAttribute('style'); - } - } - - this.iterateChildren(node, this.cleanTableWidths); - + new Roo.htmleditor.FilterTableWidth({ node : node ? node : this.doc.body}); + }, - - - - domToHTML : function(currentElement, depth, nopadtext) { - - depth = depth || 0; - nopadtext = nopadtext || false; - - if (!currentElement) { - return this.domToHTML(this.doc.body); - } - - //Roo.log(currentElement); - var j; - var allText = false; - var nodeName = currentElement.nodeName; - var tagName = Roo.util.Format.htmlEncode(currentElement.tagName); - - if (nodeName == '#text') { - - return nopadtext ? currentElement.nodeValue : currentElement.nodeValue.trim(); - } - - - var ret = ''; - if (nodeName != 'BODY') { - - var i = 0; - // Prints the node tagName, such as , , etc - if (tagName) { - var attr = []; - for(i = 0; i < currentElement.attributes.length;i++) { - // quoting? - var aname = currentElement.attributes.item(i).name; - if (!currentElement.attributes.item(i).value.length) { - continue; - } - attr.push(aname + '="' + Roo.util.Format.htmlEncode(currentElement.attributes.item(i).value) + '"' ); - } - - ret = "<"+currentElement.tagName+ ( attr.length ? (' ' + attr.join(' ') ) : '') + ">"; - } - else { - - // eack - } - } else { - tagName = false; - } - if (['IMG', 'BR', 'HR', 'INPUT'].indexOf(tagName) > -1) { - return ret; - } - if (['PRE', 'TEXTAREA', 'TD', 'A', 'SPAN'].indexOf(tagName) > -1) { // or code? - nopadtext = true; - } - - - // Traverse the tree - i = 0; - var currentElementChild = currentElement.childNodes.item(i); - var allText = true; - var innerHTML = ''; - lastnode = ''; - while (currentElementChild) { - // Formatting code (indent the tree so it looks nice on the screen) - var nopad = nopadtext; - if (lastnode == 'SPAN') { - nopad = true; - } - // text - if (currentElementChild.nodeName == '#text') { - var toadd = Roo.util.Format.htmlEncode(currentElementChild.nodeValue); - toadd = nopadtext ? toadd : toadd.trim(); - if (!nopad && toadd.length > 80) { - innerHTML += "\n" + (new Array( depth + 1 )).join( " " ); - } - innerHTML += toadd; - - i++; - currentElementChild = currentElement.childNodes.item(i); - lastNode = ''; - continue; - } - allText = false; - - innerHTML += nopad ? '' : "\n" + (new Array( depth + 1 )).join( " " ); - - // Recursively traverse the tree structure of the child node - innerHTML += this.domToHTML(currentElementChild, depth+1, nopadtext); - lastnode = currentElementChild.nodeName; - i++; - currentElementChild=currentElement.childNodes.item(i); - } - - ret += innerHTML; - - if (!allText) { - // The remaining code is mostly for formatting the tree - ret+= nopadtext ? '' : "\n" + (new Array( depth )).join( " " ); - } - - - if (tagName) { - ret+= ""; - } - return ret; - - }, + applyBlacklists : function() { var w = typeof(this.owner.white) != 'undefined' && this.owner.white ? this.owner.white : []; var b = typeof(this.owner.black) != 'undefined' && this.owner.black ? this.owner.black : []; + this.aclean = typeof(this.owner.aclean) != 'undefined' && this.owner.aclean ? this.owner.aclean : Roo.HtmlEditorCore.aclean; + this.ablack = typeof(this.owner.ablack) != 'undefined' && this.owner.ablack ? this.owner.ablack : Roo.HtmlEditorCore.ablack; + this.tag_remove = typeof(this.owner.tag_remove) != 'undefined' && this.owner.tag_remove ? this.owner.tag_remove : Roo.HtmlEditorCore.tag_remove; + this.white = []; this.black = []; Roo.each(Roo.HtmlEditorCore.white, function(tag) { @@ -1607,6 +1450,16 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { }, + + updateLanguage : function() + { + if (!this.iframe || !this.iframe.contentDocument) { + return; + } + Roo.get(this.iframe.contentDocument.body).attr("lang", this.language); + }, + + removeStylesheets : function() { var _this = this; @@ -1671,36 +1524,40 @@ Roo.extend(Roo.HtmlEditorCore, Roo.Component, { }); Roo.HtmlEditorCore.white = [ - 'area', 'br', 'img', 'input', 'hr', 'wbr', + 'AREA', 'BR', 'IMG', 'INPUT', 'HR', 'WBR', - 'address', 'blockquote', 'center', 'dd', 'dir', 'div', - 'dl', 'dt', 'h1', 'h2', 'h3', 'h4', - 'h5', 'h6', 'hr', 'isindex', 'listing', 'marquee', - 'menu', 'multicol', 'ol', 'p', 'plaintext', 'pre', - 'table', 'ul', 'xmp', + 'ADDRESS', 'BLOCKQUOTE', 'CENTER', 'DD', 'DIR', 'DIV', + 'DL', 'DT', 'H1', 'H2', 'H3', 'H4', + 'H5', 'H6', 'HR', 'ISINDEX', 'LISTING', 'MARQUEE', + 'MENU', 'MULTICOL', 'OL', 'P', 'PLAINTEXT', 'PRE', + 'TABLE', 'UL', 'XMP', - 'caption', 'col', 'colgroup', 'tbody', 'td', 'tfoot', 'th', - 'thead', 'tr', + 'CAPTION', 'COL', 'COLGROUP', 'TBODY', 'TD', 'TFOOT', 'TH', + 'THEAD', 'TR', - 'dir', 'menu', 'ol', 'ul', 'dl', + 'DIR', 'MENU', 'OL', 'UL', 'DL', - 'embed', 'object' + 'EMBED', 'OBJECT' ]; Roo.HtmlEditorCore.black = [ // 'embed', 'object', // enable - backend responsiblity to clean thiese - 'applet', // - 'base', 'basefont', 'bgsound', 'blink', 'body', - 'frame', 'frameset', 'head', 'html', 'ilayer', - 'iframe', 'layer', 'link', 'meta', 'object', - 'script', 'style' ,'title', 'xml' // clean later.. + 'APPLET', // + 'BASE', 'BASEFONT', 'BGSOUND', 'BLINK', 'BODY', + 'FRAME', 'FRAMESET', 'HEAD', 'HTML', 'ILAYER', + 'IFRAME', 'LAYER', 'LINK', 'META', 'OBJECT', + 'SCRIPT', 'STYLE' ,'TITLE', 'XML', + //'FONT' // CLEAN LATER.. + 'COLGROUP', 'COL' // messy tables. + + ]; -Roo.HtmlEditorCore.clean = [ - 'script', 'style', 'title', 'xml' +Roo.HtmlEditorCore.clean = [ // ?? needed??? + 'SCRIPT', 'STYLE', 'TITLE', 'XML' ]; -Roo.HtmlEditorCore.remove = [ - 'font' +Roo.HtmlEditorCore.tag_remove = [ + 'FONT', 'TBODY' ]; // attributes.. @@ -1731,15 +1588,6 @@ Roo.HtmlEditorCore.cblack= [ ]; -Roo.HtmlEditorCore.swapCodes =[ - [ 8211, "–" ], - [ 8212, "—" ], - [ 8216, "'" ], - [ 8217, "'" ], - [ 8220, '"' ], - [ 8221, '"' ], - [ 8226, "*" ], - [ 8230, "..." ] -]; + \ No newline at end of file diff --git a/Roo/MessageBox.js b/Roo/MessageBox.js index a43dd34826..5f640f075b 100644 --- a/Roo/MessageBox.js +++ b/Roo/MessageBox.js @@ -11,6 +11,7 @@ /** * @class Roo.MessageBox + * @static * Utility class for generating different styles of message boxes. The alias Roo.Msg can also be used. * Example usage: *

@@ -120,6 +121,7 @@ Roo.MessageBox = function(){
                         }
                     }
                 });
+              
                 dlg.on("hide", handleHide);
                 mask = dlg.mask;
                 dlg.addKeyListener(27, handleEsc);
@@ -363,6 +365,7 @@ Roo.Msg.show({
                 d.animateTarget = null;
                 d.show(options.animEl);
             }
+            dlg.toFront();
             return this;
         },
 
diff --git a/Roo/PagingToolbar.js b/Roo/PagingToolbar.js
index 9b0d7ec9fc..22f35d3f9b 100644
--- a/Roo/PagingToolbar.js
+++ b/Roo/PagingToolbar.js
@@ -12,7 +12,7 @@
 /**
  * @class Roo.PagingToolbar
  * @extends Roo.Toolbar
- * @children   Roo.Toolbar.Item Roo.form.Field
+ * @children   Roo.Toolbar.Item Roo.Toolbar.Button Roo.Toolbar.SplitButton Roo.form.Field
  * A specialized toolbar that is bound to a {@link Roo.data.Store} and provides automatic paging controls.
  * @constructor
  * Create a new PagingToolbar
@@ -255,7 +255,11 @@ Roo.extend(Roo.PagingToolbar, Roo.Toolbar, {
             this.loading.disable();
         }
     },
-
+    /**
+     * event that occurs when you click on the navigation buttons - can be used to trigger load of a grid.
+     * @param {String} which (first|prev|next|last|refresh)  which button to press.
+     *
+     */
     // private
     onClick : function(which){
         var ds = this.ds;
diff --git a/Roo/Toolbar.js b/Roo/Toolbar.js
index 05edb0199f..cee6171a70 100644
--- a/Roo/Toolbar.js
+++ b/Roo/Toolbar.js
@@ -11,7 +11,7 @@
 
 /**
  * @class Roo.Toolbar
- * @children   Roo.Toolbar.Item Roo.form.Field
+ * @children   Roo.Toolbar.Item Roo.Toolbar.Button Roo.Toolbar.SplitButton Roo.form.Field 
  * Basic Toolbar class.
  * @constructor
  * Creates a new Toolbar
@@ -547,7 +547,23 @@ Roo.extend(Roo.Toolbar.TextItem, Roo.Toolbar.Item, {
      
     enable:Roo.emptyFn,
     disable:Roo.emptyFn,
-    focus:Roo.emptyFn
+    focus:Roo.emptyFn,
+     /**
+     * Shows this button
+     */
+    show: function(){
+        this.hidden = false;
+        this.el.style.display = "";
+    },
+    
+    /**
+     * Hides this button
+     */
+    hide: function(){
+        this.hidden = true;
+        this.el.style.display = "none";
+    }
+    
 });
 
 /**
diff --git a/Roo/bootstrap/form/SecurePass.js b/Roo/bootstrap/form/SecurePass.js
index e921d79187..b75bc8dbb5 100644
--- a/Roo/bootstrap/form/SecurePass.js
+++ b/Roo/bootstrap/form/SecurePass.js
@@ -351,4 +351,4 @@ Roo.extend(Roo.bootstrap.form.SecurePass, Roo.bootstrap.form.Input, {
         return this.IsLongEnough(pwd, 6) || !this.IsLongEnough(pwd, 0);
     }
           
-})
\ No newline at end of file
+});
\ No newline at end of file
diff --git a/Roo/data/Store.js b/Roo/data/Store.js
index 4d891f9568..d75d3087cc 100644
--- a/Roo/data/Store.js
+++ b/Roo/data/Store.js
@@ -332,6 +332,16 @@ Roo.extend(Roo.data.Store, Roo.util.Observable, {
      * 

* @param {Object} options An object containing properties which control loading options: