From: Alan Knowles Date: Fri, 2 Jul 2021 06:35:21 +0000 (+0800) Subject: svg changes X-Git-Url: http://git.roojs.org/?p=roojs1;a=commitdiff_plain;h=d83e6f560d529fee838ee06b89f8f6872c2dd0ea svg changes --- diff --git a/Roo/BoxComponent.js b/Roo/BoxComponent.js index ef86fa5216..fa1e294bc0 100644 --- a/Roo/BoxComponent.js +++ b/Roo/BoxComponent.js @@ -14,7 +14,7 @@ * @extends Roo.Component * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All - * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext + * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo * layout containers. * @constructor * @param {Roo.Element/String/Object} config The configuration options. diff --git a/Roo/Element.js b/Roo/Element.js index 36d6dce660..77d6108fab 100644 --- a/Roo/Element.js +++ b/Roo/Element.js @@ -85,7 +85,8 @@ if(opt.anim.isAnimated()){ * @param {String/HTMLElement} element * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class). */ - Roo.Element = function(element, forceNew){ + Roo.Element = function(element, forceNew) + { var dom = typeof element == "string" ? document.getElementById(element) : element; if(!dom){ // invalid id/element @@ -107,6 +108,8 @@ if(opt.anim.isAnimated()){ * @type String */ this.id = id || Roo.id(dom); + + this.listeners = {}; }; var El = Roo.Element; @@ -1180,13 +1183,30 @@ if(opt.anim.isAnimated()){ * @param {Object} scope (optional) The scope (this object) of the fn * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options */ - addListener : function(eventName, fn, scope, options){ - if (this.dom) { - Roo.EventManager.on(this.dom, eventName, fn, scope || this, options); - } - if (eventName == 'dblclick') { + addListener : function(eventName, fn, scope, options) + { + if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch. this.addListener('touchstart', this.onTapHandler, this); } + + // we need to handle a special case where dom element is a svg element. + // in this case we do not actua + if (!this.dom) { + return; + } + + if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) { + if (typeof(this.listeners[eventName]) == 'undefined') { + this.listeners[eventName] = new Roo.util.Event(this, eventName); + } + this.listeners[eventName].addListener(fn, scope, options); + return; + } + + + Roo.EventManager.on(this.dom, eventName, fn, scope || this, options); + + }, tapedTwice : false, onTapHandler : function(event) @@ -1215,10 +1235,15 @@ if(opt.anim.isAnimated()){ * Removes an event handler from this element * @param {String} eventName the type of event to remove * @param {Function} fn the method the event invokes + * @param {Function} scope (needed for svg fake listeners) * @return {Roo.Element} this */ - removeListener : function(eventName, fn){ + removeListener : function(eventName, fn, scope){ Roo.EventManager.removeListener(this.dom, eventName, fn); + if (typeof(this.listeners[eventName]) == 'undefined') { + return this; + } + this.listeners[eventName].removeListener(fn, scope); return this; }, @@ -1228,6 +1253,7 @@ if(opt.anim.isAnimated()){ */ removeAllListeners : function(){ E.purgeElement(this.dom); + this.listeners = {}; return this; }, @@ -1237,6 +1263,7 @@ if(opt.anim.isAnimated()){ }); }, + /** * Set the opacity of the element * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc diff --git a/Roo/EventManager.js b/Roo/EventManager.js index 3c9a41a0b8..d23defd6b4 100644 --- a/Roo/EventManager.js +++ b/Roo/EventManager.js @@ -124,7 +124,8 @@ Roo.EventManager = function(){ - var listen = function(element, ename, opt, fn, scope){ + var listen = function(element, ename, opt, fn, scope) + { var o = (!opt || typeof opt == "boolean") ? {} : opt; fn = fn || o.fn; scope = scope || o.scope; var el = Roo.getDom(element); @@ -181,7 +182,9 @@ Roo.EventManager = function(){ - E.on(el, ename, h); + E.on(el, ename, h); // this adds the actuall listener to the object.. + + if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery el.addEventListener("DOMMouseScroll", h, false); E.on(window, 'unload', function(){ diff --git a/Roo/bootstrap/Popover.js b/Roo/bootstrap/Popover.js index bcdc7814aa..376b2d3c00 100644 --- a/Roo/bootstrap/Popover.js +++ b/Roo/bootstrap/Popover.js @@ -444,15 +444,18 @@ Roo.apply(Roo.bootstrap.Popover, { clickHander : false, + onMouseDown : function(e) { - if (!e.getTarget(".roo-popover")) { + if (this.popup.length && !e.getTarget(".roo-popover") && this.popup.length) { + /// what is nothing is showing.. this.hideAll(); } }, + popups : [], register : function(popup) @@ -461,14 +464,22 @@ Roo.apply(Roo.bootstrap.Popover, { Roo.bootstrap.Popover.clickHandler = Roo.get(document).on("mousedown", Roo.bootstrap.Popover.onMouseDown, Roo.bootstrap.Popover); } // hide other popups. - this.hideAll(); - this.popups.push(popup); + popup.on('show', Roo.bootstrap.Popover.onShow, popup); + popup.on('hide', Roo.bootstrap.Popover.onHide, popup); + this.hideAll(); //<< why? + //this.popups.push(popup); }, hideAll : function() { this.popups.forEach(function(p) { p.hide(); }); - } + }, + onShow : function() { + Roo.bootstrap.Popover.popups.push(this); + }, + onHide : function() { + Roo.bootstrap.Popover.popups.remove(this); + }, }); \ No newline at end of file diff --git a/Roo/svg/Canvas.js b/Roo/svg/Canvas.js new file mode 100644 index 0000000000..15d36c07f5 --- /dev/null +++ b/Roo/svg/Canvas.js @@ -0,0 +1,104 @@ +/** + * + * The SVG element.. - with a 'g' subelement, that can handle moving / panning etc.. + * + * + * The SVG element is the only element that handles events + * if you click on it, it will look for roo-svg-observable in the event handler and pass on events to children. + * + * + * + * + */ + +Roo.namespace('Roo.svg'); + +Roo.svg.Canvas = function(cfg) +{ + Roo.svg.Canvas.superclass.constructor.call(this, cfg); + this.addEvents({ + 'click' : true, + 'dblclick' : true, + 'context' : true, + }); + +} + +Roo.extend(Roo.svg.Canvas, Roo.bootstrap.Component, { + + + + getAutoCreate : function(){ + + + return { + ns: "svg", + xmlns: "http://www.w3.org/2000/svg", + tag: "svg", + width: 100, + height: 100, + cn : [ + { + ns: "svg", + tag: "g", + focusable : 'true' + } + ] + }; + }, + + initEvents: function() + { + Roo.svg.Canvas.superclass.initEvents.call(this); + // others... + + this.el.on('click', this.relayEvent, this); + this.el.on('dblclick', this.relayEvent, this); + this.el.on('context', this.relayEvent, this); // ??? any others + this.g = this.el.select('g', true).first(); + + + }, + + relayEvent: function(e) + { + //e.type + var cel = e.getTarget('roo-svg-observable', false, true); + if (!cel || typeof(cel.listeners[e.type]) == 'undefined') { + this.fireEvent(e.type) + return; + } + cel.listeners[e.type].fire(e, cel); + + }, + + + fitToParent : function() + { + // should it fit Horizontal - as per this? + // or fit full ? // in which case pan/zoom done by drag? + + if (!this.el.dom.parentNode) { // check if this Element still exists + return; + } + (function() { + var p = Roo.get(this.el.dom.parentNode); + var gs = this.g.dom.getBBox(); + var ratio = gs.height / gs.width; + ratio = isNaN(ratio) || ratio < 0.2 ? 1 : ratio; + var x = p.getComputedWidth() - p.getFrameWidth('lr') - 20; // close as possible with scroll bar + this.el.attr({ + width : x, + height : x * ratio //p.getComputedHeight() - p.getFrameWidth('tb') + }); + if (gs.height) { + this.el.attr("viewBox", gs.x + " " + gs.y + " " + gs.width + " " + gs.height); + } + + }).defer(300, this); + + } + + + +}); \ No newline at end of file diff --git a/Roo/svg/Element.js b/Roo/svg/Element.js new file mode 100644 index 0000000000..42fc00be4c --- /dev/null +++ b/Roo/svg/Element.js @@ -0,0 +1,116 @@ +/** + * + * The SVG element.. - with a 'g' subelement, that can handle moving / panning etc.. + * + * + * The SVG element is the only element that handles events + * if you click on it, it will look for roo-svg-observable in the event handler and pass on events to children. + * + * + * + */ + +Roo.namespace('Roo.svg'); + +Roo.svg.Element = function(cfg) +{ + Roo.svg.Element.superclass.constructor.call(this, cfg); + this.addEvents({ + 'click' : true, + 'dblclick' : true, + 'context' : true + }); + +} + +Roo.extend(Roo.svg.Element, Roo.Component, { + + tag : 'g', + + cls : '', + + getAutoCreate : function(){ + + + return { + ns: "svg", + xmlns: "http://www.w3.org/2000/svg", + tag: this.tag, + cls : this.cls + ' roo-svg-observable' + }; + }, + + initEvents: function() + { + Roo.svg.Canvas.superclass.initEvents.call(this); + // others... + this.el.relayEvent('click', this); + this.el.relayEvent('dblclick', this); + this.el.relayEvent('context', this); + + }, + + // private + onRender : function(ct, position) + { + // Roo.log("Call onRender: " + this.xtype); + + Roo.bootstrap.Component.superclass.onRender.call(this, ct, position); + + if(this.el){ + if (this.el.attr('xtype')) { + this.el.attr('xtypex', this.el.attr('xtype')); + this.el.dom.removeAttribute('xtype'); + + this.initEvents(); + } + + return; + } + + + + var cfg = Roo.apply({}, this.getAutoCreate()); + + cfg.id = this.id || Roo.id(); + + // fill in the extra attributes + if (this.xattr && typeof(this.xattr) =='object') { + for (var i in this.xattr) { + cfg[i] = this.xattr[i]; + } + } + + if(this.dataId){ + cfg.dataId = this.dataId; + } + + if (this.cls) { + cfg.cls = (typeof(cfg.cls) == 'undefined') ? this.cls : cfg.cls + ' ' + this.cls; + } + + if (this.style) { // fixme needs to support more complex style data. + cfg.style = this.style; + } + + if(this.name){ + cfg.name = this.name; + } + + this.el = ct.createChild(cfg, position); + + if (this.tooltip) { + this.tooltipEl().attr('tooltip', this.tooltip); + } + + if(this.tabIndex !== undefined){ + this.el.dom.setAttribute('tabIndex', this.tabIndex); + } + + this.initEvents(); + + }, + + + +}); \ No newline at end of file diff --git a/docs/json/roodata.json b/docs/json/roodata.json index b9513b8bae..054a06ecda 100644 --- a/docs/json/roodata.json +++ b/docs/json/roodata.json @@ -6113,7 +6113,7 @@ "name" : "removeListener", "type" : "function", "desc" : "Removes an event handler from this element", - "sig" : "(eventName, fn)", + "sig" : "(eventName, fn, scope)", "static" : false, "memberOf" : "" }, @@ -9006,7 +9006,7 @@ "name" : "removeListener", "type" : "function", "desc" : "Removes an event handler from this element", - "sig" : "(eventName, fn)", + "sig" : "(eventName, fn, scope)", "static" : false, "memberOf" : "Roo.Element" }, diff --git a/docs/src/Roo_BoxComponent.js.html b/docs/src/Roo_BoxComponent.js.html index 4394819397..f8677747ba 100644 --- a/docs/src/Roo_BoxComponent.js.html +++ b/docs/src/Roo_BoxComponent.js.html @@ -14,7 +14,7 @@ * @extends Roo.Component * Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box * model adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All - * container classes should subclass BoxComponent so that they will work consistently when nested within other Ext + * container classes should subclass BoxComponent so that they will work consistently when nested within other Roo * layout containers. * @constructor * @param {Roo.Element/String/Object} config The configuration options. diff --git a/docs/src/Roo_Element.js.html b/docs/src/Roo_Element.js.html index af724c2ed7..21b4cfaa36 100644 --- a/docs/src/Roo_Element.js.html +++ b/docs/src/Roo_Element.js.html @@ -85,7 +85,8 @@ if(opt.anim.isAnimated()){ * @param {String/HTMLElement} element * @param {Boolean} forceNew (optional) By default the constructor checks to see if there is already an instance of this element in the cache and if there is it returns the same instance. This will skip that check (useful for extending this class). */ - Roo.Element = function(element, forceNew){ + Roo.Element = function(element, forceNew) + { var dom = typeof element == "string" ? document.getElementById(element) : element; if(!dom){ // invalid id/element @@ -107,6 +108,8 @@ if(opt.anim.isAnimated()){ * @type String */ this.id = id || Roo.id(dom); + + this.listeners = {}; }; var El = Roo.Element; @@ -1180,13 +1183,30 @@ if(opt.anim.isAnimated()){ * @param {Object} scope (optional) The scope (this object) of the fn * @param {Object} options (optional)An object with standard {@link Roo.EventManager#addListener} options */ - addListener : function(eventName, fn, scope, options){ - if (this.dom) { - Roo.EventManager.on(this.dom, eventName, fn, scope || this, options); - } - if (eventName == 'dblclick') { + addListener : function(eventName, fn, scope, options) + { + if (eventName == 'dblclick') { // doublclick (touchstart) - faked on touch. this.addListener('touchstart', this.onTapHandler, this); } + + // we need to handle a special case where dom element is a svg element. + // in this case we do not actua + if (!this.dom) { + return; + } + + if (this.dom instanceof SVGElement && !(this.dom instanceof SVGSVGElement)) { + if (typeof(this.listeners[eventName]) == 'undefined') { + this.listeners[eventName] = new Roo.util.Event(this, eventName); + } + this.listeners[eventName].addListener(fn, scope, options); + return; + } + + + Roo.EventManager.on(this.dom, eventName, fn, scope || this, options); + + }, tapedTwice : false, onTapHandler : function(event) @@ -1215,10 +1235,15 @@ if(opt.anim.isAnimated()){ * Removes an event handler from this element * @param {String} eventName the type of event to remove * @param {Function} fn the method the event invokes + * @param {Function} scope (needed for svg fake listeners) * @return {Roo.Element} this */ - removeListener : function(eventName, fn){ + removeListener : function(eventName, fn, scope){ Roo.EventManager.removeListener(this.dom, eventName, fn); + if (typeof(this.listeners[eventName]) == 'undefined') { + return this; + } + this.listeners[eventName].removeListener(fn, scope); return this; }, @@ -1228,6 +1253,7 @@ if(opt.anim.isAnimated()){ */ removeAllListeners : function(){ E.purgeElement(this.dom); + this.listeners = {}; return this; }, @@ -1237,6 +1263,7 @@ if(opt.anim.isAnimated()){ }); }, + /** * Set the opacity of the element * @param {Float} opacity The new opacity. 0 = transparent, .5 = 50% visibile, 1 = fully visible, etc diff --git a/docs/src/Roo_EventManager.js.html b/docs/src/Roo_EventManager.js.html index b03cb8e881..754e07a47a 100644 --- a/docs/src/Roo_EventManager.js.html +++ b/docs/src/Roo_EventManager.js.html @@ -124,7 +124,8 @@ - var listen = function(element, ename, opt, fn, scope){ + var listen = function(element, ename, opt, fn, scope) + { var o = (!opt || typeof opt == "boolean") ? {} : opt; fn = fn || o.fn; scope = scope || o.scope; var el = Roo.getDom(element); @@ -181,7 +182,9 @@ - E.on(el, ename, h); + E.on(el, ename, h); // this adds the actuall listener to the object.. + + if(ename == "mousewheel" && el.addEventListener){ // workaround for jQuery el.addEventListener("DOMMouseScroll", h, false); E.on(window, 'unload', function(){ diff --git a/docs/src/Roo_bootstrap_ComboBox.js.html b/docs/src/Roo_bootstrap_ComboBox.js.html index 99553928f4..e17b06f244 100644 --- a/docs/src/Roo_bootstrap_ComboBox.js.html +++ b/docs/src/Roo_bootstrap_ComboBox.js.html @@ -2327,16 +2327,21 @@ combobox.cls += ' roo-select2-container-multi'; } + var required = this.allowBlank ? { + tag : 'i', + style: 'display: none' + } : { + tag : 'i', + cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star', + tooltip : 'This field is required' + }; + var align = this.labelAlign || this.parentLabelAlign(); if (align ==='left' && this.fieldLabel.length) { cfg.cn = [ - { - tag : 'i', - cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star', - tooltip : 'This field is required' - }, + required, { tag: 'label', cls : 'control-label col-form-label', @@ -2366,12 +2371,8 @@ tag : 'span', html : this.fieldLabel }, - { - tag : 'i', - cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star', - tooltip : 'This field is required' - } - ] + required + ] }, { cls : "roo-combobox-wrap ", @@ -2419,11 +2420,7 @@ } else if ( this.fieldLabel.length) { cfg.cn = [ - { - tag : 'i', - cls : 'roo-required-indicator left-indicator text-danger fa fa-lg fa-star', - tooltip : 'This field is required' - }, + required, { tag: 'label', cls : 'control-label', @@ -2445,12 +2442,8 @@ cls : 'control-label', html : this.fieldLabel, cn : [ - { - tag : 'i', - cls : 'roo-required-indicator right-indicator text-danger fa fa-lg fa-star', - tooltip : 'This field is required' - } - ] + required + ] }, { cls : '', diff --git a/docs/src/Roo_bootstrap_Popover.js.html b/docs/src/Roo_bootstrap_Popover.js.html index 242dee1227..d36a425f8b 100644 --- a/docs/src/Roo_bootstrap_Popover.js.html +++ b/docs/src/Roo_bootstrap_Popover.js.html @@ -445,14 +445,17 @@ clickHander : false, + onMouseDown : function(e) { - if (!e.getTarget(".roo-popover")) { + if (this.popup.length && !e.getTarget(".roo-popover") && this.popup.length) { + /// what is nothing is showing.. this.hideAll(); } }, + popups : [], register : function(popup) @@ -461,14 +464,22 @@ Roo.bootstrap.Popover.clickHandler = Roo.get(document).on("mousedown", Roo.bootstrap.Popover.onMouseDown, Roo.bootstrap.Popover); } // hide other popups. - this.hideAll(); - this.popups.push(popup); - }, + popup.on('show', Roo.bootstrap.Popover.onShow, popup); + popup.on('hide', Roo.bootstrap.Popover.onHide, popup); + this.hideAll(); //<< why? + //this.popups.push(popup); + }, hideAll : function() { this.popups.forEach(function(p) { p.hide(); }); - } + }, + onShow : function() { + Roo.bootstrap.Popover.popups.push(this); + }, + onHide : function() { + Roo.bootstrap.Popover.popups.remove(this); + }, }); \ No newline at end of file diff --git a/docs/symbols/Roo.BoxComponent.json b/docs/symbols/Roo.BoxComponent.json index 0d13e3686c..e73d7f3964 100644 --- a/docs/symbols/Roo.BoxComponent.json +++ b/docs/symbols/Roo.BoxComponent.json @@ -4,7 +4,7 @@ "Roo.Component", "Roo.util.Observable" ], - "desc" : "Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box\nmodel adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All\ncontainer classes should subclass BoxComponent so that they will work consistently when nested within other Ext\nlayout containers.", + "desc" : "Base class for any visual {@link Roo.Component} that uses a box container. BoxComponent provides automatic box\nmodel adjustments for sizing and positioning and will work correctly withnin the Component rendering model. All\ncontainer classes should subclass BoxComponent so that they will work consistently when nested within other Roo\nlayout containers.", "isSingleton" : false, "isStatic" : false, "isBuiltin" : false, diff --git a/docs/symbols/Roo.Element.json b/docs/symbols/Roo.Element.json index 74d0e09a22..28c3b8d44a 100644 --- a/docs/symbols/Roo.Element.json +++ b/docs/symbols/Roo.Element.json @@ -3627,6 +3627,12 @@ "type" : "Function", "desc" : "the method the event invokes", "isOptional" : false + }, + { + "name" : "scope", + "type" : "Function", + "desc" : "(needed for svg fake listeners)", + "isOptional" : false } ], "returns" : [ diff --git a/docs/symbols/Roo.Layer.json b/docs/symbols/Roo.Layer.json index 5c978e0022..e1d4ed1e2a 100644 --- a/docs/symbols/Roo.Layer.json +++ b/docs/symbols/Roo.Layer.json @@ -3706,6 +3706,12 @@ "type" : "Function", "desc" : "the method the event invokes", "isOptional" : false + }, + { + "name" : "scope", + "type" : "Function", + "desc" : "(needed for svg fake listeners)", + "isOptional" : false } ], "returns" : [ diff --git a/roojs-all.js b/roojs-all.js index c47b57b2b4..6d5a089c8f 100644 --- a/roojs-all.js +++ b/roojs-all.js @@ -306,7 +306,7 @@ return Roo.isSafari?(A[k]||k):k;},getPageX:function(){return this.xy[0];},getPag },within:function(el,C){var t=this[C?"getRelatedTarget":"getTarget"]();return t&&Roo.fly(el).contains(t);},getPoint:function(){return new Roo.lib.Point(this.xy[0],this.xy[1]);}};return new Roo.EventObjectImpl();}(); // Roo/Element.js (function(){var D=Roo.lib.Dom;var E=Roo.lib.Event;var A=Roo.lib.Anim;var B={};var C=/(-[a-z])/gi;var F=function(m,a){return a.charAt(1).toUpperCase();};var G=document.defaultView;Roo.Element=function(J,K){var L=typeof J=="string"?document.getElementById(J):J; -if(!L){return null;}var id=L.id;if(K!==true&&id&&Roo.Element.cache[id]){return Roo.Element.cache[id];}this.dom=L;this.id=id||Roo.id(L);};var El=Roo.Element;El.prototype={originalDisplay:"",visibilityMode:1,defaultUnit:"px",setVisibilityMode:function(J){this.visibilityMode=J; +if(!L){return null;}var id=L.id;if(K!==true&&id&&Roo.Element.cache[id]){return Roo.Element.cache[id];}this.dom=L;this.id=id||Roo.id(L);this.listeners={};};var El=Roo.Element;El.prototype={originalDisplay:"",visibilityMode:1,defaultUnit:"px",setVisibilityMode:function(J){this.visibilityMode=J; return this;},enableDisplayMode:function(J){this.setVisibilityMode(El.DISPLAY);if(typeof J!="undefined"){this.originalDisplay=J;}return this;},findParent:function(J,K,L){var p=this.dom,b=document.body,M=0,dq=Roo.DomQuery,N;K=K||50;if(typeof K!="number"){N=Roo.getDom(K); K=10;}while(p&&p.nodeType==1&&M