2017-01-26 09:03:53 -05:00
|
|
|
module.exports = {
|
2017-03-25 17:07:34 -04:00
|
|
|
/**
|
|
|
|
* Transform the values of an object via a mapper function
|
|
|
|
* @param {Object} obj
|
|
|
|
* @param {Function} mapper
|
|
|
|
*/
|
2017-01-26 09:03:53 -05:00
|
|
|
mapObject(obj, mapper) {
|
|
|
|
const mappedObj = {};
|
|
|
|
Object.keys(obj).forEach(key => { mappedObj[key] = mapper(key, obj[key]); });
|
|
|
|
return mappedObj;
|
2017-03-25 17:07:34 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parses the attributes from a string taken from an HTML element start tag
|
|
|
|
* E.g. ` a="one" b="two" `
|
|
|
|
* @param {string} str
|
|
|
|
*/
|
|
|
|
parseAttributes(str) {
|
|
|
|
const attrMap = {};
|
2017-04-01 14:34:10 -04:00
|
|
|
let index = 0;
|
2017-03-25 17:07:34 -04:00
|
|
|
|
|
|
|
skipSpace();
|
|
|
|
|
|
|
|
while(index < str.length) {
|
|
|
|
takeAttribute();
|
|
|
|
skipSpace();
|
|
|
|
}
|
|
|
|
|
|
|
|
function takeAttribute() {
|
|
|
|
const key = takeKey();
|
|
|
|
skipSpace();
|
|
|
|
if (tryEquals()) {
|
|
|
|
skipSpace();
|
|
|
|
const quote = tryQuote();
|
|
|
|
attrMap[key] = takeValue(quote);
|
|
|
|
// skip the closing quote or whitespace
|
|
|
|
index++;
|
|
|
|
} else {
|
|
|
|
attrMap[key] = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function skipSpace() {
|
|
|
|
while(index < str.length && /\s/.test(str[index])) {
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function tryEquals() {
|
|
|
|
if (str[index] === '=') {
|
|
|
|
index++;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function takeKey() {
|
|
|
|
let startIndex = index;
|
|
|
|
while(index < str.length && /[^\s=]/.test(str[index])) {
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
return str.substring(startIndex, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
function tryQuote() {
|
|
|
|
const quote = str[index];
|
2017-04-01 14:34:10 -04:00
|
|
|
if (['"', '\''].indexOf(quote) !== -1) {
|
2017-03-25 17:07:34 -04:00
|
|
|
index++;
|
|
|
|
return quote;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
function takeValue(quote) {
|
|
|
|
let startIndex = index;
|
|
|
|
|
|
|
|
if (quote) {
|
|
|
|
while(index < str.length && str[index] !== quote) {
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
if (index >= str.length) {
|
|
|
|
throw new Error(`Unterminated quoted attribute value in \`${str}\`. Starting at ${startIndex}. Expected a ${quote} but got "end of string".`);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
while(index < str.length && /\S/.test(str[index])) {
|
|
|
|
index++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return str.substring(startIndex, index);
|
|
|
|
}
|
|
|
|
|
|
|
|
return attrMap;
|
2017-04-26 12:58:57 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
renderAttributes(attrMap) {
|
2017-05-10 09:44:43 -04:00
|
|
|
return Object.keys(attrMap).map(key =>
|
|
|
|
attrMap[key] === false ? '' :
|
|
|
|
attrMap[key] === true ? ` ${key}` :
|
|
|
|
` ${key}="${attrMap[key].replace(/"/g, '"')}"`).join('');
|
2018-06-04 06:43:15 -04:00
|
|
|
},
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Merge the specified properties from the source to the target document
|
|
|
|
* @param {Document} target The document to receive the properties from the source
|
|
|
|
* @param {Document} source The document from which to get the properties to merge
|
|
|
|
* @param {string[]} properties A collection of the names of the properties to merge
|
|
|
|
*/
|
|
|
|
mergeProperties(target, source, properties) {
|
|
|
|
properties.forEach(property => {
|
|
|
|
if (source.hasOwnProperty(property)) {
|
|
|
|
target[property] = source[property];
|
|
|
|
}
|
|
|
|
});
|
|
|
|
},
|
2017-04-01 14:34:10 -04:00
|
|
|
};
|