From c60946188a076d8013440b141f85d57c920160a9 Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Sun, 11 Feb 2018 13:11:31 +0100 Subject: proposal for #807, includes #550, allow multiple events for `SVG.off()` and add option argument --- src/element.js | 7 +-- src/event.js | 144 +++++++++++++++++++++++++++------------------------------ src/svg.js | 2 +- 3 files changed, 73 insertions(+), 80 deletions(-) (limited to 'src') diff --git a/src/element.js b/src/element.js index eca535b..a2c8cc5 100644 --- a/src/element.js +++ b/src/element.js @@ -2,9 +2,9 @@ SVG.Element = SVG.invent({ // Initialize node - create: function (node) { - // last fired event on node - this._event = null + create: function(node) { + // event listener + this.events = {} // initialize data object this.dom = {} @@ -14,6 +14,7 @@ SVG.Element = SVG.invent({ if (this.node) { this.type = node.nodeName this.node.instance = this + this.events = node.events || {} if (node.hasAttribute('svgjs:data')) { // pull svgjs data from the dom (getAttributeNS doesn't work in html5) diff --git a/src/event.js b/src/event.js index c53e0b3..6501beb 100644 --- a/src/event.js +++ b/src/event.js @@ -1,4 +1,5 @@ // Add events to elements + ;[ 'click', 'dblclick', 'mousedown', @@ -6,14 +7,14 @@ 'mouseover', 'mouseout', 'mousemove', - // , 'mouseenter' -> not supported by IE - // , 'mouseleave' -> not supported by IE + 'mouseenter', + 'mouseleave', 'touchstart', 'touchmove', 'touchleave', 'touchend', 'touchcancel' ].forEach(function (event) { - // add event to SVG.Element + // add event to SVG.Element SVG.Element.prototype[event] = function (f) { // bind event to element rather than element node SVG.on(this, event, f) @@ -21,32 +22,31 @@ } }) -// Initialize listeners stack -SVG.listeners = [] -SVG.handlerMap = [] SVG.listenerId = 0 // Add event binder in the SVG namespace SVG.on = function (node, events, listener, binding, options) { + var l = listener.bind(binding || node), + n = node instanceof SVG.Element ? node.node : node + + // ensure instance object for nodes which are not adopted + n.instance = n.instance || {events: {}} + + var bag = n.instance.events + + // ensure valid object + bag[ev] = bag[ev] || {} + bag[ev][ns] = bag[ev][ns] || {} + + // add id to listener + if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++SVG.listenerId } + events.split(SVG.regex.delimiter).forEach(function (event) { - // create listener, get object-index - var l = listener.bind(binding || node) - var n = node instanceof SVG.Element ? node.node : node - var index = (SVG.handlerMap.indexOf(n) + 1 || SVG.handlerMap.push(n)) - 1 - var ev = event.split('.')[0] - var ns = event.split('.')[1] || '*' - - // ensure valid object - SVG.listeners[index] = SVG.listeners[index] || {} - SVG.listeners[index][ev] = SVG.listeners[index][ev] || {} - SVG.listeners[index][ev][ns] = SVG.listeners[index][ev][ns] || {} - - if (!listener._svgjsListenerId) { - listener._svgjsListenerId = ++SVG.listenerId - } + var ev = event.split('.')[0], + ns = event.split('.')[1] || '*' // reference listener - SVG.listeners[index][ev][ns][listener._svgjsListenerId] = l + bag[ev][ns][listener._svgjsListenerId] = l // add listener n.addEventListener(ev, l, options || false) @@ -54,91 +54,83 @@ SVG.on = function (node, events, listener, binding, options) { } // Add event unbinder in the SVG namespace -SVG.off = function (node, event, listener) { - var index = SVG.handlerMap.indexOf(node) - var ev = event && event.split('.')[0] - var ns = event && event.split('.')[1] - var namespace = '' - - if (index === -1) return +SVG.off = function (node, events, listener, options) { + var n = node instanceof SVG.Element ? node.node : node + if (!n.instance) return + // make a precheck for a valid listener here to avoid repetition in the loop if (listener) { if (typeof listener === 'function') listener = listener._svgjsListenerId if (!listener) return + } - // remove listener reference - if (SVG.listeners[index][ev] && SVG.listeners[index][ev][ns || '*']) { - // remove listener - node.removeEventListener(ev, SVG.listeners[index][ev][ns || '*'][listener], false) + var bag = n.instance.events - delete SVG.listeners[index][ev][ns || '*'][listener] - } - } else if (ns && ev) { - // remove all listeners for a namespaced event - if (SVG.listeners[index][ev] && SVG.listeners[index][ev][ns]) { - for (listener in SVG.listeners[index][ev][ns]) { - SVG.off(node, [ev, ns].join('.'), listener) + ;(events || '').split(SVG.regex.delimiter).forEach(function (event) { + var ev = event && event.split('.')[0], + ns = event && event.split('.')[1], + namespace + + if (listener) { + // remove listener reference + if (bag[ev] && bag[ev][ns || '*']) { + // remove listener + n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false) + + delete bag[ev][ns || '*'][listener] } + } else if (ev && ns) { + // remove all listeners for a namespaced event + if (bag[ev] && bag[ev][ns]) { + for (listener in bag[ev][ns]) { SVG.off(n, [ev, ns].join('.'), listener) } - delete SVG.listeners[index][ev][ns] - } - } else if (ns) { - // remove all listeners for a specific namespace - for (event in SVG.listeners[index]) { - for (namespace in SVG.listeners[index][event]) { - if (ns === namespace) { - SVG.off(node, [event, ns].join('.')) + delete bag[ev][ns] + } + } else if (ns) { + // remove all listeners for a specific namespace + for (event in bag) { + for (namespace in bag[event]) { + if (ns === namespace) { SVG.off(n, [event, ns].join('.')) } } } - } - } else if (ev) { - // remove all listeners for the event - if (SVG.listeners[index][ev]) { - for (namespace in SVG.listeners[index][ev]) { - SVG.off(node, [ev, namespace].join('.')) + } else if (ev) { + // remove all listeners for the event + if (bag[ev]) { + for (namespace in bag[ev]) { SVG.off(n, [ev, namespace].join('.')) } + + delete bag[ev] } + } else { + // remove all listeners on a given node + for (event in bag) { SVG.off(n, event) } - delete SVG.listeners[index][ev] - } - } else { - // remove all listeners on a given node - for (event in SVG.listeners[index]) { - SVG.off(node, event) + n.instance.events = {} } - - delete SVG.listeners[index] - delete SVG.handlerMap[index] - } + }) } -// SVG.extend(SVG.Element, { // Bind given event to listener on: function (event, listener, binding, options) { SVG.on(this, event, listener, binding, options) return this }, - // Unbind event from listener off: function (event, listener) { SVG.off(this.node, event, listener) - return this }, - - // Fire given event - fire: function (event, data) { + dispatch: function (event, data) { // Dispatch event if (event instanceof window.Event) { this.node.dispatchEvent(event) } else { this.node.dispatchEvent(event = new window.CustomEvent(event, {detail: data, cancelable: true})) } - - this._event = event - return this + return event }, - - event: function () { - return this._event + // Fire given event + fire: function (event, data) { + this.dispatch(event, data) + return this } }) diff --git a/src/svg.js b/src/svg.js index e6903da..55cb88d 100644 --- a/src/svg.js +++ b/src/svg.js @@ -77,7 +77,7 @@ SVG.adopt = function (node) { if (!node) return null // make sure a node isn't already adopted - if (node.instance) return node.instance + if (node.instance instanceof SVG.Element) return node.instance if (!(node instanceof window.SVGElement)) { return new SVG.HtmlNode(node) -- cgit v1.2.3 From 9569005ce473d614375576ff28a9095b19d94ed0 Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Tue, 27 Feb 2018 10:07:56 +0100 Subject: fix errors found by linter (jeah it works!) --- src/element.js | 2 +- src/event.js | 22 +++++++++++----------- 2 files changed, 12 insertions(+), 12 deletions(-) (limited to 'src') diff --git a/src/element.js b/src/element.js index a2c8cc5..f35dc19 100644 --- a/src/element.js +++ b/src/element.js @@ -2,7 +2,7 @@ SVG.Element = SVG.invent({ // Initialize node - create: function(node) { + create: function (node) { // event listener this.events = {} diff --git a/src/event.js b/src/event.js index 6501beb..f0d0e0c 100644 --- a/src/event.js +++ b/src/event.js @@ -26,24 +26,24 @@ SVG.listenerId = 0 // Add event binder in the SVG namespace SVG.on = function (node, events, listener, binding, options) { - var l = listener.bind(binding || node), - n = node instanceof SVG.Element ? node.node : node + var l = listener.bind(binding || node) + var n = node instanceof SVG.Element ? node.node : node // ensure instance object for nodes which are not adopted n.instance = n.instance || {events: {}} var bag = n.instance.events - // ensure valid object - bag[ev] = bag[ev] || {} - bag[ev][ns] = bag[ev][ns] || {} - // add id to listener if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++SVG.listenerId } events.split(SVG.regex.delimiter).forEach(function (event) { - var ev = event.split('.')[0], - ns = event.split('.')[1] || '*' + var ev = event.split('.')[0] + var ns = event.split('.')[1] || '*' + + // ensure valid object + bag[ev] = bag[ev] || {} + bag[ev][ns] = bag[ev][ns] || {} // reference listener bag[ev][ns][listener._svgjsListenerId] = l @@ -67,9 +67,9 @@ SVG.off = function (node, events, listener, options) { var bag = n.instance.events ;(events || '').split(SVG.regex.delimiter).forEach(function (event) { - var ev = event && event.split('.')[0], - ns = event && event.split('.')[1], - namespace + var ev = event && event.split('.')[0] + var ns = event && event.split('.')[1] + var namespace if (listener) { // remove listener reference -- cgit v1.2.3 From 826bb9845ffdbd11be427aad3ffa1f7d4a650eab Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Tue, 27 Feb 2018 12:12:19 +0100 Subject: fixed error that listener was strangely defined even if function was called without --- spec/spec/event.js | 111 +++++++++++++++++++++++++++-------------------------- src/event.js | 21 ++++++---- 2 files changed, 69 insertions(+), 63 deletions(-) (limited to 'src') diff --git a/spec/spec/event.js b/spec/spec/event.js index 0228fae..5f12172 100644 --- a/spec/spec/event.js +++ b/spec/spec/event.js @@ -10,7 +10,8 @@ describe('Event', function() { beforeEach(function() { rect = draw.rect(100, 100) - spyOn(SVG,'on').and.callThrough() + spyOn(SVG, 'on').and.callThrough() + spyOn(rect, 'dispatch').and.callThrough() }) afterEach(function() { @@ -25,8 +26,8 @@ describe('Event', function() { , 'mouseover' , 'mouseout' , 'mousemove' - // , 'mouseenter' -> not supported by IE - // , 'mouseleave' -> not supported by IE + , 'mouseenter' + , 'mouseleave' ].forEach(function(event) { describe(event+'()', function() { it('calls `on()` with '+event+' as event', function() { @@ -71,39 +72,32 @@ describe('Event', function() { SVG.off(el, 'event', action) }) it('attaches multiple handlers on different element', function() { - var listenerCnt = SVG.listeners.length - - var rect2 = draw.rect(100,100); - var rect3 = draw.rect(100,100); + var rect2 = draw.rect(100, 100) + var rect3 = draw.rect(100, 100) rect.on('event', action) rect2.on('event', action) rect3.on('event', function(){ butter = 'melting' }) rect3.on('event', action) - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]['event']['*']).length).toBe(1) // 1 listener on rect - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect2.node)]['event']['*']).length).toBe(1) // 1 listener on rect2 - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect3.node)]['event']['*']).length).toBe(2) // 2 listener on rect3 - - expect(SVG.listeners.length).toBe(listenerCnt + 3) // added listeners on 3 different elements + expect(Object.keys(rect.events['event']['*']).length).toBe(1) // 1 listener on rect + expect(Object.keys(rect2.events['event']['*']).length).toBe(1) // 1 listener on rect2 + expect(Object.keys(rect3.events['event']['*']).length).toBe(2) // 2 listener on rect3 }) if('attaches a handler to a namespaced event', function(){ - var listenerCnt = SVG.listeners.length - - var rect2 = draw.rect(100,100); - var rect3 = draw.rect(100,100); + var rect2 = draw.rect(100, 100) + var rect3 = draw.rect(100, 100) rect.on('event.namespace1', action) rect2.on('event.namespace2', action) rect3.on('event.namespace3', function(){ butter = 'melting' }) rect3.on('event', action) - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]['event']['*'])).toBeUndefined() // no global listener on rect - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]['event']['namespace1']).length).toBe( 1) // 1 namespaced listener on rect - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect2.node)]['event']['namespace2']).length).toBe(1) // 1 namespaced listener on rect - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect3.node)]['event']['*']).length).toBe(1) // 1 gobal listener on rect3 - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect3.node)]['event']['namespace3']).length).toBe(1) // 1 namespaced listener on rect3 - expect(SVG.listeners.length).toBe(listenerCnt + 3) // added listeners on 3 different elements + expect(Object.keys(rect.events['event']['*'])).toBeUndefined() // no global listener on rect + expect(Object.keys(rect.events['event']['namespace1']).length).toBe( 1) // 1 namespaced listener on rect + expect(Object.keys(rect2.events['namespace2']).length).toBe(1) // 1 namespaced listener on rect2 + expect(Object.keys(rect3.events['event']['*']).length).toBe(1) // 1 gobal listener on rect3 + expect(Object.keys(rect3.events['event']['namespace3']).length).toBe(1) // 1 namespaced listener on rect3 }) it('applies the element as context', function() { rect.on('event', action).fire('event') @@ -115,7 +109,7 @@ describe('Event', function() { }) it('stores the listener for future reference', function() { rect.on('event', action) - expect(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]['event']['*'][action._svgjsListenerId]).not.toBeUndefined() + expect(rect.events['event']['*'][action._svgjsListenerId]).not.toBeUndefined() }) it('returns the called element', function() { expect(rect.on('event', action)).toBe(rect) @@ -130,8 +124,8 @@ describe('Event', function() { }) it('detaches a specific event listener, all other still working', function() { - rect2 = draw.rect(100,100); - rect3 = draw.rect(100,100); + rect2 = draw.rect(100,100) + rect3 = draw.rect(100,100) rect.on('event', action) rect2.on('event', action) @@ -139,7 +133,7 @@ describe('Event', function() { rect.off('event', action) - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]['event']['*']).length).toBe(0) + expect(Object.keys(rect.events['event']['*']).length).toBe(0) rect.fire('event') expect(toast).toBeNull() @@ -150,11 +144,11 @@ describe('Event', function() { rect3.fire('event') expect(butter).toBe('melting') - expect(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]['event']['*'][action]).toBeUndefined() + expect(rect.events['event']['*'][action]).toBeUndefined() }) it('detaches a specific namespaced event listener, all other still working', function() { - rect2 = draw.rect(100,100); - rect3 = draw.rect(100,100); + rect2 = draw.rect(100,100) + rect3 = draw.rect(100,100) rect.on('event.namespace', action) rect2.on('event.namespace', action) @@ -162,7 +156,8 @@ describe('Event', function() { rect.off('event.namespace', action) - expect(Object.keys(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]['event']['namespace']).length).toBe(0) + expect(Object.keys(rect.events['event']['namespace']).length).toBe(0) + expect(Object.keys(rect2.events['event']['namespace']).length).toBe(1) rect.fire('event') expect(toast).toBeNull() @@ -173,7 +168,7 @@ describe('Event', function() { rect3.fire('event') expect(butter).toBe('melting') - expect(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]['event']['namespace'][action]).toBeUndefined() + expect(rect.events['event']['namespace'][action]).toBeUndefined() }) it('detaches all listeners for a specific namespace', function() { rect.on('event', action) @@ -192,7 +187,7 @@ describe('Event', function() { rect.fire('event') expect(toast).toBeNull() expect(butter).toBeNull() - expect(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]['event']).toBeUndefined() + expect(rect.events['event']).toBeUndefined() }) it('detaches all listeners without an argument', function() { rect.on('event', action) @@ -202,7 +197,20 @@ describe('Event', function() { rect.fire('click') expect(toast).toBeNull() expect(butter).toBeNull() - expect(SVG.listeners[SVG.handlerMap.indexOf(rect.node)]).toBeUndefined() + expect(Object.keys(rect.events).length).toBe(0) + }) + it('detaches multiple listeners at once', function() { + rect2 = draw.rect(100,100) + rect3 = draw.rect(100,100) + + rect.on('event.namespace bla foo.bar otherfoo.bar keepthis', action) + rect.off('event.namespace bla .bar') + + expect(Object.keys(rect.events['event']).length).toBe(0) + expect(rect.events['bla']).toBeUndefined() + expect(Object.keys(rect.events['foo']).length).toBe(0) + expect(Object.keys(rect.events['otherfoo']).length).toBe(0) + expect(Object.keys(rect.events['keepthis']['*']).length).toBe(1) }) it('returns the called element', function() { expect(rect.off('event', action)).toBe(rect) @@ -218,12 +226,23 @@ describe('Event', function() { expect('Should not error out').toBe(true) } - expect(SVG.handlerMap[SVG.handlerMap.indexOf(rect.node)]).toBe(undefined) + expect(Object.keys(rect.events).length).toBe(0) }) }) describe('fire()', function() { + it('calls dispatch with its parameters', function() { + var data = {} + rect.dispatch('event', data) + expect(rect.dispatch).toHaveBeenCalledWith('event', data) + }) + + it('returns the called element', function() { + expect(rect.fire('event')).toBe(rect) + }) + }) + describe('dispatch()', function() { beforeEach(function() { rect.on('event', action) }) @@ -234,9 +253,7 @@ describe('Event', function() { expect(toast).toBe('ready') expect(fruitsInDetail).toBe(null) }) - it('returns the called element', function() { - expect(rect.fire('event')).toBe(rect) - }) + it('fires event with additional data', function() { expect(fruitsInDetail).toBeNull() rect.fire('event', {apple:1}) @@ -248,27 +265,11 @@ describe('Event', function() { rect.fire(new window.CustomEvent('event')) expect(toast).toBe('ready') }) - it('makes the event cancelable', function() { + it('returns the dispatched event and makes it cancelable', function() { rect.on('event', function(e) { e.preventDefault() }) - rect.fire('event') - expect(rect._event.defaultPrevented).toBe(true) - }) - }) - - describe('event()', function() { - it('returns null when no event was fired', function() { - expect(rect.event()).toBe(null) - }) - it('returns the last fired event', function() { - var event = new window.CustomEvent('foo') - rect.fire(event) - expect(rect.event()).toBe(event) - - event = new window.CustomEvent('bar') - rect.fire(event) - expect(rect.event()).toBe(event) + expect(rect.dispatch('event').defaultPrevented).toBe(true) }) }) }) diff --git a/src/event.js b/src/event.js index f0d0e0c..6408e88 100644 --- a/src/event.js +++ b/src/event.js @@ -56,12 +56,16 @@ SVG.on = function (node, events, listener, binding, options) { // Add event unbinder in the SVG namespace SVG.off = function (node, events, listener, options) { var n = node instanceof SVG.Element ? node.node : node + var listenerId + if (!n.instance) return - // make a precheck for a valid listener here to avoid repetition in the loop - if (listener) { - if (typeof listener === 'function') listener = listener._svgjsListenerId - if (!listener) return + // listener can be a function or a number + if (typeof listener === 'function') { + listenerId = listener._svgjsListenerId + if (!listenerId) return + } else { + listenerId = listener } var bag = n.instance.events @@ -71,13 +75,13 @@ SVG.off = function (node, events, listener, options) { var ns = event && event.split('.')[1] var namespace - if (listener) { + if (listenerId) { // remove listener reference if (bag[ev] && bag[ev][ns || '*']) { - // remove listener - n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false) + // removeListener + n.removeEventListener(ev, bag[ev][ns || '*'][listenerId], options || false) - delete bag[ev][ns || '*'][listener] + delete bag[ev][ns || '*'][listenerId] } } else if (ev && ns) { // remove all listeners for a namespaced event @@ -118,6 +122,7 @@ SVG.extend(SVG.Element, { // Unbind event from listener off: function (event, listener) { SVG.off(this.node, event, listener) + return this }, dispatch: function (event, data) { // Dispatch event -- cgit v1.2.3 From c835f41c7f30815df1ded7ae4fa8da0d0d5b09fd Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Tue, 27 Feb 2018 12:16:31 +0100 Subject: found the error whereelse. go back to version before with applied fix --- src/event.js | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) (limited to 'src') diff --git a/src/event.js b/src/event.js index 6408e88..22ff152 100644 --- a/src/event.js +++ b/src/event.js @@ -22,7 +22,7 @@ } }) -SVG.listenerId = 0 +SVG.listener = 0 // Add event binder in the SVG namespace SVG.on = function (node, events, listener, binding, options) { @@ -35,7 +35,7 @@ SVG.on = function (node, events, listener, binding, options) { var bag = n.instance.events // add id to listener - if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++SVG.listenerId } + if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++SVG.listener } events.split(SVG.regex.delimiter).forEach(function (event) { var ev = event.split('.')[0] @@ -56,16 +56,12 @@ SVG.on = function (node, events, listener, binding, options) { // Add event unbinder in the SVG namespace SVG.off = function (node, events, listener, options) { var n = node instanceof SVG.Element ? node.node : node - var listenerId - if (!n.instance) return // listener can be a function or a number if (typeof listener === 'function') { - listenerId = listener._svgjsListenerId - if (!listenerId) return - } else { - listenerId = listener + listener = listener._svgjsListenerId + if (!listener) return } var bag = n.instance.events @@ -73,20 +69,20 @@ SVG.off = function (node, events, listener, options) { ;(events || '').split(SVG.regex.delimiter).forEach(function (event) { var ev = event && event.split('.')[0] var ns = event && event.split('.')[1] - var namespace + var namespace, l - if (listenerId) { + if (listener) { // remove listener reference if (bag[ev] && bag[ev][ns || '*']) { // removeListener - n.removeEventListener(ev, bag[ev][ns || '*'][listenerId], options || false) + n.removeEventListener(ev, bag[ev][ns || '*'][listener], options || false) - delete bag[ev][ns || '*'][listenerId] + delete bag[ev][ns || '*'][listener] } } else if (ev && ns) { // remove all listeners for a namespaced event if (bag[ev] && bag[ev][ns]) { - for (listener in bag[ev][ns]) { SVG.off(n, [ev, ns].join('.'), listener) } + for (l in bag[ev][ns]) { SVG.off(n, [ev, ns].join('.'), l) } delete bag[ev][ns] } -- cgit v1.2.3 From ec628ee93ddc2c16929f0f275068b6585ab18e77 Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Tue, 27 Feb 2018 12:17:37 +0100 Subject: search and replace replaced to much --- src/event.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/event.js b/src/event.js index 22ff152..65b13b0 100644 --- a/src/event.js +++ b/src/event.js @@ -22,7 +22,7 @@ } }) -SVG.listener = 0 +SVG.listenerId = 0 // Add event binder in the SVG namespace SVG.on = function (node, events, listener, binding, options) { @@ -35,7 +35,7 @@ SVG.on = function (node, events, listener, binding, options) { var bag = n.instance.events // add id to listener - if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++SVG.listener } + if (!listener._svgjsListenerId) { listener._svgjsListenerId = ++SVG.listenerId } events.split(SVG.regex.delimiter).forEach(function (event) { var ev = event.split('.')[0] -- cgit v1.2.3 From 64a5c17b95393c0914670b1b9e2c8b4d63707968 Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Sun, 11 Feb 2018 15:29:23 +0100 Subject: merge SVG.Doc and SVG.Nested. Add isRoot() method, update doc methods to decide between doc and nested --- gulpfile.js | 1 - src/doc.js | 35 ++++++++++++++++++++++++----------- src/element.js | 2 +- src/nested.js | 16 ---------------- src/svg.js | 6 +++--- 5 files changed, 28 insertions(+), 32 deletions(-) delete mode 100644 src/nested.js (limited to 'src') diff --git a/gulpfile.js b/gulpfile.js index 545a27f..d96451b 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -69,7 +69,6 @@ var parts = [ 'src/image.js', 'src/text.js', 'src/textpath.js', - 'src/nested.js', 'src/hyperlink.js', 'src/marker.js', 'src/sugar.js', diff --git a/src/doc.js b/src/doc.js index 2097747..843ff03 100644 --- a/src/doc.js +++ b/src/doc.js @@ -12,22 +12,37 @@ SVG.Doc = SVG.invent({ // Add class methods extend: { + isRoot: function() { + return !this.node.parentNode || !this.node.parentNode instanceof window.SVGElement || this.node.parentNode.nodeName == '#document' + }, + doc: function() { + if(this.isRoot()) return this + + var parent + while(parent = this.parent(SVG.Doc)) { + if(parent.isRoot()) return parent + } + + throw new Error('This should never be reached') + }, // Add namespaces - namespace: function () { + namespace: function() { + if(!this.isRoot()) return this.doc().namespace() return this .attr({ xmlns: SVG.ns, version: '1.1' }) .attr('xmlns:xlink', SVG.xlink, SVG.xmlns) .attr('xmlns:svgjs', SVG.svgjs, SVG.xmlns) }, // Creates and returns defs element - defs: function () { + defs: function() { + if(!this.isRoot()) return this.doc().defs() return SVG.adopt(this.node.getElementsByTagName('defs')[0]) || this.put(new SVG.Defs()) }, // custom parent method parent: function () { return this.node.parentNode.nodeName === '#document' ? null : this.node.parentNode }, - // Removes the doc from the DOM + // Removes the doc from the DOM remove: function () { if (this.parent()) { this.parent().removeChild(this.node) @@ -41,14 +56,12 @@ SVG.Doc = SVG.invent({ this.node.removeChild(this.node.lastChild) } return this - }, - toNested: function () { - var el = SVG.create('svg') - this.node.instance = null - el.appendChild(this.node) - - return SVG.adopt(this.node) + } + }, + construct: { + // Create nested svg document + nested: function() { + return this.put(new SVG.Doc) } } - }) diff --git a/src/element.js b/src/element.js index f35dc19..e7b5326 100644 --- a/src/element.js +++ b/src/element.js @@ -218,7 +218,7 @@ SVG.Element = SVG.invent({ // Get parent document doc: function () { - return this instanceof SVG.Doc ? this : this.parent(SVG.Doc) + return this.parent(SVG.Doc).doc() }, // Get defs diff --git a/src/nested.js b/src/nested.js deleted file mode 100644 index 217d59a..0000000 --- a/src/nested.js +++ /dev/null @@ -1,16 +0,0 @@ - -SVG.Nested = SVG.invent({ - // Initialize node - create: 'svg', - - // Inherit from - inherit: SVG.Container, - - // Add parent method - construct: { - // Create nested svg document - nested: function () { - return this.put(new SVG.Nested()) - } - } -}) diff --git a/src/svg.js b/src/svg.js index 55cb88d..4cb6f26 100644 --- a/src/svg.js +++ b/src/svg.js @@ -87,9 +87,9 @@ SVG.adopt = function (node) { var element // adopt with element-specific settings - if (node.nodeName === 'svg') { - element = node.parentNode instanceof window.SVGElement ? new SVG.Nested(node) : new SVG.Doc(node) - } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') { + if (node.nodeName == 'svg') + element = new SVG.Doc(node) + else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') element = new SVG.Gradient(node) } else if (SVG[capitalize(node.nodeName)]) { element = new SVG[capitalize(node.nodeName)](node) -- cgit v1.2.3 From 981c1fb154e3999f91dd9c1eff97726d689240ff Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Mon, 12 Feb 2018 13:49:38 +0100 Subject: return explicit null if there is no root --- src/doc.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/doc.js b/src/doc.js index 843ff03..d4bf7e5 100644 --- a/src/doc.js +++ b/src/doc.js @@ -23,7 +23,9 @@ SVG.Doc = SVG.invent({ if(parent.isRoot()) return parent } - throw new Error('This should never be reached') + // this can only happen when you have something like + // ... + return null }, // Add namespaces namespace: function() { -- cgit v1.2.3 From 75c3893a7c7af76f9bb1fe9be72e03b99d17a1e0 Mon Sep 17 00:00:00 2001 From: Ulrich-Matthias Schäfer Date: Thu, 1 Mar 2018 12:42:16 +0100 Subject: fixed all that errors which come along when removing an object. Fixed tests, too and added isRoot test --- spec/SpecRunner.html | 1 - spec/spec/doc.js | 21 +++++++++++++++++++-- spec/spec/element.js | 3 ++- spec/spec/nested.js | 13 ------------- spec/spec/svg.js | 4 ++-- src/HtmlNode.js | 10 ++-------- src/boxes.js | 2 +- src/doc.js | 45 +++++++++++++++++++++++---------------------- src/element.js | 3 ++- src/flatten.js | 2 +- src/matrix.js | 2 +- src/parent.js | 6 ++---- src/parser.js | 2 +- src/svg.js | 8 +++++--- 14 files changed, 61 insertions(+), 61 deletions(-) delete mode 100644 spec/spec/nested.js (limited to 'src') diff --git a/spec/SpecRunner.html b/spec/SpecRunner.html index 7461bdd..bd47626 100644 --- a/spec/SpecRunner.html +++ b/spec/SpecRunner.html @@ -78,7 +78,6 @@ - diff --git a/spec/spec/doc.js b/spec/spec/doc.js index 1e1c54c..5accd5b 100644 --- a/spec/spec/doc.js +++ b/spec/spec/doc.js @@ -16,11 +16,11 @@ describe('Doc', function() { expect(draw instanceof SVG.Doc).toBe(true) }) - it('returns itself as Doc', function() { + it('returns itself as Doc when root', function() { expect(draw.doc()).toBe(draw) }) - it('has a defs element', function() { + it('has a defs element when root', function() { expect(draw.defs() instanceof SVG.Defs).toBe(true) }) @@ -33,6 +33,23 @@ describe('Doc', function() { }) }) + describe('isRoot()', function() { + it('returns true when the doc is not attached to dom', function() { + expect(SVG().isRoot()).toBe(true) + }) + it('returns true when its outer element is not an svg element', function () { + expect(SVG().addTo(document.createElement('div')).isRoot()).toBe(true) + }) + it('returns true when its the root element of the dom', function () { + if(parserInDoc) { + expect(draw.isRoot()).toBe(true) + } + }) + it('returns false when parent is svg element', function () { + expect(SVG().addTo(SVG()).isRoot()).toBe(false) + }) + }) + describe('remove()', function() { it('removes the doc from the dom only if doc is not root element', function() { var cnt = window.document.querySelectorAll('svg').length diff --git a/spec/spec/element.js b/spec/spec/element.js index a5b26a1..53ed84f 100644 --- a/spec/spec/element.js +++ b/spec/spec/element.js @@ -476,11 +476,12 @@ describe('Element', function() { it('ungroups everything to the doc root when called on SVG.Doc / does not ungroup defs/parser', function() { draw.flatten() + expect(rect1.parent()).toBe(draw) expect(rect2.parent()).toBe(draw) expect(g1.node.parentNode).toBeFalsy() - expect(g1.node.parentNode).toBeFalsy() + expect(g2.node.parentNode).toBeFalsy() expect(nested.node.parentNode).toBeFalsy() expect(rect1.transform()).toEqual(jasmine.objectContaining({ diff --git a/spec/spec/nested.js b/spec/spec/nested.js deleted file mode 100644 index 3113880..0000000 --- a/spec/spec/nested.js +++ /dev/null @@ -1,13 +0,0 @@ -describe('Nested', function() { - - afterEach(function() { - draw.clear() - }) - - describe('()', function() { - it('creates a nested svg of type SVG.Nested', function() { - expect(draw.nested() instanceof SVG.Nested).toBeTruthy() - }) - }) - -}) diff --git a/spec/spec/svg.js b/spec/spec/svg.js index 2485a32..ea51703 100644 --- a/spec/spec/svg.js +++ b/spec/spec/svg.js @@ -52,10 +52,10 @@ describe('SVG', function() { expect(SVG(rect).node).toBe(rect) }) - it('creates an instanceof SVG.Nested when importing a whole svg', function() { + it('creates an instanceof SVG.Doc when importing a whole svg', function() { var doc = SVG('') - expect(doc instanceof SVG.Nested).toBe(true) + expect(doc instanceof SVG.Doc).toBe(true) expect(doc.node.nodeName).toBe('svg') expect(doc.width()).toBe(200) expect(doc.get(0).node.nodeName).toBe('rect') diff --git a/src/HtmlNode.js b/src/HtmlNode.js index 30cb4cf..e7dae10 100644 --- a/src/HtmlNode.js +++ b/src/HtmlNode.js @@ -8,15 +8,9 @@ SVG.HtmlNode = SVG.invent({ extend: { add: function (element, i) { element = createElement(element) - if (element instanceof SVG.Nested) { - element = new SVG.Doc(element.node) - element.setData(JSON.parse(element.node.getAttribute('svgjs:data')) || {}) - } - if (i === null) { - this.node.appendChild(element.node) - } else if (element.node !== this.node.children[i]) { - this.node.insertBefore(element.node, this.node.children[i]) + if (element.node !== this.node.children[i]) { + this.node.insertBefore(element.node, this.node.children[i] || null) } return this diff --git a/src/boxes.js b/src/boxes.js index a5ca1e8..f0154bd 100644 --- a/src/boxes.js +++ b/src/boxes.js @@ -127,7 +127,7 @@ SVG.Box = SVG.invent({ } }) -SVG.extend([SVG.Doc, SVG.Nested, SVG.Symbol, SVG.Image, SVG.Pattern, SVG.Marker, SVG.ForeignObject, SVG.View], { +SVG.extend([SVG.Doc, SVG.Symbol, SVG.Image, SVG.Pattern, SVG.Marker, SVG.ForeignObject, SVG.View], { viewbox: function (x, y, width, height) { // act as getter if (x == null) return new SVG.Box(this.attr('viewBox')) diff --git a/src/doc.js b/src/doc.js index d4bf7e5..72ea59c 100644 --- a/src/doc.js +++ b/src/doc.js @@ -4,7 +4,7 @@ SVG.Doc = SVG.invent({ this.constructor(node || SVG.create('svg')) // set svg element attributes and ensure defs node - this.namespace().defs() + this.namespace() }, // Inherit from @@ -12,40 +12,41 @@ SVG.Doc = SVG.invent({ // Add class methods extend: { - isRoot: function() { - return !this.node.parentNode || !this.node.parentNode instanceof window.SVGElement || this.node.parentNode.nodeName == '#document' + isRoot: function () { + return !this.node.parentNode || !(this.node.parentNode instanceof window.SVGElement) || this.node.parentNode.nodeName === '#document' }, - doc: function() { - if(this.isRoot()) return this - - var parent - while(parent = this.parent(SVG.Doc)) { - if(parent.isRoot()) return parent - } - - // this can only happen when you have something like - // ... - return null + // Check if this is a root svg. If not, call docs from this element + doc: function () { + if (this.isRoot()) return this + return SVG.Element.prototype.doc.call(this) }, // Add namespaces - namespace: function() { - if(!this.isRoot()) return this.doc().namespace() + namespace: function () { + if (!this.isRoot()) return this.doc().namespace() return this .attr({ xmlns: SVG.ns, version: '1.1' }) .attr('xmlns:xlink', SVG.xlink, SVG.xmlns) .attr('xmlns:svgjs', SVG.svgjs, SVG.xmlns) }, // Creates and returns defs element - defs: function() { - if(!this.isRoot()) return this.doc().defs() + defs: function () { + if (!this.isRoot()) return this.doc().defs() return SVG.adopt(this.node.getElementsByTagName('defs')[0]) || this.put(new SVG.Defs()) }, // custom parent method - parent: function () { - return this.node.parentNode.nodeName === '#document' ? null : this.node.parentNode + parent: function (type) { + if (this.isRoot()) { + return this.node.parentNode.nodeName === '#document' ? null : this.node.parentNode + } + + return SVG.Element.prototype.parent.call(this, type) }, // Removes the doc from the DOM remove: function () { + if (!this.isRoot()) { + return SVG.Element.prototype.remove.call(this) + } + if (this.parent()) { this.parent().removeChild(this.node) } @@ -62,8 +63,8 @@ SVG.Doc = SVG.invent({ }, construct: { // Create nested svg document - nested: function() { - return this.put(new SVG.Doc) + nested: function () { + return this.put(new SVG.Doc()) } } }) diff --git a/src/element.js b/src/element.js index e7b5326..0d08579 100644 --- a/src/element.js +++ b/src/element.js @@ -218,7 +218,8 @@ SVG.Element = SVG.invent({ // Get parent document doc: function () { - return this.parent(SVG.Doc).doc() + var p = this.parent(SVG.Doc) + return p && p.doc() }, // Get defs diff --git a/src/flatten.js b/src/flatten.js index 1c32a76..3ba6e22 100644 --- a/src/flatten.js +++ b/src/flatten.js @@ -2,7 +2,7 @@ SVG.extend(SVG.Parent, { flatten: function (parent) { if (this instanceof SVG.Defs) return this - parent = parent || (this instanceof SVG.Doc ? this : this.parent(SVG.Parent)) + parent = parent || (this instanceof SVG.Doc && this.isRoot() ? this : this.parent(SVG.Parent)) this.each(function () { if (this instanceof SVG.Defs) return this diff --git a/src/matrix.js b/src/matrix.js index 6e918d8..e823a81 100644 --- a/src/matrix.js +++ b/src/matrix.js @@ -185,7 +185,7 @@ SVG.Matrix = SVG.invent({ This is needed because FF does not return the transformation matrix for the inner coordinate system when getScreenCTM() is called on nested svgs. However all other Browsers do that */ - if (this instanceof SVG.Nested) { + if (this instanceof SVG.Doc && !this.isRoot()) { var rect = this.rect(1, 1) var m = rect.node.getScreenCTM() rect.remove() diff --git a/src/parent.js b/src/parent.js index 0ff1765..d48e086 100644 --- a/src/parent.js +++ b/src/parent.js @@ -21,10 +21,8 @@ SVG.Parent = SVG.invent({ add: function (element, i) { element = createElement(element) - if (i == null) { - this.node.appendChild(element.node) - } else if (element.node !== this.node.children[i]) { - this.node.insertBefore(element.node, this.node.children[i]) + if (element.node !== this.node.children[i]) { + this.node.insertBefore(element.node, this.node.children[i] || null) } return this diff --git a/src/parser.js b/src/parser.js index c3ab7a4..84c8d77 100644 --- a/src/parser.js +++ b/src/parser.js @@ -11,7 +11,7 @@ SVG.parser = function () { } SVG.parser.nodes = { - svg: new SVG.Nested().size(2, 0).css({ + svg: SVG().size(2, 0).css({ opacity: 0, position: 'absolute', left: '-100%', diff --git a/src/svg.js b/src/svg.js index 4cb6f26..9b3bfd6 100644 --- a/src/svg.js +++ b/src/svg.js @@ -87,13 +87,15 @@ SVG.adopt = function (node) { var element // adopt with element-specific settings - if (node.nodeName == 'svg') + if (node.nodeName === 'svg') { element = new SVG.Doc(node) - else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') + } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') { element = new SVG.Gradient(node) } else if (SVG[capitalize(node.nodeName)]) { element = new SVG[capitalize(node.nodeName)](node) - } else { element = new SVG.Parent(node) } + } else { + element = new SVG.Parent(node) + } return element } -- cgit v1.2.3