Skip to content

Commit

Permalink
Merge pull request #369 from kpdecker/reduce-intermediate
Browse files Browse the repository at this point in the history
Reduce intermediate object creation
  • Loading branch information
matthewmueller committed Feb 1, 2014
2 parents 7d9bcb6 + 9e0ebe7 commit f9e3ab4
Show file tree
Hide file tree
Showing 4 changed files with 120 additions and 74 deletions.
103 changes: 59 additions & 44 deletions lib/api/attributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ var _ = require('underscore'),
isTag = utils.isTag,
decode = utils.decode,
encode = utils.encode,
domEach = utils.domEach,
hasOwn = Object.prototype.hasOwnProperty,
rspace = /\s+/,

Expand All @@ -20,6 +21,27 @@ var _ = require('underscore'),
rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/;


var getAttr = function(elem, name) {
if (!elem || !isTag(elem)) return;

if (!elem.attribs) {
elem.attribs = {};
}

// Return the entire attribs object if no attribute specified
if (!name) {
for (var a in elem.attribs) {
elem.attribs[a] = decode(elem.attribs[a]);
}
return elem.attribs;
}

if (hasOwn.call(elem.attribs, name)) {
// Get the (decoded) attribute
return decode(elem.attribs[name]);
}
};

var setAttr = function(el, name, value) {
if (typeof name === 'object') return _.extend(el.attribs, name);

Expand All @@ -40,31 +62,12 @@ var attr = exports.attr = function(name, value) {
setAttr(el, name, value.call(this, i, el.attribs[name]));
});
}
return this.each(function(i, el) {
return domEach(this, function(i, el) {
el.attribs = setAttr(el, name, value);
});
}

var elem = this[0];

if (!elem || !isTag(elem)) return;

if (!elem.attribs) {
elem.attribs = {};
}

// Return the entire attribs object if no attribute specified
if (!name) {
for (var a in elem.attribs) {
elem.attribs[a] = decode(elem.attribs[a]);
}
return elem.attribs;
}

if (hasOwn.call(elem.attribs, name)) {
// Get the (decoded) attribute
return decode(elem.attribs[name]);
}
return getAttr(this[0], name);
};

var setData = function(el, name, value) {
Expand Down Expand Up @@ -102,7 +105,7 @@ var data = exports.data = function(name, value) {

// Set the value (with attr map support)
if (typeof name === 'object' || value !== undefined) {
this.each(function(i, el) {
domEach(this, function(i, el) {
el.data = setData(el, name, value);
});
return this;
Expand Down Expand Up @@ -218,7 +221,7 @@ var removeAttribute = function(elem, name) {


var removeAttr = exports.removeAttr = function(name) {
this.each(function(i, elem) {
domEach(this, function(i, elem) {
removeAttribute(elem, name);
});

Expand All @@ -245,22 +248,22 @@ var addClass = exports.addClass = function(value) {
if (!value || !_.isString(value)) return this;

var classNames = value.split(rspace),
numElements = this.length,
numClasses,
setClass,
$elem;
numElements = this.length;


for (var i = 0; i < numElements; i++) {
$elem = this._make(this[i]);
// If selected element isnt a tag, move on
if (!isTag(this[i])) continue;

// If we don't already have classes
if (!$elem.attr('class')) {
$elem.attr('class', classNames.join(' ').trim());
var className = getAttr(this[i], 'class'),
numClasses,
setClass;

if (!className) {
setAttr(this[i], 'class', classNames.join(' ').trim());
} else {
setClass = ' ' + $elem.attr('class') + ' ';
setClass = ' ' + className + ' ';
numClasses = classNames.length;

// Check if class already exists
Expand All @@ -269,17 +272,18 @@ var addClass = exports.addClass = function(value) {
setClass += classNames[j] + ' ';
}

$elem.attr('class', setClass.trim());
setAttr(this[i], 'class', setClass.trim());
}
}

return this;
};

var splitClass = function(className) {
return className ? className.trim().split(rspace) : [];
};

var removeClass = exports.removeClass = function(value) {
var split = function(className) {
return className ? className.trim().split(rspace) : [];
};
var classes, removeAll;

// Handle if value is a function
Expand All @@ -289,14 +293,15 @@ var removeClass = exports.removeClass = function(value) {
});
}

classes = split(value);
classes = splitClass(value);
removeAll = arguments.length === 0;

return this.each(function(i, el) {
return domEach(this, function(i, el) {
if (!isTag(el)) return;

el.attribs.class = removeAll ?
'' :
_.difference(split(el.attribs.class), classes).join(' ');
_.difference(splitClass(el.attribs.class), classes).join(' ');
});
};

Expand All @@ -315,20 +320,30 @@ var toggleClass = exports.toggleClass = function(value, stateVal) {
numClasses = classNames.length,
isBool = typeof stateVal === 'boolean',
numElements = this.length,
$elem,
state;
elementClasses,
index;

for (var i = 0; i < numElements; i++) {
$elem = this._make(this[i]);
// If selected element isnt a tag, move on
if (!isTag(this[i])) continue;

elementClasses = splitClass(this[i].attribs.class);

// Check if class already exists
for (var j = 0; j < numClasses; j++) {
// check each className given, space separated list
state = isBool ? stateVal : !$elem.hasClass(classNames[j]);
$elem[state ? 'addClass' : 'removeClass'](classNames[j]);
// Check if the class name is curently defined
index = !isBool || !stateVal ? elementClasses.indexOf(classNames[j]) : -1;

// Add if stateValue === true or we are toggling and there is no value
if (isBool ? stateVal : index < 0) {
elementClasses.push(classNames[j]);
} else if (index >= 0) {
// Otherwise remove but only if the item exists
elementClasses.splice(index, 1);
}
}

this[i].attribs.class = elementClasses.join(' ');
}

return this;
Expand Down
33 changes: 19 additions & 14 deletions lib/api/manipulation.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ var _ = require('underscore'),
$ = require('../static'),
updateDOM = parse.update,
evaluate = parse.evaluate,
encode = require('../utils').encode,
utils = require('../utils'),
domEach = utils.domEach,
encode = utils.encode,
slice = Array.prototype.slice;

// Create an array of nodes, recursing into arrays and parsing strings if
// necessary
var makeDomArray = function(elem) {
Expand All @@ -27,12 +28,16 @@ var _insert = function(concatenator) {
var elems = slice.call(arguments),
dom = makeDomArray(elems);

return this.each(function(i, el) {
if (_.isFunction(elems[0])) {
if (_.isFunction(elems[0])) {
return this.each(function(i, el) {
dom = makeDomArray(elems[0].call(el, i, this.html()));
}
updateDOM(concatenator(dom, el.children || (el.children = [])), el);
});
updateDOM(concatenator(dom, el.children || (el.children = [])), el);
});
} else {
return domEach(this, function(i, el) {
updateDOM(concatenator(dom, el.children || (el.children = [])), el);
});
}
};
};

Expand All @@ -48,7 +53,7 @@ var after = exports.after = function() {
var elems = slice.call(arguments),
dom = makeDomArray(elems);

this.each(function(i, el) {
domEach(this, function(i, el) {
var parent = el.parent || el.root,
siblings = parent.children,
index = siblings.indexOf(el);
Expand All @@ -74,7 +79,7 @@ var before = exports.before = function() {
var elems = slice.call(arguments),
dom = makeDomArray(elems);

this.each(function(i, el) {
domEach(this, function(i, el) {
var parent = el.parent || el.root,
siblings = parent.children,
index = siblings.indexOf(el);
Expand Down Expand Up @@ -106,7 +111,7 @@ var remove = exports.remove = function(selector) {
if (selector)
elems = elems.filter(selector);

elems.each(function(i, el) {
domEach(elems, function(i, el) {
var parent = el.parent || el.root,
siblings = parent.children,
index = siblings.indexOf(el);
Expand All @@ -125,7 +130,7 @@ var remove = exports.remove = function(selector) {
var replaceWith = exports.replaceWith = function(content) {
var dom = makeDomArray(content);

this.each(function(i, el) {
domEach(this, function(i, el) {
var parent = el.parent || el.root,
siblings = parent.children,
index;
Expand All @@ -151,7 +156,7 @@ var replaceWith = exports.replaceWith = function(content) {
};

var empty = exports.empty = function() {
this.each(function(i, el) {
domEach(this, function(i, el) {
el.children = [];
});
return this;
Expand All @@ -168,7 +173,7 @@ var html = exports.html = function(str) {

str = str.cheerio ? str.toArray() : evaluate(str);

this.each(function(i, el) {
domEach(this, function(i, el) {
el.children = str;
updateDOM(el.children, el);
});
Expand Down Expand Up @@ -201,7 +206,7 @@ var text = exports.text = function(str) {
};

// Append text node to each selected elements
this.each(function(i, el) {
domEach(this, function(i, el) {
el.children = elem;
updateDOM(el.children, el);
});
Expand Down
Loading

0 comments on commit f9e3ab4

Please sign in to comment.