pure.js 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. /*!
  2. PURE Unobtrusive Rendering Engine for HTML
  3. Licensed under the MIT licenses.
  4. More information at: http://www.opensource.org
  5. Copyright (c) 2010 Michael Cvilic - BeeBole.com
  6. Thanks to Rog Peppe for the functional JS jump
  7. revision: 2.33
  8. */
  9. exports.pureInit = function(window, document) {
  10. var $p, pure = $p = function(){
  11. var sel = arguments[0],
  12. ctxt = false;
  13. if(typeof sel === 'string'){
  14. ctxt = arguments[1] || false;
  15. }
  16. return $p.core(sel, ctxt);
  17. };
  18. $p.core = function(sel, ctxt, plugins){
  19. //get an instance of the plugins
  20. var plugins = getPlugins(),
  21. templates = [];
  22. //search for the template node(s)
  23. switch(typeof sel){
  24. case 'string':
  25. templates = plugins.find(ctxt || document, sel);
  26. if(templates.length === 0) {
  27. error('The template "' + sel + '" was not found');
  28. }
  29. break;
  30. case 'undefined':
  31. error('The template root is undefined, check your selector');
  32. break;
  33. default:
  34. templates = [sel];
  35. }
  36. for(var i = 0, ii = templates.length; i < ii; i++){
  37. plugins[i] = templates[i];
  38. }
  39. plugins.length = ii;
  40. // set the signature string that will be replaced at render time
  41. var Sig = '_s' + Math.floor( Math.random() * 1000000 ) + '_',
  42. // another signature to prepend to attributes and avoid checks: style, height, on[events]...
  43. attPfx = '_a' + Math.floor( Math.random() * 1000000 ) + '_',
  44. // rx to parse selectors, e.g. "+tr.foo[class]"
  45. selRx = /^(\+)?([^\@\+]+)?\@?([^\+]+)?(\+)?$/,
  46. // set automatically attributes for some tags
  47. autoAttr = {
  48. IMG:'src',
  49. INPUT:'value'
  50. };
  51. return plugins;
  52. /* * * * * * * * * * * * * * * * * * * * * * * * * *
  53. core functions
  54. * * * * * * * * * * * * * * * * * * * * * * * * * */
  55. // error utility
  56. function error(e){
  57. window.alert(e);
  58. if(typeof console !== 'undefined'){
  59. console.log(e);
  60. debugger;
  61. }
  62. throw('pure error: ' + e);
  63. }
  64. //return a new instance of plugins
  65. function getPlugins(){
  66. var plugins = $p.plugins,
  67. f = function(){};
  68. f.prototype = plugins;
  69. // do not overwrite functions if external definition
  70. f.prototype.compile = plugins.compile || compile;
  71. f.prototype.render = plugins.render || render;
  72. f.prototype.autoRender = plugins.autoRender || autoRender;
  73. f.prototype.find = plugins.find || find;
  74. // give the compiler and the error handling to the plugin context
  75. f.prototype._compiler = compiler;
  76. f.prototype._error = error;
  77. return new f();
  78. }
  79. // returns the outer HTML of a node
  80. function outerHTML(node){
  81. // if IE take the internal method otherwise build one
  82. return node.outerHTML || (
  83. function(n){
  84. var div = document.createElement('div'), h;
  85. div.appendChild( n.cloneNode(true) );
  86. h = div.innerHTML;
  87. div = null;
  88. return h;
  89. })(node);
  90. }
  91. // check if the argument is an array
  92. function isArray(o){
  93. return Object.prototype.toString.call( o ) === "[object Array]";
  94. }
  95. // returns the string generator function
  96. function wrapquote(qfn, f){
  97. return function(ctxt){
  98. return qfn('' + f.call(ctxt.context, ctxt));
  99. };
  100. }
  101. // convert a JSON HTML structure to a dom node and returns the leaf
  102. function domify(ns, pa){
  103. pa = pa || document.createDocumentFragment();
  104. var nn, leaf;
  105. for(var n in ns){
  106. nn = document.createElement(n);
  107. pa.appendChild(nn);
  108. if(typeof ns[n] === 'object'){
  109. leaf = domify(ns[n], nn);
  110. }else{
  111. leaf = document.createElement(ns[n]);
  112. nn.appendChild(leaf);
  113. }
  114. }
  115. return leaf;
  116. };
  117. // default find using querySelector when available on the browser
  118. function find(n, sel){
  119. if(typeof n === 'string'){
  120. sel = n;
  121. n = false;
  122. }
  123. if(typeof document.querySelectorAll !== 'undefined'){
  124. return (n||document).querySelectorAll( sel );
  125. }else{
  126. error('You can test PURE standalone with: iPhone, FF3.5+, Safari4+ and IE8+\n\nTo run PURE on your browser, you need a JS library/framework with a CSS selector engine');
  127. }
  128. }
  129. // create a function that concatenates constant string
  130. // sections (given in parts) and the results of called
  131. // functions to fill in the gaps between parts (fns).
  132. // fns[n] fills in the gap between parts[n-1] and parts[n];
  133. // fns[0] is unused.
  134. // this is the inner template evaluation loop.
  135. function concatenator(parts, fns){
  136. return function(ctxt){
  137. var strs = [ parts[ 0 ] ],
  138. n = parts.length,
  139. fnVal, pVal, attLine, pos;
  140. for(var i = 1; i < n; i++){
  141. fnVal = fns[i]( ctxt );
  142. pVal = parts[i];
  143. // if the value is empty and attribute, remove it
  144. if(fnVal === ''){
  145. attLine = strs[ strs.length - 1 ];
  146. if( ( pos = attLine.search( /[\w]+=\"?$/ ) ) > -1){
  147. strs[ strs.length - 1 ] = attLine.substring( 0, pos );
  148. pVal = pVal.substr( 1 );
  149. }
  150. }
  151. strs[ strs.length ] = fnVal;
  152. strs[ strs.length ] = pVal;
  153. }
  154. return strs.join('');
  155. };
  156. }
  157. // parse and check the loop directive
  158. function parseloopspec(p){
  159. var m = p.match( /^(\w+)\s*<-\s*(\S+)?$/ );
  160. if(m === null){
  161. error('bad loop spec: "' + p + '"');
  162. }
  163. if(m[1] === 'item'){
  164. error('"item<-..." is a reserved word for the current running iteration.\n\nPlease choose another name for your loop.');
  165. }
  166. if( !m[2] || (m[2] && (/context/i).test(m[2]))){ //undefined or space(IE)
  167. m[2] = function(ctxt){return ctxt.context;};
  168. }
  169. return {name: m[1], sel: m[2]};
  170. }
  171. // parse a data selector and return a function that
  172. // can traverse the data accordingly, given a context.
  173. function dataselectfn(sel){
  174. if(typeof(sel) === 'function'){
  175. return sel;
  176. }
  177. //check for a valid js variable name with hyphen(for properties only) and $
  178. var m = sel.match(/^[a-zA-Z$_][\w$]*(\.[\w$-]*[^\.])*$/);
  179. if(m === null){
  180. var found = false, s = sel, parts = [], pfns = [], i = 0, retStr;
  181. // check if literal
  182. if(/\'|\"/.test( s.charAt(0) )){
  183. if(/\'|\"/.test( s.charAt(s.length-1) )){
  184. retStr = s.substring(1, s.length-1);
  185. return function(){ return retStr; };
  186. }
  187. }else{
  188. // check if literal + #{var}
  189. while((m = s.match(/#\{([^{}]+)\}/)) !== null){
  190. found = true;
  191. parts[i++] = s.slice(0, m.index);
  192. pfns[i] = dataselectfn(m[1]);
  193. s = s.slice(m.index + m[0].length, s.length);
  194. }
  195. }
  196. if(!found){
  197. error('bad data selector syntax: ' + sel);
  198. }
  199. parts[i] = s;
  200. return concatenator(parts, pfns);
  201. }
  202. m = sel.split('.');
  203. return function(ctxt){
  204. var data = ctxt.context;
  205. if(!data){
  206. return '';
  207. }
  208. var v = ctxt[m[0]],
  209. i = 0;
  210. if(v && v.item){
  211. data = v.item;
  212. i += 1;
  213. }
  214. var n = m.length;
  215. for(; i < n; i++){
  216. if(!data){break;}
  217. data = data[m[i]];
  218. }
  219. return (!data && data !== 0) ? '':data;
  220. };
  221. }
  222. // wrap in an object the target node/attr and their properties
  223. function gettarget(dom, sel, isloop){
  224. var osel, prepend, selector, attr, append, target = [];
  225. if( typeof sel === 'string' ){
  226. osel = sel;
  227. var m = sel.match(selRx);
  228. if( !m ){
  229. error( 'bad selector syntax: ' + sel );
  230. }
  231. prepend = m[1];
  232. selector = m[2];
  233. attr = m[3];
  234. append = m[4];
  235. if(selector === '.' || ( !selector && attr ) ){
  236. target[0] = dom;
  237. }else{
  238. target = plugins.find(dom, selector);
  239. }
  240. if(!target || target.length === 0){
  241. return error('The node "' + sel + '" was not found in the template');
  242. }
  243. }else{
  244. // autoRender node
  245. prepend = sel.prepend;
  246. attr = sel.attr;
  247. append = sel.append;
  248. target = [dom];
  249. }
  250. if( prepend || append ){
  251. if( prepend && append ){
  252. error('append/prepend cannot take place at the same time');
  253. }else if( isloop ){
  254. error('no append/prepend/replace modifiers allowed for loop target');
  255. }else if( append && isloop ){
  256. error('cannot append with loop (sel: ' + osel + ')');
  257. }
  258. }
  259. var setstr, getstr, quotefn, isStyle, isClass, attName;
  260. if(attr){
  261. isStyle = (/^style$/i).test(attr);
  262. isClass = (/^class$/i).test(attr);
  263. attName = isClass ? 'className' : attr;
  264. setstr = function(node, s) {
  265. node.setAttribute(attPfx + attr, s);
  266. if (attName in node && !isStyle) {
  267. node[attName] = '';
  268. }
  269. if (node.nodeType === 1) {
  270. node.removeAttribute(attr);
  271. isClass && node.removeAttribute(attName);
  272. }
  273. };
  274. if(isStyle) {
  275. getstr = function(node){ return node.style.cssText; };
  276. }else if(isClass) {
  277. getstr = function(node){ return node.className; };
  278. }else{
  279. getstr = function(node){ return node.getAttribute(attr); };
  280. }
  281. if (isStyle || isClass) {//IE no quotes special care
  282. quotefn = function(s){ return s.replace(/\"/g, '&quot;'); };
  283. }else {
  284. quotefn = function(s){ return s.replace(/\"/g, '&quot;').replace(/\s/g, '&nbsp;'); };
  285. }
  286. }else{
  287. if(isloop){
  288. setstr = function(node, s){
  289. // we can have a null parent node
  290. // if we get overlapping targets.
  291. var pn = node.parentNode;
  292. if(pn){
  293. //replace node with s
  294. pn.insertBefore( document.createTextNode( s ), node.nextSibling );
  295. pn.removeChild( node );
  296. }
  297. };
  298. }else{
  299. getstr = function(node){
  300. return node.innerHTML;
  301. };
  302. setstr = function(node, s, ap){
  303. if(ap === true){
  304. node.innerHTML = s;
  305. }else{
  306. node.innerHTML = '';
  307. node.appendChild( document.createTextNode( s ));
  308. }
  309. };
  310. }
  311. quotefn = function(s){
  312. return s;
  313. };
  314. }
  315. var setfn;
  316. if(prepend){
  317. setfn = function(node, s){
  318. setstr( node, s + getstr( node ) , true);
  319. };
  320. }else if(append){
  321. setfn = function(node, s){
  322. setstr( node, getstr( node ) + s , true);
  323. };
  324. }else{
  325. setfn = function(node, s){
  326. setstr( node, s );
  327. };
  328. }
  329. return {attr: attr, nodes: target, set: setfn, sel: osel, quotefn: quotefn};
  330. }
  331. function setsig(target, n){
  332. var sig = Sig + n + ':';
  333. for(var i = 0; i < target.nodes.length; i++){
  334. // could check for overlapping targets here.
  335. target.set( target.nodes[i], sig );
  336. }
  337. }
  338. // read de loop data, and pass it to the inner rendering function
  339. function loopfn(name, dselect, inner, sorter){
  340. return function(ctxt){
  341. var a = dselect(ctxt),
  342. old = ctxt[name],
  343. temp = { items : a },
  344. strs = [],
  345. buildArg = function(idx, temp){
  346. ctxt.pos = temp.pos = idx;
  347. ctxt.item = temp.item = a[ idx ];
  348. ctxt.items = a;
  349. strs.push( inner.call(temp, ctxt ) );
  350. };
  351. ctxt[name] = temp;
  352. if( isArray(a) ){
  353. if(typeof sorter !== 'undefined'){
  354. a.sort(sorter);
  355. }
  356. //loop on array
  357. for(var i = 0, ii = a.length || 0; i < ii; i++){
  358. buildArg(i, temp);
  359. }
  360. }else{
  361. if(typeof sorter !== 'undefined'){
  362. error('sort is only available on arrays, not objects');
  363. }
  364. //loop on collections
  365. for(var prop in a){
  366. a.hasOwnProperty( prop ) && buildArg(prop, temp);
  367. }
  368. }
  369. typeof old !== 'undefined' ? ctxt[name] = old : delete ctxt[name];
  370. return strs.join('');
  371. };
  372. }
  373. // generate the template for a loop node
  374. function loopgen(dom, sel, loop, fns){
  375. var already = false, ls, sorter, prop;
  376. for(prop in loop){
  377. if(loop.hasOwnProperty(prop)){
  378. if(prop === 'sort'){
  379. sorter = loop.sort;
  380. continue;
  381. }
  382. if(already){
  383. error('cannot have more than one loop on a target');
  384. }
  385. ls = prop;
  386. already = true;
  387. }
  388. }
  389. if(!ls){
  390. error('no loop spec');
  391. }
  392. var dsel = loop[ls];
  393. // if it's a simple data selector then we default to contents, not replacement.
  394. if(typeof(dsel) === 'string' || typeof(dsel) === 'function'){
  395. loop = {};
  396. loop[ls] = {root: dsel};
  397. return loopgen(dom, sel, loop, fns);
  398. }
  399. var spec = parseloopspec(ls),
  400. itersel = dataselectfn(spec.sel),
  401. target = gettarget(dom, sel, true),
  402. nodes = target.nodes;
  403. for(i = 0; i < nodes.length; i++){
  404. var node = nodes[i],
  405. inner = compiler(node, dsel);
  406. fns[fns.length] = wrapquote(target.quotefn, loopfn(spec.name, itersel, inner, sorter));
  407. target.nodes = [node]; // N.B. side effect on target.
  408. setsig(target, fns.length - 1);
  409. }
  410. }
  411. function getAutoNodes(n, data){
  412. var ns = n.getElementsByTagName('*'),
  413. an = [],
  414. openLoops = {a:[],l:{}},
  415. cspec,
  416. isNodeValue,
  417. i, ii, j, jj, ni, cs, cj;
  418. //for each node found in the template
  419. for(i = -1, ii = ns.length; i < ii; i++){
  420. ni = i > -1 ?ns[i]:n;
  421. if(ni.nodeType === 1 && ni.className !== ''){
  422. //when a className is found
  423. cs = ni.className.split(' ');
  424. // for each className
  425. for(j = 0, jj=cs.length;j<jj;j++){
  426. cj = cs[j];
  427. // check if it is related to a context property
  428. cspec = checkClass(cj, ni.tagName);
  429. // if so, store the node, plus the type of data
  430. if(cspec !== false){
  431. isNodeValue = (/nodevalue/i).test(cspec.attr);
  432. if(cspec.sel.indexOf('@') > -1 || isNodeValue){
  433. ni.className = ni.className.replace('@'+cspec.attr, '');
  434. if(isNodeValue){
  435. cspec.attr = false;
  436. }
  437. }
  438. an.push({n:ni, cspec:cspec});
  439. }
  440. }
  441. }
  442. }
  443. return an;
  444. function checkClass(c, tagName){
  445. // read the class
  446. var ca = c.match(selRx),
  447. attr = ca[3] || autoAttr[tagName],
  448. cspec = {prepend:!!ca[1], prop:ca[2], attr:attr, append:!!ca[4], sel:c},
  449. i, ii, loopi, loopil, val;
  450. // check in existing open loops
  451. for(i = openLoops.a.length-1; i >= 0; i--){
  452. loopi = openLoops.a[i];
  453. loopil = loopi.l[0];
  454. val = loopil && loopil[cspec.prop];
  455. if(typeof val !== 'undefined'){
  456. cspec.prop = loopi.p + '.' + cspec.prop;
  457. if(openLoops.l[cspec.prop] === true){
  458. val = val[0];
  459. }
  460. break;
  461. }
  462. }
  463. // not found check first level of data
  464. if(typeof val === 'undefined'){
  465. val = isArray(data) ? data[0][cspec.prop] : data[cspec.prop];
  466. // nothing found return
  467. if(typeof val === 'undefined'){
  468. return false;
  469. }
  470. }
  471. // set the spec for autoNode
  472. if(isArray(val)){
  473. openLoops.a.push( {l:val, p:cspec.prop} );
  474. openLoops.l[cspec.prop] = true;
  475. cspec.t = 'loop';
  476. }else{
  477. cspec.t = 'str';
  478. }
  479. return cspec;
  480. }
  481. }
  482. // returns a function that, given a context argument,
  483. // will render the template defined by dom and directive.
  484. function compiler(dom, directive, data, ans){
  485. var fns = [];
  486. // autoRendering nodes parsing -> auto-nodes
  487. ans = ans || data && getAutoNodes(dom, data);
  488. if(data){
  489. var j, jj, cspec, n, target, nodes, itersel, node, inner;
  490. // for each auto-nodes
  491. while(ans.length > 0){
  492. cspec = ans[0].cspec;
  493. n = ans[0].n;
  494. ans.splice(0, 1);
  495. if(cspec.t === 'str'){
  496. // if the target is a value
  497. target = gettarget(n, cspec, false);
  498. setsig(target, fns.length);
  499. fns[fns.length] = wrapquote(target.quotefn, dataselectfn(cspec.prop));
  500. }else{
  501. // if the target is a loop
  502. itersel = dataselectfn(cspec.sel);
  503. target = gettarget(n, cspec, true);
  504. nodes = target.nodes;
  505. for(j = 0, jj = nodes.length; j < jj; j++){
  506. node = nodes[j];
  507. inner = compiler(node, false, data, ans);
  508. fns[fns.length] = wrapquote(target.quotefn, loopfn(cspec.sel, itersel, inner));
  509. target.nodes = [node];
  510. setsig(target, fns.length - 1);
  511. }
  512. }
  513. }
  514. }
  515. // read directives
  516. var target, dsel;
  517. for(var sel in directive){
  518. if(directive.hasOwnProperty(sel)){
  519. dsel = directive[sel];
  520. if(typeof(dsel) === 'function' || typeof(dsel) === 'string'){
  521. // set the value for the node/attr
  522. target = gettarget(dom, sel, false);
  523. setsig(target, fns.length);
  524. fns[fns.length] = wrapquote(target.quotefn, dataselectfn(dsel));
  525. }else{
  526. // loop on node
  527. loopgen(dom, sel, dsel, fns);
  528. }
  529. }
  530. }
  531. // convert node to a string
  532. var h = outerHTML(dom), pfns = [];
  533. // IE adds an unremovable "selected, value" attribute
  534. // hard replace while waiting for a better solution
  535. h = h.replace(/<([^>]+)\s(value\=""|selected)\s?([^>]*)>/ig, "<$1 $3>");
  536. // remove attribute prefix
  537. h = h.split(attPfx).join('');
  538. // slice the html string at "Sig"
  539. var parts = h.split( Sig ), p;
  540. // for each slice add the return string of
  541. for(var i = 1; i < parts.length; i++){
  542. p = parts[i];
  543. // part is of the form "fn-number:..." as placed there by setsig.
  544. pfns[i] = fns[ parseInt(p, 10) ];
  545. parts[i] = p.substring( p.indexOf(':') + 1 );
  546. }
  547. return concatenator(parts, pfns);
  548. }
  549. // compile the template with directive
  550. // if a context is passed, the autoRendering is triggered automatically
  551. // return a function waiting the data as argument
  552. function compile(directive, ctxt, template){
  553. var rfn = compiler( ( template || this[0] ).cloneNode(true), directive, ctxt);
  554. return function(context){
  555. return rfn({context:context});
  556. };
  557. }
  558. //compile with the directive as argument
  559. // run the template function on the context argument
  560. // return an HTML string
  561. // should replace the template and return this
  562. function render(ctxt, directive){
  563. var fn = typeof directive === 'function' ? directive : plugins.compile( directive, false, this[0] );
  564. for(var i = 0, ii = this.length; i < ii; i++){
  565. this[i] = replaceWith( this[i], fn( ctxt, false ));
  566. }
  567. context = null;
  568. return this;
  569. }
  570. // compile the template with autoRender
  571. // run the template function on the context argument
  572. // return an HTML string
  573. function autoRender(ctxt, directive){
  574. var fn = plugins.compile( directive, ctxt, this[0] );
  575. for(var i = 0, ii = this.length; i < ii; i++){
  576. this[i] = replaceWith( this[i], fn( ctxt, false));
  577. }
  578. context = null;
  579. return this;
  580. }
  581. function replaceWith(elm, html){
  582. var tagName = elm.tagName, ne, pa, ep, parent = {TABLE:{}};
  583. if((/TD|TR|TH/).test(tagName)){
  584. var parents = { TR:{TABLE:'TBODY'}, TD:{TABLE:{TBODY:'TR'}}, TH:{TABLE:{THEAD:'TR'}} };
  585. pa = domify( parents[ tagName ] );
  586. }else if( ( /TBODY|THEAD|TFOOT/ ).test( tagName )){
  587. pa = document.createElement('TABLE');
  588. }else{
  589. pa = document.createElement('SPAN');
  590. }
  591. var sys = require("sys");
  592. ep = elm.parentNode;
  593. // avoid IE mem leak
  594. ep.insertBefore(pa, elm);
  595. ep.removeChild(elm);
  596. // pa.style.display = 'none';
  597. pa.innerHTML = html;
  598. ne = pa.firstChild;
  599. ep.insertBefore(ne, pa);
  600. ep.removeChild(pa);
  601. elm = ne;
  602. pa = ne = ep = null;
  603. return elm;
  604. }
  605. };
  606. $p.plugins = {};
  607. $p.libs = {
  608. dojo:function(){
  609. if(typeof document.querySelector === 'undefined'){
  610. $p.plugins.find = function(n, sel){
  611. return dojo.query(sel, n);
  612. };
  613. }
  614. },
  615. domassistant:function(){
  616. if(typeof document.querySelector === 'undefined'){
  617. $p.plugins.find = function(n, sel){
  618. return $(n).cssSelect(sel);
  619. };
  620. }
  621. DOMAssistant.attach({
  622. publicMethods : [ 'compile', 'render', 'autoRender'],
  623. compile:function(directive, ctxt){ return $p(this).compile(directive, ctxt); },
  624. render:function(ctxt, directive){ return $( $p(this).render(ctxt, directive) )[0]; },
  625. autoRender:function(ctxt, directive){ return $( $p(this).autoRender(ctxt, directive) )[0]; }
  626. });
  627. },
  628. jquery:function(){
  629. if(typeof document.querySelector === 'undefined'){
  630. $p.plugins.find = function(n, sel){
  631. return $(n).find(sel);
  632. };
  633. }
  634. jQuery.fn.extend({
  635. compile:function(directive, ctxt){ return $p(this[0]).compile(directive, ctxt); },
  636. render:function(ctxt, directive){ return jQuery( $p( this[0] ).render( ctxt, directive ) ); },
  637. autoRender:function(ctxt, directive){ return jQuery( $p( this[0] ).autoRender( ctxt, directive ) ); }
  638. });
  639. },
  640. mootools:function(){
  641. if(typeof document.querySelector === 'undefined'){
  642. $p.plugins.find = function(n, sel){
  643. return $(n).getElements(sel);
  644. };
  645. }
  646. Element.implement({
  647. compile:function(directive, ctxt){ return $p(this).compile(directive, ctxt); },
  648. render:function(ctxt, directive){ return $p(this).render(ctxt, directive); },
  649. autoRender:function(ctxt, directive){ return $p(this).autoRender(ctxt, directive); }
  650. });
  651. },
  652. prototype:function(){
  653. if(typeof document.querySelector === 'undefined'){
  654. $p.plugins.find = function(n, sel){
  655. n = n === document ? n.body : n;
  656. return typeof n === 'string' ? $$(n) : $(n).select(sel);
  657. };
  658. }
  659. Element.addMethods({
  660. compile:function(element, directive, ctxt){ return $p(element).compile(directive, ctxt); },
  661. render:function(element, ctxt, directive){ return $p(element).render(ctxt, directive); },
  662. autoRender:function(element, ctxt, directive){ return $p(element).autoRender(ctxt, directive); }
  663. });
  664. },
  665. sizzle:function(){
  666. if(typeof document.querySelector === 'undefined'){
  667. $p.plugins.find = function(n, sel){
  668. return window.Sizzle(sel, n);
  669. };
  670. }
  671. },
  672. sly:function(){
  673. if(typeof document.querySelector === 'undefined'){
  674. $p.plugins.find = function(n, sel){
  675. return Sly(sel, n);
  676. };
  677. }
  678. }
  679. };
  680. // get lib specifics if available
  681. (function(){
  682. var libkey =
  683. typeof dojo !== 'undefined' && 'dojo' ||
  684. typeof DOMAssistant !== 'undefined' && 'domassistant' ||
  685. typeof jQuery !== 'undefined' && 'jquery' ||
  686. typeof MooTools !== 'undefined' && 'mootools' ||
  687. typeof Prototype !== 'undefined' && 'prototype' ||
  688. typeof window.Sizzle !== 'undefined' && 'sizzle' ||
  689. typeof Sly !== 'undefined' && 'sly';
  690. libkey && $p.libs[libkey]();
  691. })();
  692. return pure;
  693. };