Skip to content

Commit

Permalink
proposal for #807, includes #550, allow multiple events for `SVG.off(…
Browse files Browse the repository at this point in the history
…)` and add option argument
  • Loading branch information
Fuzzyma committed Feb 27, 2018
1 parent 2afc67f commit c609461
Show file tree
Hide file tree
Showing 3 changed files with 73 additions and 80 deletions.
7 changes: 4 additions & 3 deletions src/element.js
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {}
Expand All @@ -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)
Expand Down
144 changes: 68 additions & 76 deletions src/event.js
Original file line number Diff line number Diff line change
@@ -1,144 +1,136 @@
// Add events to elements

;[ 'click',
'dblclick',
'mousedown',
'mouseup',
'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)
return this
}
})

// 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)
})
}

// 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
}
})
2 changes: 1 addition & 1 deletion src/svg.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

0 comments on commit c609461

Please sign in to comment.