/*--------------------------------------------------------------------------
* EJS - Embedded JavaScript, version 0.1.0
* Copyright (c) 2007 Edward Benson
* http://www.edwardbenson.com/projects/ejs
* ------------------------------------------------------------------------
*
* EJS is freely distributable under the terms of an MIT-style license.
*
* EJS is a client-side preprocessing engine written in and for JavaScript.
* If you have used PHP, ASP, JSP, or ERB then you get the idea: code embedded
* in <% // Code here %> tags will be executed, and code embedded in <%= .. %>
* tags will be evaluated and appended to the output.
*
* This is essentially a direct JavaScript port of Masatoshi Seki's erb.rb
* from the Ruby Core, though it contains a subset of ERB's functionality.
*
* Requirements:
* prototype.js
*
* Usage:
* // source should be either a string or a DOM node whose innerHTML
* // contains EJB source.
* var source = "<% var ejb="EJB"; %>
Hello, <%= ejb %>!
";
* var compiler = new EjsCompiler(source);
* compiler.compile();
* var output = eval(compiler.out);
* alert(output); // -> "Hello, EJB!
"
*
* For a demo: see demo.html
* For the license: see license.txt
*
*--------------------------------------------------------------------------*/
import("jsutils.*");
import("funhtml");
import("etherpad.log");
jimport("java.lang.System.out.println");
jimport("net.appjet.ajstdlib.execution.executeCodeInNewScope");
/* Make a split function like Ruby's: "abc".split(/b/) -> ['a', 'b', 'c'] */
function rsplit(x, regex) {
var item = x;
var result = regex.exec(item);
var retArr = new Array();
while (result != null)
{
var first_idx = result.index;
var last_idx = regex.lastIndex;
if ((first_idx) != 0)
{
var first_bit = item.substring(0,first_idx);
retArr.push(item.substring(0,first_idx));
item = item.slice(first_idx);
}
retArr.push(result[0]);
item = item.slice(result[0].length);
result = regex.exec(item);
}
if (! item == '')
{
retArr.push(item);
}
return retArr;
};
/* Chop is nice to have too */
function chop(x) {
return x.substr(0, x.length - 1);
}
/* Adaptation from the Scanner of erb.rb */
var EjsScanner = function(source, left, right) {
this.left_delimiter = left +'%'; //<%
this.right_delimiter = '%'+right; //>
this.double_left = left+'%%';
this.double_right = '%%'+right;
this.left_equal = left+'%=';
this.left_colon = left+'%:';
this.left_comment = left+'%#';
if(left=='[') {
this.SplitRegexp = /(\[%%)|(%%\])|(\[%:)|(\[%=)|(\[%#)|(\[%)|(%\]\n)|(%\])|(\n)/;
}
else {
this.SplitRegexp = new RegExp('('+this.double_left+')|(%%'+this.double_right+')|('+this.left_equal+')|('+this.left_colon+')|('+this.left_equal+')|('+this.left_comment+')|('+this.left_delimiter+')|('+this.right_delimiter+'\n)|('+this.right_delimiter+')|(\n)')
}
this.source = source;
this.stag = null;
this.lines = 0;
};
EjsView = function(data) {
this.data = data;
};
EjsView.prototype.partial = function(options, data){
if(!data) data = this.data;
return new EJS(options).render(data);
};
EjsScanner.to_text = function(input){
if(input == null || input === undefined)
return '';
if(input instanceof Date)
return input.toDateString();
if(input.toString)
return input.toString();
return '';
}
EjsScanner.prototype = {
/* For each line, scan! */
scan: function(block) {
scanline = this.scanline;
regex = this.SplitRegexp;
if (! this.source == '')
{
var source_split = rsplit(this.source, /\n/);
for(var i=0; i 0)
{
for (var i=0; i 0)
{
// Chould be content.dump in Ruby
buff.push(put_cmd + '"' + clean(content) + '"');
}
content = '';
break;
case scanner.double_left:
content = content + scanner.left_delimiter;
break;
default:
content = content + token;
break;
}
}
else {
switch(token) {
case scanner.right_delimiter:
switch(scanner.stag) {
case scanner.left_delimiter:
if (content[content.length - 1] == '\n')
{
content = chop(content);
buff.push(content);
buff.cr();
}
else {
buff.push(content);
}
break;
case scanner.left_equal:
buff.push(insert_cmd + "(EjsScanner.to_text(" + content + "))");
break;
case scanner.left_colon:
buff.push(insert_cmd + content);
break;
}
scanner.stag = null;
content = '';
break;
case scanner.double_right:
content = content + scanner.right_delimiter;
break;
default:
content = content + token;
break;
}
}
});
if (content.length > 0)
{
// Chould be content.dump in Ruby
buff.push(put_cmd + '"' + clean(content) + '"');
}
buff.close();
this.out = buff.script + ";";
var to_be_evaled = [
'var process = function(_CONTEXT,_VIEW) {',
' with(_VIEW) {',
' with (_CONTEXT) {',
this.out,
' return ejs_data;',
' }',
' }',
'};'
].join('');
// make funhtml.* available in parent scope.
var parentScope = {};
parentScope.EjsScanner = EjsScanner;
keys(funhtml).forEach(function(k) {
parentScope[k] = funhtml[k];
});
var ret = executeCodeInNewScope(
parentScope,
to_be_evaled,
(options.name || "template"),
1
);
this.process = ret.process;
}
}
//type, cache, folder
EJS = function( options ){
this.set_options(options);
if(options.url){
var template = EJS.get(options.url, this.cache);
if (template) return template;
if (template == EJS.INVALID_PATH) return null;
this.text = EJS.request(options.url);
if(this.text == null){
//EJS.update(options.url, this.INVALID_PATH);
throw 'There is no template at '+options.url;
}
this.name = options.url;
}else if(options.element)
{
if(typeof options.element == 'string'){
var name = options.element;
options.element = document.getElementById( options.element );
if(options.element == null) throw name+'does not exist!';
}
if(options.element.value){
this.text = options.element.value;
}else{
this.text = options.element.innerHTML;
}
this.name = options.element.id;
this.type = '[';
}
var template = new EjsCompiler(this.text, this.type);
template.compile(options);
EJS.update(this.name, this);
this.template = template;
};
EJS.config = function(options){
EJS.cache = options.cache != null ? options.cache : EJS.cache;
EJS.type = options.type != null ? options.type : EJS.type;
var templates_directory = {}; //nice and private container
EJS.get = function(path, cache){
if(cache == false) return null;
if(templates_directory[path]) return templates_directory[path];
return null;
};
EJS.update = function(path, template) {
if(path == null) return;
templates_directory[path] = template;
};
EJS.INVALID_PATH = -1;
};
EJS.config( {cache: true, type: '<' } );
EJS.prototype = {
render : function(object){
var v = new EjsView(object);
return this.template.process.call(v, object, v);
},
out : function(){
return this.template.out;
},
set_options : function(options){
this.type = options.type != null ? options.type : EJS.type;
this.cache = options.cache != null ? options.cache : EJS.cache;
this.text = options.text != null ? options.text : null;
this.name = options.name != null ? options.name : null;
},
// called without options, returns a function that takes the object
// called with options being a string, uses that as a url
// called with options as an object
update : function(element, options){
if(typeof element == 'string'){
element = document.getElementById(element);
}
if(options == null){
_template = this;
return function(object){
EJS.prototype.update.call(_template, element, object);
};
}
if(typeof options == 'string'){
params = {};
params.url = options;
_template = this;
params.onComplete = function(request){
var object = eval( request.responseText );
EJS.prototype.update.call(_template, element, object);
};
EJS.ajax_request(params);
}else
{
element.innerHTML = this.render(options);
}
}
};
EJS.newRequest = function(){
var factories = [function() { return new ActiveXObject("Msxml2.XMLHTTP"); },function() { return new XMLHttpRequest(); },function() { return new ActiveXObject("Microsoft.XMLHTTP"); }];
for(var i = 0; i < factories.length; i++) {
try {
var request = factories[i]();
if (request != null) return request;
}
catch(e) { continue;}
}
};
EJS.request = function(path){
var request = new EJS.newRequest();
request.open("GET", path, false);
try{request.send(null);}
catch(e){return null;}
if ( request.status == 404 || request.status == 2 ||(request.status == 0 && request.responseText == '') ) return null;
return request.responseText
};
EJS.ajax_request = function(params){
params.method = ( params.method ? params.method : 'GET');
var request = new EJS.newRequest();
request.onreadystatechange = function(){
if(request.readyState == 4){
if(request.status == 200){
params.onComplete(request);
}else
{
params.onComplete(request);
}
}
};
request.open(params.method, params.url);
request.send(null);
};
//}