| 'use strict'; |
| |
| var values = require('object.values'); |
| if (!Object.values) { |
| values.shim(); |
| } |
| |
| |
| var CSSClassList = function(node) { |
| this.parentNode = node; |
| this.classNames = new Set(); |
| this.classAttr = null; |
| //this.classValue = null; |
| }; |
| |
| /** |
| * Performs a deep clone of this object. |
| * |
| * @param parentNode the parentNode to assign to the cloned result |
| */ |
| CSSClassList.prototype.clone = function(parentNode) { |
| var node = this; |
| var nodeData = {}; |
| |
| Object.keys(node).forEach(function(key) { |
| if (key !== 'parentNode') { |
| nodeData[key] = node[key]; |
| } |
| }); |
| |
| // Deep-clone node data. |
| nodeData = JSON.parse(JSON.stringify(nodeData)); |
| |
| var clone = new CSSClassList(parentNode); |
| Object.assign(clone, nodeData); |
| return clone; |
| }; |
| |
| CSSClassList.prototype.hasClass = function() { |
| this.classAttr = { // empty class attr |
| 'name': 'class', |
| 'value': null |
| }; |
| |
| this.addClassHandler(); |
| }; |
| |
| |
| // attr.class |
| |
| CSSClassList.prototype.addClassHandler = function() { |
| |
| Object.defineProperty(this.parentNode.attrs, 'class', { |
| get: this.getClassAttr.bind(this), |
| set: this.setClassAttr.bind(this), |
| enumerable: true, |
| configurable: true |
| }); |
| |
| this.addClassValueHandler(); |
| }; |
| |
| // attr.class.value |
| |
| CSSClassList.prototype.addClassValueHandler = function() { |
| |
| Object.defineProperty(this.classAttr, 'value', { |
| get: this.getClassValue.bind(this), |
| set: this.setClassValue.bind(this), |
| enumerable: true, |
| configurable: true |
| }); |
| }; |
| |
| CSSClassList.prototype.getClassAttr = function() { |
| return this.classAttr; |
| }; |
| |
| CSSClassList.prototype.setClassAttr = function(newClassAttr) { |
| this.setClassValue(newClassAttr.value); // must before applying value handler! |
| |
| this.classAttr = newClassAttr; |
| this.addClassValueHandler(); |
| }; |
| |
| CSSClassList.prototype.getClassValue = function() { |
| var arrClassNames = Array.from(this.classNames); |
| return arrClassNames.join(' '); |
| }; |
| |
| CSSClassList.prototype.setClassValue = function(newValue) { |
| if(typeof newValue === 'undefined') { |
| this.classNames.clear(); |
| return; |
| } |
| var arrClassNames = newValue.split(' '); |
| this.classNames = new Set(arrClassNames); |
| }; |
| |
| |
| CSSClassList.prototype.add = function(/* variadic */) { |
| this.hasClass(); |
| Object.values(arguments).forEach(this._addSingle.bind(this)); |
| }; |
| |
| CSSClassList.prototype._addSingle = function(className) { |
| this.classNames.add(className); |
| }; |
| |
| |
| CSSClassList.prototype.remove = function(/* variadic */) { |
| this.hasClass(); |
| Object.values(arguments).forEach(this._removeSingle.bind(this)); |
| }; |
| |
| CSSClassList.prototype._removeSingle = function(className) { |
| this.classNames.delete(className); |
| }; |
| |
| |
| CSSClassList.prototype.item = function(index) { |
| var arrClassNames = Array.from(this.classNames); |
| return arrClassNames[index]; |
| }; |
| |
| CSSClassList.prototype.toggle = function(className, force) { |
| if(this.contains(className) || force === false) { |
| this.classNames.delete(className); |
| } |
| this.classNames.add(className); |
| }; |
| |
| CSSClassList.prototype.contains = function(className) { |
| return this.classNames.has(className); |
| }; |
| |
| |
| module.exports = CSSClassList; |