diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/animation/Animator.js | 8 | ||||
-rw-r--r-- | src/animation/Morphable.js (renamed from src/types/Morphable.js) | 19 | ||||
-rw-r--r-- | src/animation/Runner.js | 22 | ||||
-rw-r--r-- | src/animation/Timeline.js | 131 | ||||
-rw-r--r-- | src/elements/Bare.js | 31 | ||||
-rw-r--r-- | src/elements/Dom.js | 15 | ||||
-rw-r--r-- | src/elements/HtmlNode.js | 6 | ||||
-rw-r--r-- | src/elements/Style.js | 6 | ||||
-rw-r--r-- | src/main.js | 19 | ||||
-rw-r--r-- | src/modules/optional/arrange.js | 13 | ||||
-rw-r--r-- | src/polyfills/children.js | 8 | ||||
-rw-r--r-- | src/polyfills/innerHTML.js | 95 | ||||
-rw-r--r-- | src/svg.js | 5 | ||||
-rw-r--r-- | src/types/Box.js | 26 | ||||
-rw-r--r-- | src/types/Color.js | 20 | ||||
-rw-r--r-- | src/utils/adopter.js | 46 | ||||
-rw-r--r-- | src/utils/methods.js | 13 | ||||
-rw-r--r-- | src/utils/window.js | 23 |
18 files changed, 320 insertions, 186 deletions
diff --git a/src/animation/Animator.js b/src/animation/Animator.js index cac0eb9..2786602 100644 --- a/src/animation/Animator.js +++ b/src/animation/Animator.js @@ -5,7 +5,7 @@ const Animator = { nextDraw: null, frames: new Queue(), timeouts: new Queue(), - timer: globals.window.performance || globals.window.Date, + timer: () => globals.window.performance || globals.window.Date, transforms: [], frame (fn) { @@ -29,7 +29,7 @@ const Animator = { delay = delay || 0 // Work out when the event should fire - var time = Animator.timer.now() + delay + var time = Animator.timer().now() + delay // Add the timeout to the end of the queue var node = Animator.timeouts.push({ run: fn, time: time }) @@ -43,11 +43,11 @@ const Animator = { }, cancelFrame (node) { - Animator.frames.remove(node) + node != null && Animator.frames.remove(node) }, clearTimeout (node) { - Animator.timeouts.remove(node) + node != null && Animator.timeouts.remove(node) }, _draw (now) { diff --git a/src/types/Morphable.js b/src/animation/Morphable.js index e7af8c1..56ffe95 100644 --- a/src/types/Morphable.js +++ b/src/animation/Morphable.js @@ -1,14 +1,14 @@ -import { Ease } from '../animation/Controller.js' +import { Ease } from './Controller.js' import { delimiter, numberAndUnit, pathLetters } from '../modules/core/regex.js' import { extend } from '../utils/adopter.js' -import Color from './Color.js' -import PathArray from './PathArray.js' -import SVGArray from './SVGArray.js' -import SVGNumber from './SVGNumber.js' +import Color from '../types/Color.js' +import PathArray from '../types/PathArray.js' +import SVGArray from '../types/SVGArray.js' +import SVGNumber from '../types/SVGNumber.js' export default class Morphable { constructor (stepper) { @@ -203,7 +203,14 @@ export class ObjectBag { return } - var entries = Object.entries(objOrArr || {}).sort((a, b) => { + objOrArr = objOrArr || {} + var entries = [] + + for (let i in objOrArr) { + entries.push([i, objOrArr[i]]) + } + + entries.sort((a, b) => { return a[0] - b[0] }) diff --git a/src/animation/Runner.js b/src/animation/Runner.js index 7e04c21..3af5823 100644 --- a/src/animation/Runner.js +++ b/src/animation/Runner.js @@ -9,7 +9,7 @@ import Animator from './Animator.js' import Box from '../types/Box.js' import EventTarget from '../types/EventTarget.js' import Matrix from '../types/Matrix.js' -import Morphable, { TransformBag } from '../types/Morphable.js' +import Morphable, { TransformBag } from './Morphable.js' import Point from '../types/Point.js' import SVGNumber from '../types/SVGNumber.js' import Timeline from './Timeline.js' @@ -48,7 +48,10 @@ export default class Runner extends EventTarget { // Store the state of the runner this.enabled = true this._time = 0 - this._last = 0 + this._lastTime = 0 + + // At creation, the runner is in reseted state + this._reseted = true // Save transforms applied to this runner this.transforms = new Matrix() @@ -261,7 +264,7 @@ export default class Runner extends EventTarget { // Figure out if we just started var duration = this.duration() - var justStarted = this._lastTime < 0 && this._time > 0 + var justStarted = this._lastTime <= 0 && this._time > 0 var justFinished = this._lastTime < this._time && this.time > duration this._lastTime = this._time if (justStarted) { @@ -274,6 +277,9 @@ export default class Runner extends EventTarget { var declarative = this._isDeclarative this.done = !declarative && !justFinished && this._time >= duration + // Runner is running. So its not in reseted state anymore + this._reseted = false + // Call initialise and the run function if (running || declarative) { this._initialise(running) @@ -281,6 +287,7 @@ export default class Runner extends EventTarget { // clear the transforms on this runner so they dont get added again and again this.transforms = new Matrix() var converged = this._run(declarative ? dt : position) + this.fire('step', this) } // correct the done flag here @@ -292,6 +299,13 @@ export default class Runner extends EventTarget { return this } + reset () { + if (this._reseted) return this + this.loops(0) + this._reseted = true + return this + } + finish () { return this.step(Infinity) } @@ -564,7 +578,7 @@ registerMethods({ return new Runner(o.duration) .loop(o) .element(this) - .timeline(timeline) + .timeline(timeline.play()) .schedule(delay, when) }, diff --git a/src/animation/Timeline.js b/src/animation/Timeline.js index 6abcb80..c3ad07c 100644 --- a/src/animation/Timeline.js +++ b/src/animation/Timeline.js @@ -10,64 +10,58 @@ var makeSchedule = function (runnerInfo) { return { start: start, duration: duration, end: end, runner: runnerInfo.runner } } +const defaultSource = function () { + let w = globals.window + return (w.performance || w.Date).now() +} + export default class Timeline extends EventTarget { // Construct a new timeline on the given element - constructor () { + constructor (timeSource = defaultSource) { super() - this._timeSource = function () { - let w = globals.window - return (w.performance || w.Date).now() - } + this._timeSource = timeSource // Store the timing variables this._startTime = 0 this._speed = 1.0 - // Play control variables control how the animation proceeds - this._reverse = false + // Determines how long a runner is hold in memory. Can be a dt or true/false this._persist = 0 // Keep track of the running animations and their starting parameters this._nextFrame = null - this._paused = false + this._paused = true this._runners = [] this._order = [] this._time = 0 this._lastSourceTime = 0 this._lastStepTime = 0 - } - /** - * - */ + // Make sure that step is always called in class context + this._step = this._step.bind(this) + } // schedules a runner on the timeline schedule (runner, delay, when) { - // FIXME: how to sort? maybe by runner id? if (runner == null) { return this._runners.map(makeSchedule).sort(function (a, b) { - return (a.start - b.start) || (a.duration - b.duration) + return a.runner.id - b.runner.id }) } - if (!this.active()) { - this._step() - if (when == null) { - when = 'now' - } - } - // The start time for the next animation can either be given explicitly, // derived from the current timeline time or it can be relative to the // last start time to chain animations direclty + var absoluteStartTime = 0 + var endTime = this.getEndTime() delay = delay || 0 // Work out when to start the animation if (when == null || when === 'last' || when === 'after') { // Take the last time and increment - absoluteStartTime = this._startTime + absoluteStartTime = endTime } else if (when === 'absolute' || when === 'start') { absoluteStartTime = delay delay = 0 @@ -86,21 +80,18 @@ export default class Timeline extends EventTarget { // Manage runner runner.unschedule() runner.timeline(this) - runner.time(-delay) - - // Save startTime for next runner - this._startTime = absoluteStartTime + runner.duration() + delay + // runner.time(-delay) // Save runnerInfo this._runners[runner.id] = { persist: this.persist(), runner: runner, - start: absoluteStartTime + start: absoluteStartTime + delay } - // Save order and continue + // Save order, update Time if needed and continue this._order.push(runner.id) - this._continue() + this.updateTime()._continue() return this } @@ -115,27 +106,42 @@ export default class Timeline extends EventTarget { return this } + // Calculates the end of the timeline + getEndTime () { + var lastRunnerInfo = this._runners[this._order[this._order.length - 1]] + var lastDuration = lastRunnerInfo ? lastRunnerInfo.runner.duration() : 0 + var lastStartTime = lastRunnerInfo ? lastRunnerInfo.start : 0 + return lastStartTime + lastDuration + } + + // Makes sure, that after pausing the time doesn't jump + updateTime () { + if (!this.active()) { + this._lastSourceTime = this._timeSource() + } + return this + } + play () { // Now make sure we are not paused and continue the animation this._paused = false - return this._continue() + return this.updateTime()._continue() } pause () { - // Cancel the next animation frame and pause - this._nextFrame = null this._paused = true - return this + return this._continue() } stop () { - // Cancel the next animation frame and go to start - this.seek(-this._time) + // Go to start and pause + this.time(0) return this.pause() } finish () { - this.seek(Infinity) + // Go to end and pause + this.time(this.getEndTime() + 1) return this.pause() } @@ -154,14 +160,13 @@ export default class Timeline extends EventTarget { } seek (dt) { - this._time += dt - return this._continue() + return this.time(this._time + dt) } time (time) { if (time == null) return this._time this._time = time - return this + return this._continue(true) } persist (dtOrForever) { @@ -176,20 +181,25 @@ export default class Timeline extends EventTarget { return this } - _step () { - // If the timeline is paused, just do nothing - if (this._paused) return - + _step (immediateStep = false) { // Get the time delta from the last time and update the time var time = this._timeSource() var dtSource = time - this._lastSourceTime + + if (immediateStep) dtSource = 0 + var dtTime = this._speed * dtSource + (this._time - this._lastStepTime) this._lastSourceTime = time - // Update the time - this._time += dtTime + // Only update the time if we use the timeSource. + // Otherwise use the current time + if (!immediateStep) { + // Update the time + this._time += dtTime + this._time = this._time < 0 ? 0 : this._time + } this._lastStepTime = this._time - // this.fire('time', this._time) + this.fire('time', this._time) // Run all of the runners directly var runnersLeft = false @@ -204,8 +214,13 @@ export default class Timeline extends EventTarget { let dtToStart = this._time - runnerInfo.start // Dont run runner if not started yet - if (dtToStart < 0) { + if (dtToStart <= 0) { runnersLeft = true + + // This is for the case that teh timeline was seeked so that the time + // is now before the startTime of the runner. Thats why we need to set + // the runner to position 0 + runner.reset() continue } else if (dtToStart < dt) { // Adjust dt to make sure that animation is on point @@ -234,21 +249,27 @@ export default class Timeline extends EventTarget { } } - // Get the next animation frame to keep the simulation going - if (runnersLeft) { - this._nextFrame = Animator.frame(this._step.bind(this)) + // Basically: we continue when there are runners right from us in time + // when -->, and when runners are left from us when <-- + if ((runnersLeft && !(this._speed < 0 && this._time === 0)) || (this._order.length && this._speed < 0 && this._time > 0)) { + this._continue() } else { - this._nextFrame = null + this.fire('finished') + this.pause() } + return this } // Checks if we are running and continues the animation - _continue () { + _continue (immediateStep = false) { + Animator.cancelFrame(this._nextFrame) + this._nextFrame = null + + if (immediateStep) return this._step(true) if (this._paused) return this - if (!this._nextFrame) { - this._nextFrame = Animator.frame(this._step.bind(this)) - } + + this._nextFrame = Animator.frame(this._step) return this } diff --git a/src/elements/Bare.js b/src/elements/Bare.js deleted file mode 100644 index a057634..0000000 --- a/src/elements/Bare.js +++ /dev/null @@ -1,31 +0,0 @@ -import { nodeOrNew, register, wrapWithAttrCheck } from '../utils/adopter.js' -import { registerMethods } from '../utils/methods.js' -import Container from './Container.js' -import { globals } from '../utils/window.js' - -export default class Bare extends Container { - constructor (node, attrs) { - super(nodeOrNew(node, typeof node === 'string' ? null : node), attrs) - } - - words (text) { - // remove contents - while (this.node.hasChildNodes()) { - this.node.removeChild(this.node.lastChild) - } - - // create text node - this.node.appendChild(globals.document.createTextNode(text)) - - return this - } -} - -register(Bare) - -registerMethods('Container', { - // Create an element that is not described by SVG.js - element: wrapWithAttrCheck(function (node) { - return this.put(new Bare(node)) - }) -}) diff --git a/src/elements/Dom.js b/src/elements/Dom.js index bccfbb8..ff8542e 100644 --- a/src/elements/Dom.js +++ b/src/elements/Dom.js @@ -4,6 +4,7 @@ import { eid, extend, makeInstance, + makeNode, register } from '../utils/adopter.js' import { find } from '../modules/core/selector.js' @@ -88,6 +89,10 @@ export default class Dom extends EventTarget { return this } + element (nodeName) { + return this.put(new Dom(makeNode(nodeName))) + } + // Get first child first () { return adopt(this.node.firstChild) @@ -285,12 +290,20 @@ export default class Dom extends EventTarget { fragment.appendChild(well.firstElementChild) } + let parent = this.parent() + // Add the whole fragment at once return outerHTML - ? this.replace(fragment) + ? this.replace(fragment) && parent : this.add(fragment) } + words (text) { + // This is faster than removing all children and adding a new one + this.node.textContent = text + return this + } + // write svgjs data to the dom writeDataToDom () { // dump variables recursively diff --git a/src/elements/HtmlNode.js b/src/elements/HtmlNode.js deleted file mode 100644 index 009b122..0000000 --- a/src/elements/HtmlNode.js +++ /dev/null @@ -1,6 +0,0 @@ -import { register } from '../utils/adopter.js' -import Dom from './Dom.js' - -export default class HtmlNode extends Dom {} - -register(HtmlNode) diff --git a/src/elements/Style.js b/src/elements/Style.js index 50ec50e..0b1cdb7 100644 --- a/src/elements/Style.js +++ b/src/elements/Style.js @@ -23,8 +23,8 @@ export default class Style extends Element { super(nodeOrNew('style', node), node) } - words (w) { - this.node.textContent += (w || '') + addText (w = '') { + this.node.textContent += w return this } @@ -37,7 +37,7 @@ export default class Style extends Element { } rule (selector, obj) { - return this.words(cssRule(selector, obj)) + return this.addText(cssRule(selector, obj)) } } diff --git a/src/main.js b/src/main.js index 919fb25..8ea3e5d 100644 --- a/src/main.js +++ b/src/main.js @@ -7,7 +7,7 @@ import './modules/optional/memory.js' import './modules/optional/sugar.js' import './modules/optional/transform.js' -import { extend } from './utils/adopter.js' +import { extend, makeInstance } from './utils/adopter.js' import { getMethodNames, getMethodsFor } from './utils/methods.js' import Box from './types/Box.js' import Circle from './elements/Circle.js' @@ -30,7 +30,7 @@ import Morphable, { TransformBag, makeMorphable, registerMorphableType -} from './types/Morphable.js' +} from './animation/Morphable.js' import Path from './elements/Path.js' import PathArray from './types/PathArray.js' import Pattern from './elements/Pattern.js' @@ -43,9 +43,13 @@ import SVGArray from './types/SVGArray.js' import SVGNumber from './types/SVGNumber.js' import Shape from './elements/Shape.js' import Svg from './elements/Svg.js' +import Symbol from './elements/Symbol.js' import Text from './elements/Text.js' import Tspan from './elements/Tspan.js' import * as defaults from './modules/core/defaults.js' +import * as utils from './utils/utils.js' +import * as namespaces from './modules/core/namespaces.js' +import * as regex from './modules/core/regex.js' export { Morphable, @@ -56,9 +60,8 @@ export { NonMorphable } -export { defaults } -export * from './utils/utils.js' -export * from './modules/core/namespaces.js' +export { defaults, utils, namespaces, regex } +export const SVG = makeInstance export { default as parser } from './modules/core/parser.js' export { default as find } from './modules/core/selector.js' export * from './modules/core/event.js' @@ -73,19 +76,18 @@ export { default as Runner } from './animation/Runner.js' export { default as Timeline } from './animation/Timeline.js' /* Types */ -export { default as SVGArray } from './types/SVGArray.js' +export { default as Array } from './types/SVGArray.js' export { default as Box } from './types/Box.js' export { default as Color } from './types/Color.js' export { default as EventTarget } from './types/EventTarget.js' export { default as Matrix } from './types/Matrix.js' -export { default as SVGNumber } from './types/SVGNumber.js' +export { default as Number } from './types/SVGNumber.js' export { default as PathArray } from './types/PathArray.js' export { default as Point } from './types/Point.js' export { default as PointArray } from './types/PointArray.js' export { default as List } from './types/List.js' /* Elements */ -export { default as Bare } from './elements/Bare.js' export { default as Circle } from './elements/Circle.js' export { default as ClipPath } from './elements/ClipPath.js' export { default as Container } from './elements/Container.js' @@ -95,7 +97,6 @@ export { default as Element } from './elements/Element.js' export { default as Ellipse } from './elements/Ellipse.js' export { default as Gradient } from './elements/Gradient.js' export { default as G } from './elements/G.js' -export { default as HtmlNode } from './elements/HtmlNode.js' export { default as A } from './elements/A.js' export { default as Image } from './elements/Image.js' export { default as Line } from './elements/Line.js' diff --git a/src/modules/optional/arrange.js b/src/modules/optional/arrange.js index 6ce2eea..f06509a 100644 --- a/src/modules/optional/arrange.js +++ b/src/modules/optional/arrange.js @@ -107,5 +107,16 @@ export function insertAfter (element) { } registerMethods('Dom', { - siblings, position, next, prev, forward, backward, front, back, before, after + siblings, + position, + next, + prev, + forward, + backward, + front, + back, + before, + after, + insertBefore, + insertAfter }) diff --git a/src/polyfills/children.js b/src/polyfills/children.js new file mode 100644 index 0000000..98e9143 --- /dev/null +++ b/src/polyfills/children.js @@ -0,0 +1,8 @@ +import { filter } from '../utils/utils.js' + +// IE11: children does not work for svg nodes +export default function children (node) { + return filter(node.childNodes, function (child) { + return child.nodeType === 1 + }) +} diff --git a/src/polyfills/innerHTML.js b/src/polyfills/innerHTML.js new file mode 100644 index 0000000..4be7f1b --- /dev/null +++ b/src/polyfills/innerHTML.js @@ -0,0 +1,95 @@ +/* globals SVGElement, DOMParser */ + +(function () { + try { + if (SVGElement.prototype.innerHTML) return + } catch (e) { return } + + var serializeXML = function (node, output) { + var nodeType = node.nodeType + if (nodeType === 3) { + output.push(node.textContent.replace(/&/, '&').replace(/</, '<').replace('>', '>')) + } else if (nodeType === 1) { + output.push('<', node.tagName) + if (node.hasAttributes()) { + [].forEach.call(node.attributes, function (attrNode) { + output.push(' ', attrNode.name, '=\'', attrNode.value, '\'') + }) + } + if (node.hasChildNodes()) { + output.push('>'); + [].forEach.call(node.childNodes, function (childNode) { + serializeXML(childNode, output) + }) + output.push('</', node.tagName, '>') + } else { + output.push('/>') + } + } else if (nodeType === 8) { + output.push('<!--', node.nodeValue, '-->') + } + } + + Object.defineProperty(SVGElement.prototype, 'innerHTML', { + get: function () { + var output = [] + var childNode = this.firstChild + while (childNode) { + serializeXML(childNode, output) + childNode = childNode.nextSibling + } + return output.join('') + }, + set: function (markupText) { + while (this.firstChild) { + this.removeChild(this.firstChild) + } + + try { + var dXML = new DOMParser() + dXML.async = false + + var sXML = '<svg xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\'>' + markupText + '</svg>' + var svgDocElement = dXML.parseFromString(sXML, 'text/xml').documentElement + + var childNode = svgDocElement.firstChild + while (childNode) { + this.appendChild(this.ownerDocument.importNode(childNode, true)) + childNode = childNode.nextSibling + } + } catch (e) { + throw new Error('Can not set innerHTML on node') + }; + } + }) + + Object.defineProperty(SVGElement.prototype, 'outerHTML', { + get: function () { + var output = [] + serializeXML(this, output) + return output.join('') + }, + set: function (markupText) { + while (this.firstChild) { + this.removeChild(this.firstChild) + } + + try { + var dXML = new DOMParser() + dXML.async = false + + var sXML = '<svg xmlns=\'http://www.w3.org/2000/svg\' xmlns:xlink=\'http://www.w3.org/1999/xlink\'>' + markupText + '</svg>' + var svgDocElement = dXML.parseFromString(sXML, 'text/xml').documentElement + + var childNode = svgDocElement.firstChild + while (childNode) { + this.parentNode.insertBefore(this.ownerDocument.importNode(childNode, true), this) + // this.appendChild(this.ownerDocument.importNode(childNode, true)); + childNode = childNode.nextSibling + } + } catch (e) { + throw new Error('Can not set outerHTML on node') + }; + } + }) +})() @@ -1,5 +1,4 @@ import * as svgMembers from './main.js' -import * as regex from './modules/core/regex.js' import { makeInstance } from './utils/adopter.js' // The main wrapping element @@ -8,7 +7,3 @@ export default function SVG (element) { } Object.assign(SVG, svgMembers) - -SVG.utils = SVG -SVG.regex = regex -SVG.get = SVG diff --git a/src/types/Box.js b/src/types/Box.js index c90c7e0..d2ddcdd 100644 --- a/src/types/Box.js +++ b/src/types/Box.js @@ -104,7 +104,7 @@ export default class Box { } } -function getBox (cb) { +function getBox (cb, retry) { let box try { @@ -114,23 +114,29 @@ function getBox (cb) { throw new Error('Element not in the dom') } } catch (e) { - try { - let clone = this.clone().addTo(parser().svg).show() - box = cb(clone.node) - clone.remove() - } catch (e) { - throw new Error('Getting a bounding box of element "' + this.node.nodeName + '" is not possible') - } + box = retry(this) } + return box } export function bbox () { - return new Box(getBox.call(this, (node) => node.getBBox())) + return new Box(getBox.call(this, (node) => node.getBBox(), (el) => { + try { + let clone = el.clone().addTo(parser().svg).show() + let box = clone.node.getBBox() + clone.remove() + return box + } catch (e) { + throw new Error('Getting bbox of element "' + el.node.nodeName + '" is not possible') + } + })) } export function rbox (el) { - let box = new Box(getBox.call(this, (node) => node.getBoundingClientRect())) + let box = new Box(getBox.call(this, (node) => node.getBoundingClientRect(), (el) => { + throw new Error('Getting rbox of element "' + el.node.nodeName + '" is not possible') + })) if (el) return box.transform(el.screenCTM().inverse()) return box.addOffset() } diff --git a/src/types/Color.js b/src/types/Color.js index 0004251..b745bfd 100644 --- a/src/types/Color.js +++ b/src/types/Color.js @@ -78,7 +78,7 @@ export default class Color { Object.assign(this, { _a: a, _b: b, _c: c, _d: d, space }) // If the user gave us an array, make the color from it } else if (a instanceof Array) { - this.space = b || a[4] || 'rgb' + this.space = b || (typeof a[3] === 'string' ? a[3] : a[4]) || 'rgb' Object.assign(this, { _a: a[0], _b: a[1], _c: a[2], _d: a[3] || 0 }) } else if (a instanceof Object) { // Set the object up and assign its values directly @@ -109,20 +109,6 @@ export default class Color { Object.assign(this, components) } - opacity (opacity = 1) { - this.opacity = opacity - } - - /* - - */ - - brightness () { - const { _a: r, _b: g, _c: b } = this.rgb() - const value = (r / 255 * 0.30) + (g / 255 * 0.59) + (b / 255 * 0.11) - return value - } - /* Conversion Methods */ @@ -332,14 +318,14 @@ export default class Color { Input and Output methods */ - hex () { + toHex () { let { _a, _b, _c } = this.rgb() let [ r, g, b ] = [ _a, _b, _c ].map(componentHex) return `#${r}${g}${b}` } toString () { - return this.hex() + return this.toHex() } toRgb () { diff --git a/src/utils/adopter.js b/src/utils/adopter.js index ec6b2e5..5830f5c 100644 --- a/src/utils/adopter.js +++ b/src/utils/adopter.js @@ -5,7 +5,7 @@ import { globals } from '../utils/window.js' import Base from '../types/Base.js' const elements = {} -export const root = Symbol('root') +export const root = '___SYMBOL___ROOT___' // Method for element creation export function makeNode (name) { @@ -17,7 +17,7 @@ export function makeInstance (element) { if (element instanceof Base) return element if (typeof element === 'object') { - return adopt(element) + return adopter(element) } if (element == null) { @@ -25,7 +25,7 @@ export function makeInstance (element) { } if (typeof element === 'string' && element.charAt(0) !== '<') { - return adopt(globals.document.querySelector(element)) + return adopter(globals.document.querySelector(element)) } var node = makeNode('svg') @@ -33,7 +33,7 @@ export function makeInstance (element) { // We can use firstChild here because we know, // that the first char is < and thus an element - element = adopt(node.firstChild) + element = adopter(node.firstChild) return element } @@ -50,25 +50,25 @@ export function adopt (node) { // make sure a node isn't already adopted if (node.instance instanceof Base) return node.instance - if (!(node instanceof globals.window.SVGElement)) { - return new elements.HtmlNode(node) - } - // initialize variables - var element - - // adopt with element-specific settings - if (node.nodeName === 'svg') { - element = new elements[root](node) - } else if (node.nodeName === 'linearGradient' || node.nodeName === 'radialGradient') { - element = new elements.Gradient(node) - } else if (elements[capitalize(node.nodeName)]) { - element = new elements[capitalize(node.nodeName)](node) - } else { - element = new elements.Bare(node) + var className = capitalize(node.nodeName) + + // Make sure that gradients are adopted correctly + if (className === 'LinearGradient' || className === 'RadialGradient') { + className = 'Gradient' + + // Fallback to Dom if element is not known + } else if (!elements[className]) { + className = 'Dom' } - return element + return new elements[className](node) +} + +let adopter = adopt + +export function mockAdopt (mock = adopt) { + adopter = mock } export function register (element, name = element.name, asRoot = false) { @@ -123,9 +123,9 @@ export function extend (modules, methods, attrCheck) { } } -export function extendWithAttrCheck (...args) { - extend(...args, true) -} +// export function extendWithAttrCheck (...args) { +// extend(...args, true) +// } export function wrapWithAttrCheck (fn) { return function (...args) { diff --git a/src/utils/methods.js b/src/utils/methods.js index 527e7b7..bc05a70 100644 --- a/src/utils/methods.js +++ b/src/utils/methods.js @@ -1,5 +1,4 @@ const methods = {} -const constructors = {} const names = [] export function registerMethods (name, m) { @@ -11,8 +10,8 @@ export function registerMethods (name, m) { } if (typeof name === 'object') { - for (let [ _name, _m ] of Object.entries(name)) { - registerMethods(_name, _m) + for (let _name in name) { + registerMethods(_name, name[_name]) } return } @@ -32,11 +31,3 @@ export function getMethodNames () { export function addMethodNames (_names) { names.push(..._names) } - -export function registerConstructor (name, setup) { - constructors[name] = setup -} - -export function getConstructor (name) { - return constructors[name] ? { setup: constructors[name], name } : {} -} diff --git a/src/utils/window.js b/src/utils/window.js index 9e51339..626fde3 100644 --- a/src/utils/window.js +++ b/src/utils/window.js @@ -7,3 +7,26 @@ export function registerWindow (win = null, doc = null) { globals.window = win globals.document = doc } + +const save = {} + +export function saveWindow () { + save.window = globals.window + save.document = globals.document +} + +export function restoreWindow () { + globals.window = save.window + globals.document = save.document +} + +export function withWindow (win, fn) { + saveWindow() + registerWindow(win, win.document) + fn(win, win.document) + restoreWindow() +} + +export function getWindow () { + return globals.window +} |