-
-
Save L2L2L/01260fea41ede8d46bdb to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
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 () { | |
} | |
]; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Is this not possible via JavaScript alone?