Add analytics
[bus.git] / busui / owa / modules / base / js / includes / jquery / jQote2 / external / jquery.tempest.js
blob:a/busui/owa/modules/base/js/includes/jquery/jQote2/external/jquery.tempest.js -> blob:b/busui/owa/modules/base/js/includes/jquery/jQote2/external/jquery.tempest.js
  // Tempest jQuery Templating Plugin
  // ================================
  //
  // Copyright (c) 2009 Nick Fitzgerald - http://fitzgeraldnick.com/
  //
  // Permission is hereby granted, free of charge, to any person obtaining a copy
  // of this software and associated documentation files (the "Software"), to deal
  // in the Software without restriction, including without limitation the rights
  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  // copies of the Software, and to permit persons to whom the Software is
  // furnished to do so, subject to the following conditions:
  //
  // The above copyright notice and this permission notice shall be included in
  // all copies or substantial portions of the Software.
  //
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  // THE SOFTWARE.
   
  // JSLint
  "use strict";
   
  (function ($) {
  // PRIVATE VARIABLES
  var templateCache = {},
   
  // TAG REGULAR EXPRESSIONS
  // Overwrite these if you want, but don't blame me when stuff goes wrong.
  OPEN_VAR_TAG = /\{\{[\s]*?/g,
  CLOSE_VAR_TAG = /[\s]*?\}\}/g,
  OPEN_BLOCK_TAG = /\{%[\s]*?/g,
  CLOSE_BLOCK_TAG = /[\s]*?%\}/g,
   
  // Probably, you don't want to mess with these, as they are built from
  // the ones above.
  VAR_TAG = new RegExp(OPEN_VAR_TAG.source +
  "[\\w\\-\\.]+?" +
  CLOSE_VAR_TAG.source, "g"),
   
  BLOCK_TAG = new RegExp(OPEN_BLOCK_TAG.source +
  "[\\w]+?(?:[ ]+?[\\w\\-\\.]*?)*?" +
  CLOSE_BLOCK_TAG.source, "g"),
   
  END_BLOCK_TAG = new RegExp(OPEN_BLOCK_TAG.source +
  "end[\\w]*?" +
  CLOSE_BLOCK_TAG.source, "g"),
   
  // All block tags stored in here. Tags have a couple things to work
  // with:
  //
  // * "args" property is set before render:
  // - Example: {% tag_type arg1 arg2 foo bar %}
  // * The "args" property would be set to
  // ["arg1", "arg2", "foo", "bar"]
  // in this example. The tag's render method could look them
  // up in the context object, or could do whatever it wanted
  // to do with it.
  // * "subNodes" property which is an array of all the nodes between
  // the block tag and it's corresponding {% end... %} tag
  // - NOTE: This property is only set for a block if it has the
  // "expectsEndTag" property set to true.
  // * Every block tag should have a "render" method that takes one
  // argument: a context object. It should return a string.
  BLOCK_NODES = {
  "for": {
  expectsEndTag: true,
  render: function (context) {
  var args = this.args,
  subNodes = this.subNodes,
  renderedNodes = [],
  i, itemName, arrName, arr, forContext, tmpObj;
   
  if (args.length === 3 && args[1] === "in") {
  itemName = args[0];
  arrName = args[2];
  arr = getValFromObj(arrName, context);
   
  for (i = 0; i < arr.length; i++) {
  tmpObj = {};
  tmpObj[itemName] = arr[i];
  tmpObj._index = i;
  forContext = $.extend(true, {}, context, tmpObj);
   
  $.each(subNodes, function (j, node) {
  renderedNodes.push(
  node.render(forContext)
  );
  });
  }
   
  return renderedNodes.join("");
  }
  else {
  throw new TemplateSyntaxError(
  "Bad for tag syntax. Use {% for <item> in <array> %}"
  );
  }
  }
  },
  "if": {
  expectsEndTag: true,
  render: function (context) {
  var rendered_nodes = [],
  subNodes = this.subNodes;
   
  // Check the truthiness of the argument.
  if (!!context[this.args[0]]) {
  $.each(subNodes, function (i, node) {
  rendered_nodes.push(node.render(context));
  });
  }
   
  return rendered_nodes.join("");
  }
  }
  },
   
  // Base text node object for prototyping.
  baseTextNode = {
  render: function (context) {
  return this.text || "";
  }
  },
   
  // Base variable node object for prototyping.
  baseVarNode = {
  render: function (context) {
  var val = context[this.name] === undefined ?
  "" :
  context[this.name];
  if (val === "" && this.name.search(/\./) !== -1) {
  return getValFromObj(this.name, context);
  }
  return cleanVal(val);
  }
  };
   
  // CUSTOM ERRORS
   
  function TemplateSyntaxError(message) {
  if (!(this instanceof TemplateSyntaxError)) {
  return new TemplateSyntaxError(message);
  }
  this.message = message;
  return this;
  }
  TemplateSyntaxError.prototype = new SyntaxError();
  TemplateSyntaxError.prototype.name = "TemplateSyntaxError";
   
  // PRIVATE FUNCTIONS
   
  // Some browsers don't return the grouped part of the RegExp with the array,
  // so we must accomodate them.
  var split = (function () {
  if ("abc".split(/(b)/).length === 3) {
  return function (str, delimiter) {
  return String.prototype
  .split
  .call(str, delimiter);
  };
  } else {
  return function (str, delimiter) {
  if (Object.prototype
  .toString
  .call(delimiter) === "[object RegExp]") {
  var regex = delimiter.ignoreCase ?
  new RegExp(delimiter.source, "gi") :
  new RegExp(delimiter.source, "g"),
  match,
  match_str = "",
  arr = [],
  i,
  len = str.length;
   
  for (i = 0; i < len; i++) {
  match_str += str.charAt(i);
  match = match_str.match(regex);
  if (match !== null && match.length > 0) {
  arr.push(match_str.replace(match[0], ""));
  arr.push(match[0]);
  match_str = "";
  }
  }
   
  if (match_str !== "") {
  arr.push(match_str);
  }
   
  return arr;
  } else {
  return String.prototype
  .split
  .call(str, delimiter);
  }
  };
  }
  }());
   
  function isBlockTag(token) {
  return token.search(BLOCK_TAG) !== -1;
  }
  function isEndTag(token) {
  return token.search(END_BLOCK_TAG) !== -1;
  }
  function isVarTag(token) {
  return token.search(VAR_TAG) !== -1;
  }
   
  function strip(str) {
  return str.replace(/^[\s]+/, "").replace(/[\s]+$/, "");
  }
   
  // Clean the passed value the best we can.
  function cleanVal(val) {
  if (val instanceof $) {
  return jQueryToString(val);
  } else if (val !== null && !isArray(val) && typeof(val) === "object") {
  if (typeof(val.toHTML) === "function") {
  return cleanVal(val.toHTML());
  } else {
  return val.toString();
  }
  } else {
  return val;
  }
  }
   
  // Traverse a path of an obj from a string representation,
  // for example "object.child.attr".
  function getValFromObj(str, obj) {
  var path = split(str, "."),
  val = obj[path[0]],
  i;
  for (i = 1; i < path.length; i++) {
  // Return an empty string if the lookup ever hits undefined.
  if (val !== undefined) {
  val = val[path[i]];
  } else {
  return "";
  }
  }
   
  // Make sure the last piece did not end up undefined.
  val = val === undefined ? "" : val;
  return cleanVal(val);
  }
   
  // Hack to get the HTML of a jquery object as a string.
  function jQueryToString(jq) {
  return $(document.createElement("div")).append(jq).html();
  }
   
  // Make a new copy of a given object.
  function makeObj(obj) {
  if (obj === undefined) {
  return obj;
  }
  var O = function () {};
  O.prototype = obj;
  return new O();
  }
   
  // Return an array of key/template pairs.
  function storedTemplates() {
  var cache = [];
  $.each(templateCache, function (key, templ) {
  cache.push([ key, templ ]);
  });
  return cache;
  }
   
  // Determine if the string is a key to a stored template or a
  // one-time-use template.
  function chooseTemplate(str) {
  return typeof templateCache[str] === "string" ?
  templateCache[str] :
  str;
  }
   
  // Return true if (and only if) an object is an array.
  function isArray(objToTest) {
  return Object.prototype
  .toString
  .apply(objToTest) === "[object Array]";
  }
   
  // Call a rendering function on arrays of objects or just a single
  // object seamlessly.
  function renderEach(data, f) {
  return isArray(data) ?
  $.each(data, f) :
  f(0, data);
  }
   
  // Split a template in to tokens which will eventually be converted to
  // nodes and then rendered.
  function tokenize(templ) {
  return (function (arr) {
  var tokens = [];
  for (i = 0; i < arr.length; i++) {
  (function (token) {
  return token === "" ?
  null :
  tokens.push(token);
  }(arr[i]));
  }
  return tokens;
  }(split(templ, new RegExp("(" + VAR_TAG.source + "|" +
  BLOCK_TAG.source + "|" +
  END_BLOCK_TAG.source + ")"))));
  }
   
  // "Lisp in C's clothing." - Douglas Crockford
  function cdr(arr) {
  return arr.slice(1);
  }
   
  // Array.push changes the original array in place and returns the new
  // length of the array rather than the the actual array itself. This
  // makes it unchainable, which is ridiculous.
  function append(item, list) {
  return list.concat([item]);
  }
   
  // Take a token and create a variable node from it.
  function makeVarNode(token) {
  var node = makeObj(baseVarNode);
  node.name = strip(token.replace(OPEN_VAR_TAG, "")
  .replace(CLOSE_VAR_TAG, ""));
  return node;
  }
   
  // Take a token and create a text node from it.
  function makeTextNode(token) {
  var node = makeObj(baseTextNode);
  node.text = token;
  return node;
  }
   
  // A recursive function that terminates either when all tokens have
  // been converted to nodes or an end-block tag is found.
  function makeNodes(tokens) {
  return (function (nodes, tokens) {
  var token = tokens[0];
  return tokens.length === 0 ?
  [nodes, [], true] :
  isEndTag(token) ?
  [nodes, cdr(tokens)] :
  isVarTag(token) ?
  arguments.callee(append(makeVarNode(token), nodes), cdr(tokens)) :
  isBlockTag(token) ?
  makeBlockNode(nodes, tokens, arguments.callee) :
  // Else assume it is a text node.
  arguments.callee(append(makeTextNode(token), nodes), cdr(tokens));