urltomarkdown/node_modules/domino/lib/DOMTokenList.js

187 lines
4.8 KiB
JavaScript

"use strict";
// DOMTokenList implementation based on https://github.com/Raynos/DOM-shim
var utils = require('./utils');
module.exports = DOMTokenList;
function DOMTokenList(getter, setter) {
this._getString = getter;
this._setString = setter;
this._length = 0;
this._lastStringValue = '';
this._update();
}
Object.defineProperties(DOMTokenList.prototype, {
length: { get: function() { return this._length; } },
item: { value: function(index) {
var list = getList(this);
if (index < 0 || index >= list.length) {
return null;
}
return list[index];
}},
contains: { value: function(token) {
token = String(token); // no error checking for contains()
var list = getList(this);
return list.indexOf(token) > -1;
}},
add: { value: function() {
var list = getList(this);
for (var i = 0, len = arguments.length; i < len; i++) {
var token = handleErrors(arguments[i]);
if (list.indexOf(token) < 0) {
list.push(token);
}
}
// Note: as per spec, if handleErrors() throws any errors, we never
// make it here and none of the changes take effect.
// Also per spec: we run the "update steps" even if no change was
// made (ie, if the token already existed)
this._update(list);
}},
remove: { value: function() {
var list = getList(this);
for (var i = 0, len = arguments.length; i < len; i++) {
var token = handleErrors(arguments[i]);
var index = list.indexOf(token);
if (index > -1) {
list.splice(index, 1);
}
}
// Note: as per spec, if handleErrors() throws any errors, we never
// make it here and none of the changes take effect.
// Also per spec: we run the "update steps" even if no change was
// made (ie, if the token wasn't previously present)
this._update(list);
}},
toggle: { value: function toggle(token, force) {
token = handleErrors(token);
if (this.contains(token)) {
if (force === undefined || force === false) {
this.remove(token);
return false;
}
return true;
} else {
if (force === undefined || force === true) {
this.add(token);
return true;
}
return false;
}
}},
replace: { value: function replace(token, newToken) {
// weird corner case of spec: if `token` contains whitespace, but
// `newToken` is the empty string, we must throw SyntaxError not
// InvalidCharacterError (sigh)
if (String(newToken)==='') { utils.SyntaxError(); }
token = handleErrors(token);
newToken = handleErrors(newToken);
var list = getList(this);
var idx = list.indexOf(token);
if (idx < 0) {
// Note that, per spec, we do not run the update steps on this path.
return false;
}
var idx2 = list.indexOf(newToken);
if (idx2 < 0) {
list[idx] = newToken;
} else {
// "replace the first instance of either `token` or `newToken` with
// `newToken` and remove all other instances"
if (idx < idx2) {
list[idx] = newToken;
list.splice(idx2, 1);
} else {
// idx2 is already `newToken`
list.splice(idx, 1);
}
}
this._update(list);
return true;
}},
toString: { value: function() {
return this._getString();
}},
value: {
get: function() {
return this._getString();
},
set: function(v) {
this._setString(v);
this._update();
}
},
// Called when the setter is called from outside this interface.
_update: { value: function(list) {
if (list) {
fixIndex(this, list);
this._setString(list.join(" ").trim());
} else {
fixIndex(this, getList(this));
}
this._lastStringValue = this._getString();
} },
});
function fixIndex(clist, list) {
var oldLength = clist._length;
var i;
clist._length = list.length;
for (i = 0; i < list.length; i++) {
clist[i] = list[i];
}
// Clear/free old entries.
for (; i < oldLength; i++) {
clist[i] = undefined;
}
}
function handleErrors(token) {
token = String(token);
if (token === "") {
utils.SyntaxError();
}
if (/[ \t\r\n\f]/.test(token)) {
utils.InvalidCharacterError();
}
return token;
}
function toArray(clist) {
var length = clist._length;
var arr = Array(length);
for (var i = 0; i < length; i++) {
arr[i] = clist[i];
}
return arr;
}
function getList(clist) {
var strProp = clist._getString();
if (strProp === clist._lastStringValue) {
return toArray(clist);
}
var str = strProp.replace(/(^[ \t\r\n\f]+)|([ \t\r\n\f]+$)/g, '');
if (str === "") {
return [];
} else {
var seen = Object.create(null);
return str.split(/[ \t\r\n\f]+/g).filter(function(n) {
var key = '$' + n;
if (seen[key]) { return false; }
seen[key] = true;
return true;
});
}
}