Develop and Download Open Source Software

Browse Subversion Repository

Contents of /js/ejs.js

Parent Directory Parent Directory | Revision Log Revision Log


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

Back to OSDN">Back to OSDN
ViewVC Help
Powered by ViewVC 1.1.26