Add WCF.Template
authorTim Düsterhus <timwolla@arcor.de>
Sun, 24 Jul 2011 12:58:46 +0000 (14:58 +0200)
committerTim Düsterhus <timwolla@arcor.de>
Mon, 25 Jul 2011 13:32:39 +0000 (15:32 +0200)
wcfsetup/install/files/js/WCF.js

index c6a315a31c8c8b360356d0d905c12a2584654d10..65347111321430ea0091e0cbb3c2368035b92cd0 100644 (file)
@@ -18,7 +18,7 @@ $.extend(true, {
        /**\r
         * Escapes an ID to work with jQuery selectors.\r
         *\r
-        * @see         http://docs.jquery.com/Frequently_Asked_Questions#How_do_I_select_an_element_by_an_ID_that_has_characters_used_in_CSS_notation.3F\r
+        * @see         http://docs.jquery.com/Frequently_Asked_Questions#How_do_I_select_an_element_by_an_ID_that_has_characters_used_in_CSS_notation.3F\r
         * @param       string          id\r
         * @return      string\r
         */\r
@@ -1076,6 +1076,27 @@ WCF.Language = {
  * String utilities.\r
  */\r
 WCF.String = {\r
+       /**\r
+        * Escapes special HTML-characters within a string\r
+        * \r
+        * @param       string  string\r
+        * @return      string\r
+        */\r
+       escapeHTML: function (string) {\r
+               return string.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');\r
+       },\r
+       \r
+       /**\r
+        * Escapes a String to work with RegExp.\r
+        *\r
+        * @see         https://github.com/sstephenson/prototype/blob/master/src/prototype/lang/regexp.js#L25\r
+        * @param       string  string\r
+        * @return      string\r
+        */\r
+       escapeRegExp: function(string) {\r
+               return string.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');\r
+       },\r
+       \r
        /**\r
         * Makes a string's first character uppercase\r
         * \r
@@ -1130,6 +1151,159 @@ WCF.TabMenu = {
        }\r
 };\r
 \r
+/**\r
+ * Templates that may be fetched more than once with different variables. Based upon ideas from Prototype's template\r
+ * \r
+ * Usage:\r
+ *     var myTemplate = new WCF.Template('{$hello} World');\r
+ *     myTemplate.fetch({ hello: 'Hi' }); // Hi World\r
+ *     myTemplate.fetch({ hello: 'Hello' }); // Hello World\r
+ *     \r
+ *     my2ndTemplate = new WCF.Template('{@$html}{$html}');\r
+ *     my2ndTemplate.fetch({ html: '<b>Test</b>' }); // <b>Test</b>&lt;b&gt;Test&lt;/b&gt;\r
+ * \r
+ *     var my3rdTemplate = new WCF.Template('You can use {literal}{$variable}{/literal}-Tags here');\r
+ *     my3rdTemplate.fetch({ variable: 'Not shown' }); // You can use {$variable}-Tags here\r
+ * \r
+ * \r
+ * @param      template                template-content\r
+ * @see                https://github.com/sstephenson/prototype/blob/master/src/prototype/lang/template.js\r
+ */\r
+WCF.Template = function(template) { this.init(template); };\r
+WCF.Template.prototype = {\r
+       /**\r
+        * Template-content\r
+        * \r
+        * @var string\r
+        */\r
+       _template: '',\r
+       \r
+       /**\r
+        * Saved literal-tags\r
+        * \r
+        * @var WCF.Dictionary\r
+        */\r
+       _literals: new WCF.Dictionary(),\r
+       \r
+       /**\r
+        * Prepares template\r
+        * \r
+        * @param       $template               template-content\r
+        */\r
+       init: function($template) {\r
+               this._template = $template;\r
+               \r
+               // save literal-tags\r
+               this._template = this._template.replace(/\{literal\}(.*?)\{\/literal\}/g, $.proxy(function ($match) {\r
+                       // hopefully no one uses this string in one of his templates\r
+                       var id = '@@@@@@@@@@@'+Math.random()+'@@@@@@@@@@@';\r
+                       this._literals.add(id, $match.replace(/\{\/?literal\}/g, ''));\r
+                       \r
+                       return id;\r
+               }, this));\r
+       },\r
+       \r
+       /**\r
+        * Fetches the template with the given variables\r
+        *\r
+        * @param       $variables      variables to insert\r
+        * @return                      parsed template\r
+        */\r
+       fetch: function($variables) {\r
+               var $result = this._template;\r
+               \r
+               // insert them :)\r
+               for (var $key in $variables) {\r
+                       $result = $result.replace(new RegExp(WCF.String.escapeRegExp('{$'+$key+'}'), 'g'), WCF.String.escapeHTML($variables[$key]));\r
+                       $result = $result.replace(new RegExp(WCF.String.escapeRegExp('{@$'+$key+'}'), 'g'), $variables[$key]);\r
+               }\r
+               \r
+               // insert delimiter tags\r
+               $result = $result.replace('{ldelim}', '{').replace('{rdelim}', '}');\r
+               \r
+               // and re-insert saved literals\r
+               return this.insertLiterals($result);\r
+       },\r
+       \r
+       /**\r
+        * Inserts literals into given string\r
+        * \r
+        * @param       $template       string to insert into\r
+        * @return                      string with inserted literals\r
+        */\r
+       insertLiterals: function ($template) {\r
+               this._literals.each(function ($pair) {\r
+                       $template = $template.replace($pair.key, $pair.value);\r
+               });\r
+               \r
+               return $template;\r
+       },\r
+       \r
+       /**\r
+        * Compiles this template into javascript-code\r
+        * \r
+        * @return      WCF.Template.Compiled\r
+        */\r
+       compile: function () {\r
+               var $compiled = this._template;\r
+               \r
+               // escape \ and '\r
+               $compiled = $compiled.replace('\\', '\\\\').replace("'", "\\'");\r
+               \r
+               // parse our variable-tags\r
+               $compiled = $compiled.replace(/\{\$(.*?)\}/g, function ($match) {\r
+                       var $name = '$v.' + $match.substring(2, $match.length - 1);\r
+                       // trinary operator to maintain compatibility with uncompiled template\r
+                       // ($name) ? $name : '$match'\r
+                       // -> $v.muh ? $v.muh : '{$muh}'\r
+                       return "' + WCF.String.escapeHTML("+ $name + " ? " + $name + " : '" + $match + "') + '";\r
+               }).replace(/\{@\$(.*?)\}/g, function ($match) {\r
+                       var $name = '$v.' + $match.substring(3, $match.length - 1);\r
+                       // trinary operator to maintain compatibility with uncompiled template\r
+                       // ($name) ? $name : '$match'\r
+                       // -> $v.muh ? $v.muh : '{$muh}'\r
+                       return "' + ("+ $name + " ? " + $name + " : '" + $match + "') + '";\r
+               });\r
+               \r
+               // insert delimiter tags\r
+               $compiled = $compiled.replace('{ldelim}', '{').replace('{rdelim}', '}');\r
+               \r
+               // and re-insert saved literals\r
+               return new WCF.Template.Compiled("'" + this.insertLiterals($compiled) + "';");\r
+       }\r
+};\r
+\r
+/**\r
+ * Represents a compiled template\r
+ * \r
+ * @param      compiled                compiled template\r
+ */\r
+WCF.Template.Compiled = function(compiled) { this.init(compiled); };\r
+WCF.Template.Compiled.prototype = {\r
+       /**\r
+        * Compiled template\r
+        * \r
+        * @var string\r
+        */\r
+       _compiled: '',\r
+       \r
+       /**\r
+        * Initializes our compiled template\r
+        * \r
+        * @param       $compiled       compiled template\r
+        */\r
+       init: function($compiled) {\r
+               this._compiled = $compiled;\r
+       },\r
+       \r
+       /**\r
+        * @see WCF.Template.fetch\r
+        */\r
+       fetch: function($v) {\r
+               return eval(this._compiled);\r
+       }\r
+};\r
+\r
 /**\r
  * Toggles options.\r
  * \r