PageRenderTime 26ms CodeModel.GetById 0ms RepoModel.GetById 0ms app.codeStats 0ms

/jax-engine/vendor/assets/javascripts/ejs.js

http://github.com/sinisterchipmunk/jax
JavaScript | 505 lines | 466 code | 25 blank | 14 comment | 59 complexity | 6e69d4142f72ca44395897df009355dc MD5 | raw file
  1. (function(){
  2. var rsplit = function(string, regex) {
  3. var result = regex.exec(string),retArr = new Array(), first_idx, last_idx, first_bit;
  4. while (result != null)
  5. {
  6. first_idx = result.index; last_idx = regex.lastIndex;
  7. if ((first_idx) != 0)
  8. {
  9. first_bit = string.substring(0,first_idx);
  10. retArr.push(string.substring(0,first_idx));
  11. string = string.slice(first_idx);
  12. }
  13. retArr.push(result[0]);
  14. string = string.slice(result[0].length);
  15. result = regex.exec(string);
  16. }
  17. if (! string == '')
  18. {
  19. retArr.push(string);
  20. }
  21. return retArr;
  22. },
  23. chop = function(string){
  24. return string.substr(0, string.length - 1);
  25. },
  26. extend = function(d, s){
  27. for(var n in s){
  28. if(s.hasOwnProperty(n)) d[n] = s[n]
  29. }
  30. }
  31. EJS = function( options ){
  32. options = typeof options == "string" ? {view: options} : options
  33. this.set_options(options);
  34. if(options.precompiled){
  35. this.template = {};
  36. this.template.process = options.precompiled;
  37. EJS.update(this.name, this);
  38. return;
  39. }
  40. if(options.element)
  41. {
  42. if(typeof options.element == 'string'){
  43. var name = options.element
  44. options.element = document.getElementById( options.element )
  45. if(options.element == null) throw name+'does not exist!'
  46. }
  47. if(options.element.value){
  48. this.text = options.element.value
  49. }else{
  50. this.text = options.element.innerHTML
  51. }
  52. this.name = options.element.id
  53. this.type = '['
  54. }else if(options.url){
  55. options.url = EJS.endExt(options.url, this.extMatch);
  56. this.name = this.name ? this.name : options.url;
  57. var url = options.url
  58. //options.view = options.absolute_url || options.view || options.;
  59. var template = EJS.get(this.name /*url*/, this.cache);
  60. if (template) return template;
  61. if (template == EJS.INVALID_PATH) return null;
  62. try{
  63. this.text = EJS.request( url+(this.cache ? '' : '?'+Math.random() ));
  64. }catch(e){}
  65. if(this.text == null){
  66. throw( {type: 'EJS', message: 'There is no template at '+url} );
  67. }
  68. //this.name = url;
  69. }
  70. var template = new EJS.Compiler(this.text, this.type);
  71. template.compile(options, this.name);
  72. EJS.update(this.name, this);
  73. this.template = template;
  74. };
  75. /* @Prototype*/
  76. EJS.prototype = {
  77. /**
  78. * Renders an object with extra view helpers attached to the view.
  79. * @param {Object} object data to be rendered
  80. * @param {Object} extra_helpers an object with additonal view helpers
  81. * @return {String} returns the result of the string
  82. */
  83. render : function(object, extra_helpers){
  84. object = object || {};
  85. this._extra_helpers = extra_helpers;
  86. var v = new EJS.Helpers(object, extra_helpers || {});
  87. return this.template.process.call(object, object,v);
  88. },
  89. update : function(element, options){
  90. if(typeof element == 'string'){
  91. element = document.getElementById(element)
  92. }
  93. if(options == null){
  94. _template = this;
  95. return function(object){
  96. EJS.prototype.update.call(_template, element, object)
  97. }
  98. }
  99. if(typeof options == 'string'){
  100. params = {}
  101. params.url = options
  102. _template = this;
  103. params.onComplete = function(request){
  104. var object = eval( request.responseText )
  105. EJS.prototype.update.call(_template, element, object)
  106. }
  107. EJS.ajax_request(params)
  108. }else
  109. {
  110. element.innerHTML = this.render(options)
  111. }
  112. },
  113. out : function(){
  114. return this.template.out;
  115. },
  116. /**
  117. * Sets options on this view to be rendered with.
  118. * @param {Object} options
  119. */
  120. set_options : function(options){
  121. this.type = options.type || EJS.type;
  122. this.cache = options.cache != null ? options.cache : EJS.cache;
  123. this.text = options.text || null;
  124. this.name = options.name || null;
  125. this.ext = options.ext || EJS.ext;
  126. this.extMatch = new RegExp(this.ext.replace(/\./, '\.'));
  127. }
  128. };
  129. EJS.endExt = function(path, match){
  130. if(!path) return null;
  131. match.lastIndex = 0
  132. return path+ (match.test(path) ? '' : this.ext )
  133. }
  134. /* @Static*/
  135. EJS.Scanner = function(source, left, right) {
  136. extend(this,
  137. {left_delimiter: left +'%',
  138. right_delimiter: '%'+right,
  139. double_left: left+'%%',
  140. double_right: '%%'+right,
  141. left_equal: left+'%=',
  142. left_comment: left+'%#'})
  143. this.SplitRegexp = left=='[' ? /(\[%%)|(%%\])|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/ : new RegExp('('+this.double_left+')|(%%'+this.double_right+')|('+this.left_equal+')|('+this.left_comment+')|('+this.left_delimiter+')|('+this.right_delimiter+'\n)|('+this.right_delimiter+')|(\n)') ;
  144. this.source = source;
  145. this.stag = null;
  146. this.lines = 0;
  147. };
  148. EJS.Scanner.to_text = function(input){
  149. if(input == null || input === undefined)
  150. return '';
  151. if(input instanceof Date)
  152. return input.toDateString();
  153. if(input.toString)
  154. return input.toString();
  155. return '';
  156. };
  157. EJS.Scanner.prototype = {
  158. scan: function(block) {
  159. scanline = this.scanline;
  160. regex = this.SplitRegexp;
  161. if (! this.source == '')
  162. {
  163. var source_split = rsplit(this.source, /\n/);
  164. for(var i=0; i<source_split.length; i++) {
  165. var item = source_split[i];
  166. this.scanline(item, regex, block);
  167. }
  168. }
  169. },
  170. scanline: function(line, regex, block) {
  171. this.lines++;
  172. var line_split = rsplit(line, regex);
  173. for(var i=0; i<line_split.length; i++) {
  174. var token = line_split[i];
  175. if (token != null) {
  176. try{
  177. block(token, this);
  178. }catch(e){
  179. throw {type: 'EJS.Scanner', line: this.lines};
  180. }
  181. }
  182. }
  183. }
  184. };
  185. EJS.Buffer = function(pre_cmd, post_cmd) {
  186. this.line = new Array();
  187. this.script = "";
  188. this.pre_cmd = pre_cmd;
  189. this.post_cmd = post_cmd;
  190. for (var i=0; i<this.pre_cmd.length; i++)
  191. {
  192. this.push(pre_cmd[i]);
  193. }
  194. };
  195. EJS.Buffer.prototype = {
  196. push: function(cmd) {
  197. this.line.push(cmd);
  198. },
  199. cr: function() {
  200. this.script = this.script + this.line.join('; ');
  201. this.line = new Array();
  202. this.script = this.script + "\n";
  203. },
  204. close: function() {
  205. if (this.line.length > 0)
  206. {
  207. for (var i=0; i<this.post_cmd.length; i++){
  208. this.push(pre_cmd[i]);
  209. }
  210. this.script = this.script + this.line.join('; ');
  211. line = null;
  212. }
  213. }
  214. };
  215. EJS.Compiler = function(source, left) {
  216. this.pre_cmd = ['var ___ViewO = [];'];
  217. this.post_cmd = new Array();
  218. this.source = ' ';
  219. if (source != null)
  220. {
  221. if (typeof source == 'string')
  222. {
  223. source = source.replace(/\r\n/g, "\n");
  224. source = source.replace(/\r/g, "\n");
  225. this.source = source;
  226. }else if (source.innerHTML){
  227. this.source = source.innerHTML;
  228. }
  229. if (typeof this.source != 'string'){
  230. this.source = "";
  231. }
  232. }
  233. left = left || '<';
  234. var right = '>';
  235. switch(left) {
  236. case '[':
  237. right = ']';
  238. break;
  239. case '<':
  240. break;
  241. default:
  242. throw left+' is not a supported deliminator';
  243. break;
  244. }
  245. this.scanner = new EJS.Scanner(this.source, left, right);
  246. this.out = '';
  247. };
  248. EJS.Compiler.prototype = {
  249. compile: function(options, name) {
  250. options = options || {};
  251. this.out = '';
  252. var put_cmd = "___ViewO.push(";
  253. var insert_cmd = put_cmd;
  254. var buff = new EJS.Buffer(this.pre_cmd, this.post_cmd);
  255. var content = '';
  256. var clean = function(content)
  257. {
  258. content = content.replace(/\\/g, '\\\\');
  259. content = content.replace(/\n/g, '\\n');
  260. content = content.replace(/"/g, '\\"');
  261. return content;
  262. };
  263. this.scanner.scan(function(token, scanner) {
  264. if (scanner.stag == null)
  265. {
  266. switch(token) {
  267. case '\n':
  268. content = content + "\n";
  269. buff.push(put_cmd + '"' + clean(content) + '");');
  270. buff.cr();
  271. content = '';
  272. break;
  273. case scanner.left_delimiter:
  274. case scanner.left_equal:
  275. case scanner.left_comment:
  276. scanner.stag = token;
  277. if (content.length > 0)
  278. {
  279. buff.push(put_cmd + '"' + clean(content) + '")');
  280. }
  281. content = '';
  282. break;
  283. case scanner.double_left:
  284. content = content + scanner.left_delimiter;
  285. break;
  286. default:
  287. content = content + token;
  288. break;
  289. }
  290. }
  291. else {
  292. switch(token) {
  293. case scanner.right_delimiter:
  294. switch(scanner.stag) {
  295. case scanner.left_delimiter:
  296. if (content[content.length - 1] == '\n')
  297. {
  298. content = chop(content);
  299. buff.push(content);
  300. buff.cr();
  301. }
  302. else {
  303. buff.push(content);
  304. }
  305. break;
  306. case scanner.left_equal:
  307. buff.push(insert_cmd + "(EJS.Scanner.to_text(" + content + ")))");
  308. break;
  309. }
  310. scanner.stag = null;
  311. content = '';
  312. break;
  313. case scanner.double_right:
  314. content = content + scanner.right_delimiter;
  315. break;
  316. default:
  317. content = content + token;
  318. break;
  319. }
  320. }
  321. });
  322. if (content.length > 0)
  323. {
  324. // Chould be content.dump in Ruby
  325. buff.push(put_cmd + '"' + clean(content) + '")');
  326. }
  327. buff.close();
  328. this.out = buff.script + ";";
  329. var to_be_evaled = '/*'+name+'*/this.process = function(_CONTEXT,_VIEW) { try { with(_VIEW) { with (_CONTEXT) {'+this.out+" return ___ViewO.join('');}}}catch(e){e.lineNumber=null;throw e;}};";
  330. try{
  331. eval(to_be_evaled);
  332. }catch(e){
  333. if(typeof JSLINT != 'undefined'){
  334. JSLINT(this.out);
  335. for(var i = 0; i < JSLINT.errors.length; i++){
  336. var error = JSLINT.errors[i];
  337. if(error.reason != "Unnecessary semicolon."){
  338. error.line++;
  339. var e = new Error();
  340. e.lineNumber = error.line;
  341. e.message = error.reason;
  342. if(options.view)
  343. e.fileName = options.view;
  344. throw e;
  345. }
  346. }
  347. }else{
  348. throw e;
  349. }
  350. }
  351. }
  352. };
  353. //type, cache, folder
  354. /**
  355. * Sets default options for all views
  356. * @param {Object} options Set view with the following options
  357. * <table class="options">
  358. <tbody><tr><th>Option</th><th>Default</th><th>Description</th></tr>
  359. <tr>
  360. <td>type</td>
  361. <td>'<'</td>
  362. <td>type of magic tags. Options are '&lt;' or '['
  363. </td>
  364. </tr>
  365. <tr>
  366. <td>cache</td>
  367. <td>true in production mode, false in other modes</td>
  368. <td>true to cache template.
  369. </td>
  370. </tr>
  371. </tbody></table>
  372. *
  373. */
  374. EJS.config = function(options){
  375. EJS.cache = options.cache != null ? options.cache : EJS.cache;
  376. EJS.type = options.type != null ? options.type : EJS.type;
  377. EJS.ext = options.ext != null ? options.ext : EJS.ext;
  378. var templates_directory = EJS.templates_directory || {}; //nice and private container
  379. EJS.templates_directory = templates_directory;
  380. EJS.get = function(path, cache){
  381. if(cache == false) return null;
  382. if(templates_directory[path]) return templates_directory[path];
  383. return null;
  384. };
  385. EJS.update = function(path, template) {
  386. if(path == null) return;
  387. templates_directory[path] = template ;
  388. };
  389. EJS.INVALID_PATH = -1;
  390. };
  391. EJS.config( {cache: true, type: '<', ext: '.ejs' } );
  392. /**
  393. * @constructor
  394. * By adding functions to EJS.Helpers.prototype, those functions will be available in the
  395. * views.
  396. * @init Creates a view helper. This function is called internally. You should never call it.
  397. * @param {Object} data The data passed to the view. Helpers have access to it through this._data
  398. */
  399. EJS.Helpers = function(data, extras){
  400. this._data = data;
  401. this._extras = extras;
  402. extend(this, extras );
  403. };
  404. /* @prototype*/
  405. EJS.Helpers.prototype = {
  406. /**
  407. * Renders a new view. If data is passed in, uses that to render the view.
  408. * @param {Object} options standard options passed to a new view.
  409. * @param {optional:Object} data
  410. * @return {String}
  411. */
  412. view: function(options, data, helpers){
  413. if(!helpers) helpers = this._extras
  414. if(!data) data = this._data;
  415. return new EJS(options).render(data, helpers);
  416. },
  417. /**
  418. * For a given value, tries to create a human representation.
  419. * @param {Object} input the value being converted.
  420. * @param {Object} null_text what text should be present if input == null or undefined, defaults to ''
  421. * @return {String}
  422. */
  423. to_text: function(input, null_text) {
  424. if(input == null || input === undefined) return null_text || '';
  425. if(input instanceof Date) return input.toDateString();
  426. if(input.toString) return input.toString().replace(/\n/g, '<br />').replace(/''/g, "'");
  427. return '';
  428. }
  429. };
  430. EJS.newRequest = function(){
  431. var factories = [function() { return new ActiveXObject("Msxml2.XMLHTTP"); },function() { return new XMLHttpRequest(); },function() { return new ActiveXObject("Microsoft.XMLHTTP"); }];
  432. for(var i = 0; i < factories.length; i++) {
  433. try {
  434. var request = factories[i]();
  435. if (request != null) return request;
  436. }
  437. catch(e) { continue;}
  438. }
  439. }
  440. EJS.request = function(path){
  441. var request = new EJS.newRequest()
  442. request.open("GET", path, false);
  443. try{request.send(null);}
  444. catch(e){return null;}
  445. if ( request.status == 404 || request.status == 2 ||(request.status == 0 && request.responseText == '') ) return null;
  446. return request.responseText
  447. }
  448. EJS.ajax_request = function(params){
  449. params.method = ( params.method ? params.method : 'GET')
  450. var request = new EJS.newRequest();
  451. request.onreadystatechange = function(){
  452. if(request.readyState == 4){
  453. if(request.status == 200){
  454. params.onComplete(request)
  455. }else
  456. {
  457. params.onComplete(request)
  458. }
  459. }
  460. }
  461. request.open(params.method, params.url)
  462. request.send(null)
  463. }
  464. })();