Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Inspired by David Herman's gist here: https://gist.github.com/2011902
(( window ) -> {
// "doQuery" is a fake, future descendant of "jQuery"
// Create a WeakMap instance for Node data storage. This is perfect
// because using the Node as the key ensures that any data associated
// with the Node will be GC'ed if the Node is removed from the DOM
var nodeData = new WeakMap();
function doQuery( selector, context ) {
var matches;
this.context = context || document;
// Handle doQuery(DOMElement)
if ( selector.nodeType ) {
this.context = this[ 0 ] = selector;
this.length = 1;
return this;
}
// query DOM for elements
matches = (context || document).querySelectorAll( selector );
if ( matches.length ) {
// spread matches NodeList into an array
[ ...matches ].forEach((match, index) => do {
// do-expression retains outer |this|
this[ index ] = match;
});
this.length = matches.length;
}
}
// Multipurpose static function for getting and setting
// values to a node collection
// The value(s) can optionally be executed if it's a function
doQuery.execute = ( ...args ) -> {
let [ nodes, key, val, fn ] = args,
length = nodes.length,
p;
// Call self to set many { key: val }
// on a collection
if ( key && typeof key === "object" ) {
for ( p in key ) {
doQuery.execute( nodes, p, key[ p ], fn );
}
// Sets a single "key" to "val" for
// all nodes in a collection
} else {
nodes.each( (node) => fn(node, key, val) );
}
return nodes;
};
doQuery.prototype.each = ( callback ) -> {
// Spread the "array like" instance object into an array
[ ...this ].forEach(( node, index ) -> {
// Inside the callback:
// Preserve jQuery's "node is |this|" style semantics
// Also, index comes first in jQuery callback params
callback.call( node, index, node );
});
return this;
};
doQuery.prototype.data = ( opts ) -> {
// If no argument, return stored data of first item in set
if ( !opts ) {
return nodeData.get( this[0] );
}
// |this| is the doQuery/jQuery instance/query match set
return this.each((index) -> {
// Inside the callback:
// |this| refers to the node, as set by
// callback.call( node, ... ) in
// doQuery.prototype.each
let merged = {},
data = nodeData.get( this );
// I need a way to merge two objects.
// A serious pain-point. This is totally made up
// and has no proposal to back it up
Object.merge( merged, data, opts );
nodeData.set( this, merged );
});
};
// Static style get/set function
doQuery.style = ( node, prop, value ) -> {
let defaultView = node.ownerDocument.defaultView;
if ( value ) {
node.style[ prop ] = value;
} else {
return defaultView.getComputedStyle( node ).getPropertyValue( prop );
}
};
// Proto css method
doQuery.prototype.css = ( ...args ) -> {
let [ prop, value ] = args;
// If no value, return current style of
// first node in collection
if ( !value ) {
return doQuery.syle( this[0], prop );
}
// Otherwise, apply new style to
// all nodes in collection
return doQuery.execute( this, prop, value, (node, k, v) => doQuery.style(node, k, v) );
};
window.doQuery = doQuery;
})( this );
@savetheclocktower
Copy link

savetheclocktower commented Mar 11, 2012

Isn't the do expression at line 14 incorrect? If I read things right, => is all you need to retain outer this.

@rwaldron
Copy link
Author

rwaldron commented Mar 11, 2012

IIUC, the AssignmentExpression needs to be wrapped in the do-expression, per http://wiki.ecmascript.org/doku.php?id=strawman:do_expressions Take a look, could be that I missed something?

@rwaldron
Copy link
Author

rwaldron commented Mar 11, 2012

So, after re-reading, you're right about only needing => retain the outer this, but in my case, I have expressions that might require more logic and therefore benefit from the do { ... } expression form

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment