Skip to content

Instantly share code, notes, and snippets.

@mlopez0987
Forked from brettz9/jqflower-test.html
Created August 3, 2014 19:54
Show Gist options
  • Select an option

  • Save mlopez0987/01260fea41ede8d46bdb to your computer and use it in GitHub Desktop.

Select an option

Save mlopez0987/01260fea41ede8d46bdb to your computer and use it in GitHub Desktop.
<!DOCTYPE html>
<meta charset="utf-8" />
<label class="myItems">Hello</label>
<label class="myItems">World!</label>
<script src="jqflower.js"></script>
<script>
try {
queryAll([document, '.myItems']).reduce(function (a, b) {
a.push(b);
}, []);
// also consider https://github.com/nkallen/jquery-database
var result = JQFlower().
// XML Pipelining / XProc functions: http://www.ibm.com/developerworks/library/x-xproc/
$declaration(
{output:[]}
).
$( // Better to put wrapper outside, but can at least put in order here if desired
document.body
).
$for(
['$a', $at('count'), $in(document, '.myItems')],
{$a: $in([document, '.myItems']), // Fix: also allow $in() to accept callback, e.g., auto-generated by Ajax-creator funtion
at: '$count' // for numbering count as go along
}, // allow retrieval from server, and also allow XPath (e.g. MDBX?)
// allow joining multiple nodes in association with first without need for count (and way to make up for difference with append)
// also allow callback which is given 'this' as argument to continue the chain instead (since asynchronous);
{$a: JSONP(url, function (flower) { // JSONP returns the function so $for can detect it should call with 'this'?
flower.$let().$where().$return(function () {document.body.appendChild($a);});
})}
). // Fix: allow multiple 'for's (including non-nested joinable ones in the same $for())
$at('$count').
$at({'$item': arr}).
$at({'$item': function (ct, node) {
return arr[ct] ? arr[c] : 'something else';
}}).
$let([
{$b:5},
// call functions with the count and/or 'for'?
{$c: function () { // Fix: make one useful for XML and one useful for JSON
// Fix: also allow {$c: letter('$a', '@value')}
// {$c: increment(data)}
return string(this.$a);
}}
]).
// allow this too?
// $for('$a', $in('.myItems', document))
/**/
$where(function () { // Fix: add custom where and orderBy specific to XML and ones specific to JSON; demo calling function to return function,
// e.g., $where('$a', '>', '$b')
return number(this.$a) > 5;
}).
$orderBy(function (a, b) {
// e.g., $orderBy('@value', 'asc')
// If a zero or single argument defined function, just treat it as returning all filtered (with argument as the nodes)
return a.attr('value') > b.attr('value'); // [?value]\\
}).
//*/
// Fix: throw if any extra return function calls
// Fix: decide whether recursion needs to be nested inside here, or can be as next chained call; should be chained since two subsequent "for"'s must be (unless using return); specify output as "input" so continues into other process
$return(function (output) { // Demo as output XML DOM, XML String (concat with outside HTML string for use in $J()), or JSON Object, JSON array, and JSON string
// XML.$for(...); // Fix: Test nested and demo a join!
// Demo modification of input nodes (XQUF)
//$return(push('string($a) + $b;'));
output.push(string(this.$a) + this.$b); // $count, etc.
});
alert(result);
// Make XML.for and a JSON.for classes, which have different default where/orderBy (and include different built-in static classes)
var result = $for({$a: '.myItems'}, document).
$let({$b: '$a.length'}). // also allow $let({$b:function () {return this.$a.length;}}).
//or $let({$b:function () this.$a.length}). in JS 1.8
$return('alert(string($a) + $b);');
// also allow $return(function ($a) {return string(this.$a) + this.$b;}); // with the $a in the arguments being the latest or 2nd latest for (but not let?)?
// could also refer to global if set up global "var $a, $b;", etc.?
var result = $for({$a: '.myItems'}, document).
// Fix: At least allow "for"'s to be accessible as $a ($b, etc.) arguments like this:
$let(function ($a, $b) {return {$c:string($a)+string($b)};}). // Do we need this? // Fix: (function($a,$b) { })();
$return('alert(string($a) + $b);');
}
catch(e) {
alert(e);
}
</script>
// Inspiration from XQuery, https://github.com/nkallen/jquery-database , and http://www.sitepen.com/blog/2008/07/16/jsonquery-data-querying-beyond-jsonpath/
// I also came across http://plugins.jquery.com/project/jLINQ (and http://www.hugoware.net/Projects/jLinq ) and http://jsinq.codeplex.com/ after starting this work
// Flower is inspired by the FLWOR expressions of XQuery (For, Let, Where, Order by, Return)
// Methods are prefixed by '$' to avoid use of JavaScript keywords (e.g., for, let, return)
// (JS-pre-declared) Variables could be implementable without need for "this." in subsequent methods by using eval() and strings, but less JS-like (and may as well do XQuery parser in that case) and also less secure
// Fix: only accept where, order by, and return if a let or for has been called, and require where, order by, and return in that order
function JQFlower (opts) {
if (!(this instanceof JQFlower)) {
return new JQFlower(opts);
}
this.depth = 0;
this.forMap = {children:{}};
if (opts) {
this.$declaration(opts);
}
}
// Allows invoking on an explicit function separately though it is unnecessary
// as this function is also auto-invoked by the constructor
JQFlower.prototype.$declaration = function (opts) {
for (var opt in opts) {
}
return this;
};
JQFlower.prototype.$ = JQFlower.prototype.$wrapper = function () {
return this;
};
JQFlower.prototype.$for = function (query) {
for (var key in query) {
query = query[key];
break;
}
this.key = key;
this.query = query;
this.vrs = '';
if (typeof query === 'function') {
query.call(this); // Continue the FLWOR chain asynchronously
}
};
JQFlower.prototype.$at = function (vrs) {
return this;
};
JQFlower.prototype.$let = function (vrs) {
if (typeof vrs === 'function') {
vrs = vrs();
}
for (var p in vrs) {
this.vrs += 'var ' + p + '=' + vrs[p] + ';';
}
return this;
};
JQFlower.prototype.$where = function (__clause__) {
// Fix: filter down this.key
eval(this.vrs);
this.nodes = this.nodes.querySelectorAll(__clause__);
return this;
};
JQFlower.prototype.$orderBy = function (order) {
// Fix: order this.key
eval(this.vrs);
return this;
};
JQFlower.prototype.$return = function (cb) {
if (typeof cb === 'function') {
var scope = {};
scope[this.key] = document.querySelectorAll(this.query);
return cb.call(scope);
}
var nodes = document.querySelectorAll(this.query);
for (var i=0; i < nodes.length; i++) {
eval('var '+this.key + '= nodes[i];' +this.vrs + ';' + cb);
}
};
// Branch off into domain-specific functions (and associated with constant strings?)
// Fix: define this on JQFlower, unless a 'global' declaration is made
// Make JSON-specific ones, jQuery-specific (e.g., filter()), etc.
// XQuery-like element converter
function string (el) {
if (el.length) {
var content = '';
for (var i = 0; i < el.length; i++) {
content += el[i].textContent;
}
return content;
}
return el.textContent;
}
// For users who don't want jQuery
var $in = function queryAll (node, selector) {
if (selector) {
return [].slice.call(node.querySelectorAll(this.query));
}
else {
return [].slice.call(document.querySelectorAll(this.query));
}
};
var queryAll = $in;
/*
Design requirements
1) Support all of FLWOR
2) Allow hierarchically evaluated but sequentially nested
3) Synchronous or asynchronous loading of URLs?
4) Reference to JSXQueryParser code?
5) Shortcoming: inability of xqueryjs to represent the recursive possibilities of XQueryX or XSL, so make (hopefully easier!) version of XQueryX-as-E()
collection() argument with Mongodb?
*/
// Note: Need function to get variables (unless used some string syntax)
$let('myUls', function ($) {
return $('ul.myClass', 'http://www.example.com');
}).
$for('ul', function ($) {
return $('ul.anotherClass');
}).
$for('li', function ($) {
return $('li.anotherClass');
}).
$let('myLis', function ($) {
return $('li', this.$myUls);
}).
$let('links', 'a'). // 2nd argument string as shorthand for function () {return $('a');}
$where(function (liWhereMethod) { // Long-hand form (but better to avoid adding too much logic in here)
return liWhereMethod($('*:contains("hello")', this.$links));
}).
$orderBy(function () {
return [this.$links.children('em'), 'ASC'];
}).
$return(function () {
return $('div', [this.$li, this.$myLis]);
});
// Other possible approach (if iteration predictable order, could use regular objects instead of array of functions, but ECMAScript does not require for-in iteration order to be same as creation order)
var xqueryTemplates = [
function $for () {
},
function $let () {
},
function $for2 () {
}
];
@mlopez0987
Copy link
Author

Is this not possible via JavaScript alone?

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