1 /* 2 * ***** BEGIN LICENSE BLOCK ***** 3 * Zimbra Collaboration Suite Web Client 4 * Copyright (C) 2008, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc. 5 * 6 * The contents of this file are subject to the Common Public Attribution License Version 1.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at: https://www.zimbra.com/license 9 * The License is based on the Mozilla Public License Version 1.1 but Sections 14 and 15 10 * have been added to cover use of software over a computer network and provide for limited attribution 11 * for the Original Developer. In addition, Exhibit A has been modified to be consistent with Exhibit B. 12 * 13 * Software distributed under the License is distributed on an "AS IS" basis, 14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. 15 * See the License for the specific language governing rights and limitations under the License. 16 * The Original Code is Zimbra Open Source Web Client. 17 * The Initial Developer of the Original Code is Zimbra, Inc. All rights to the Original Code were 18 * transferred by Zimbra, Inc. to Synacor, Inc. on September 14, 2015. 19 * 20 * All portions of the code are Copyright (C) 2008, 2009, 2010, 2011, 2013, 2014, 2016 Synacor, Inc. All Rights Reserved. 21 * ***** END LICENSE BLOCK ***** 22 */ 23 24 /** 25 * @author Andy Clark 26 * 27 * @private 28 */ 29 AjxTemplate.compile = function(pkg, authoritative, define, templateText) { 30 var name = AjxPackage.__package2path(pkg); 31 var lines = templateText != null ? templateText : AjxLoader.load(name).reponseText; 32 var buffer = [], offset = 0, first = true; 33 34 AjxTemplate.__RE_TEMPLATE.lastIndex = 0; 35 var m = AjxTemplate.__RE_TEMPLATE.exec(lines); 36 if (m) { 37 do { 38 var attrs = AjxTemplate.__parseAttrs(m[1]); 39 var body = m[2]; 40 if (attrs["xml:space"] != "preserve") { 41 // bug 47973: IE doesn't support String.prototype.trim 42 // NOTE: This was caused when the Java TemplateCompiler class was ported. 43 body = body.replace(AjxTemplate.__RE_GT_LINESEP_LT, "><").replace(/^\s+|\s+$/,""); 44 } 45 46 var packageId = pkg; 47 var templateId = attrs.id; 48 // NOTE: Template ids can be specified absolutely (i.e. 49 // overriding the default package) if the id starts 50 // with a forward slash (/), or if the id contains 51 // a hash mark (#). This allows a template file to 52 // override both types of template files (i.e. a 53 // single template per file or multiple templates 54 // per file). 55 if (templateId && (templateId.indexOf('#') != -1 || templateId.match(/^\//))) { 56 if (templateId.indexOf('#') == -1) { 57 templateId += "#"; 58 } 59 packageId = templateId.replace(/#.*$/, "").replace(/^\//,"").replace(/\//g,'.'); 60 templateId = templateId.replace(/^.*#/, ""); 61 } 62 var id = templateId ? packageId+"#"+templateId : packageId; 63 64 var func = AjxTemplate.__convertLines(body); 65 AjxTemplate.register(id, func, attrs, authoritative); 66 67 if (first && define) { 68 AjxPackage.define(packageId); 69 } 70 if (first) { 71 first = false; 72 AjxTemplate.register(packageId, func, attrs, authoritative); 73 } 74 } while (m = AjxTemplate.__RE_TEMPLATE.exec(lines)); 75 } 76 else { 77 if (define) { 78 AjxPackage.define(pkg); 79 } 80 var func = AjxTemplate.__convertLines(lines); 81 AjxTemplate.register(pkg, func, {}, authoritative); 82 } 83 }; 84 85 // template compilation utility 86 87 AjxTemplate.__RE_REPLACE = new RegExp([ "\\$\\{(.+?)\\}", "<\\$=(.+?)\\$>", "<\\$(.+?)\\$>" ].join("|"), "mg"); 88 AjxTemplate.__RE_TEMPLATE = new RegExp("<template(.*?)>(.*?)</template>", "mg"); 89 AjxTemplate.__RE_ATTR = new RegExp("\\s*(\\S+)\\s*=\\s*('[^']*'|\"[^\"]*\")", "mg"); 90 AjxTemplate.__RE_PARAM_PART = new RegExp("([^\\(\\.]+)(\\(.*?\\))?\\.?", "g"); 91 AjxTemplate.__RE_GT_LINESEP_LT = new RegExp([">", "\\s*\\n+\\s*", "<"].join(""), "mg"); 92 93 AjxTemplate.__convertLines = function(lines) { 94 var buffer = [], offset = 0; 95 96 buffer[offset++] = "\tvar _hasBuffer = Boolean(buffer);"; 97 buffer[offset++] = "\tdata = (typeof data == \"string\" ? { id: data } : data) || {};"; 98 buffer[offset++] = "\tbuffer = buffer || [];"; 99 buffer[offset++] = "\tvar _i = buffer.length;"; 100 buffer[offset++] = "\n"; 101 102 AjxTemplate.__RE_REPLACE.lastIndex = 0; 103 var m = AjxTemplate.__RE_REPLACE.exec(lines); 104 if (m) { 105 var head = 0; 106 do { 107 var tail = AjxTemplate.__RE_REPLACE.lastIndex - m[0].length; 108 if (head < tail) { 109 AjxTemplate.__printStringLines(buffer, lines.substring(head, tail)); 110 } 111 var param = m[1]; 112 var inline = m[2]; 113 if (param) { 114 offset = AjxTemplate.__printDataLine(buffer, param); 115 } 116 else if (inline) { 117 offset = AjxTemplate.__printBufferLine(buffer, inline); 118 } 119 else { 120 offset = AjxTemplate.__printLine(buffer, "\t", m[3].replace(/\n/g, "\n\t"), "\n"); 121 } 122 head = AjxTemplate.__RE_REPLACE.lastIndex; 123 } while (m = AjxTemplate.__RE_REPLACE.exec(lines)); 124 if (head < lines.length) { 125 offset = AjxTemplate.__printStringLines(buffer, lines.substring(head)); 126 } 127 } 128 else { 129 offset = AjxTemplate.__printStringLines(buffer, lines); 130 } 131 buffer[offset++] = "\n"; 132 133 buffer[offset++] = "\treturn _hasBuffer ? buffer.length : buffer.join(\"\");"; 134 135 return new Function("name,params,data,buffer",buffer.join("")); 136 }; 137 138 AjxTemplate.__parseAttrs = function(s) { 139 var attrs = {}, m; 140 AjxTemplate.__RE_ATTR.lastIndex = 0; 141 while (m = AjxTemplate.__RE_ATTR.exec(s)) { 142 var value = m[2]; 143 attrs[m[1]] = value.substring(1, value.length - 1); 144 } 145 return attrs; 146 }; 147 148 AjxTemplate.__printLine = function(buffer, s1 /* ..., sN */) { 149 var offset = buffer.length; 150 for (var i = 1; i < arguments.length; i++) { 151 buffer[offset++] = arguments[i]; 152 } 153 return offset; 154 }; 155 156 AjxTemplate.__printStringLines = function(buffer, s1 /* ..., sN */) { 157 var offset = buffer.length; 158 for (var j = 1; j < arguments.length; j++) { 159 var s = arguments[j]; 160 var lines = s.split("\n"); 161 for (var i = 0; i < lines.length; i++) { 162 var line = lines[i]; 163 offset = AjxTemplate.__printStringLine(buffer, line, i < lines.length - 1 ? "\n" : ""); 164 } 165 } 166 return offset; 167 }; 168 169 AjxTemplate.__printStringLine = function(buffer, s1 /* ..., sN */) { 170 var offset = buffer.length; 171 buffer[offset++] = "\tbuffer[_i++] = \""; 172 for (var i = 1; i < arguments.length; i++) { 173 offset = AjxTemplate.__printEscaped(buffer, arguments[i]); 174 } 175 buffer[offset++] = "\";"; 176 return offset; 177 }; 178 179 AjxTemplate.__printDataLine = function(buffer, s) { 180 var offset = buffer.length, m; 181 buffer[offset++] = "\tbuffer[_i++] = data"; 182 AjxTemplate.__RE_PARAM_PART.lastIndex = 0; 183 while (m = AjxTemplate.__RE_PARAM_PART.exec(s)) { 184 buffer[offset++] = "[\""; 185 buffer[offset++] = m[1]; 186 buffer[offset++] = "\"]"; 187 if (m[2] != null) { 188 buffer[offset++] = m[2]; 189 } 190 } 191 buffer[offset++] = ";"; 192 return offset; 193 }; 194 195 AjxTemplate.__printBufferLine = function(buffer, s1 /* ..., sN */) { 196 var offset = buffer.length; 197 buffer[offset++] = "\tbuffer[_i++] = "; 198 for (var i = 1; i < arguments.length; i++) { 199 buffer[offset++] = arguments[i]; 200 } 201 buffer[offset++] = ";"; 202 return offset; 203 }; 204 205 AjxTemplate.__printEscaped = function(buffer, s) { 206 var offset = buffer.length; 207 buffer[offset++] = s.replace(/\\/g,"\\\\").replace(/"/g,"\\\"").replace('\n',"\\n").replace('\r',"\\r").replace('\t',"\\t"); 208 return offset; 209 }; 210