# Source: core/Global.js

    /*
     * Helma License Notice
     *
     * The contents of this file are subject to the Helma License
     * Version 2.0 (the "License"). You may not use this file except in
     * compliance with the License. A copy of the License is available at
     * http://adele.helma.org/download/helma/license.txt
     *
     * Copyright 1998-2005 Helma Software. All Rights Reserved.
     *
     * $RCSfile: Global.js,v $
     * $Author$
     * $Revision$
     * $Date$
     */

    /**
     * @fileoverview Adds useful global macros.
     * <br /><br />
     * To use this optional module, its repository needs to be added to the
     * application, for example by calling app.addRepository('modules/core/Global.js')
     */

    app.addRepository("modules/core/String.js");

    /**
     * write out a property contained in app.properties
     * @param Object containing the name of the property
     */
    function property_macro(param, name) {
        res.write(getProperty(name || param.name) || String.NULL);
        return;
    }

    /**
     * wrapper to output a string from within a skin
     * just to be able to use different encodings
     * @param Object containing the string as text property
     */
    function write_macro(param, text) {
        res.write(param.text || text || String.NULL);
        return;
    }

    /**
     * renders the current datetime
     * @param Object containing a formatting string as format property
     */
    function now_macro(param) {
        var d = new Date();
        if (param.format) {
            try {
                res.write(d.format(param.format));
            } catch (e) {
                res.write('<span title="' + e + '">[Invalid date format]</span>');
            }
        } else if (param.as == "timestamp") {
            res.write(d.getTime());
        } else {
            res.write(d);
        }
        return;
    }

    /**
     * renders a global skin
     */
    var skin_macro = function(param, name) {
        var skinName = name || param.name;
        if (skinName) {
            renderSkin(skinName, param);
        }
        return;
    }

    /**
     * Encodes a string for HTML output and inserts linebreak tags.
     *
     * Performs the following string manipulations:
     *  All line breaks (i.e. line feeds) are replaced with <br/> tags.
     *  All special characters are being replaced with their equivalent HTML entity.
     *  Existing markup tags are being encoded.
     *
     * @param {string} text
     *  The string to encode for HTML output.
     * @param {boolean} [encodeNewLine = true]
     *  If or if not to encode line breaks (i.e. line feeds).
     * @return {string}
     *  The encoded string.
     */
    function encode(text, encodeNewLine) {
      text = String(text);

      if (text === null || !text.length) return text;
      var buffer = [];
      if (typeof encodeNewLine === 'undefined') encodeNewLine = true;

      for (var i = 0, len = text.length; i < len; i += 1) {
        var char = text.charAt(i);

        switch (char) {
          case '<':
          buffer.push('&lt;');
          break;

          case '>':
          buffer.push('&gt;');
          break;

          case '&':
          buffer.push('&amp;');
          break;

          case '"':
          buffer.push('&quot;');
          break;

          case '\n':
          if (encodeNewLine) {
            buffer.push("<br/>");
          }
          buffer.push('\n');
          break;

          default:
          buffer.push(char);
        }
      }

      return buffer.join('');
    }

    /**
     * Encodes a string for XML output.
     *
     * Performs the following string manipulations:
     *  All special characters are being replaced with their equivalent HTML entity.
     *  Existing tags, single and double quotes, as well as ampersands are being encoded.
     *  Some invalid XML characters below '0x20' are removed
     *
     * @param {string} text
     *  The string to encode for XML output.
     * @return {string}
     *  The string encoded for XML output.
     */
    function encodeXml(text) {
      text = String(text);

      if (text === null || !text.length) return text;
      var buffer = [];

      for (var i = 0, len = text.length; i < len; i += 1) {
        var char = text.charAt(i);

        switch (char) {
          case '<':
          buffer.push('&lt;');
          break;

          case '>':
          buffer.push('&gt;');
          break;

          case '&':
          buffer.push('&amp;');
          break;

          case '"':
          buffer.push('&quot;');
          break;

          case '\'':
          buffer.push('&#39;');
          break;

          default:
          var charCode = text.charCodeAt(i);
          if (charCode < 0x20) {
            // sort out invalid XML characters below 0x20 - all but 0x9, 0xA and 0xD.
            // The trick is an adaption of java.lang.Character.isSpace().
            if (((((1 << 0x9) | (1 << 0xA) | (1 << 0xD)) >> charCode) & 1) !== 0) {
              buffer.push(char);
            }
          } else {
            buffer.push(char);
          }
        }
      }

      return buffer.join('');
    }

    /**
     * Encodes a string for HTML output, leaving linebreaks untouched.
     *
     * Performs the following string manipulations:
     *  Unlike encode, leaves linebreaks untouched. This is what you usually want to do for encoding form content (esp.
     *  with text input values).
     *  All special characters (i.e. non ASCII) are being replaced with their equivalent HTML entity.
     *  Existing markup tags are being encoded.
     *
     * @param {string} text
     *  The string to format for HTML output.
     * @return {string}
     *  The string formatted for HTML output.
     */
    var encodeForm = function(text) {
      text = String(text);

      if (text === null || !text.length) return text;

      return encode(text, false);
    };

    /**
     * Removes any markup tags contained in the passed string, and returns the modified string.
     *
     * @param {string} markup
     *  The text that is to be stripped of tags.
     * @return {string}
     *  The text with the tags stripped out.
     */
    var stripTags = function (markup) {
      if (!markup) return '';

      var chars = String(markup).split('');
      var charCounter = 0;
      var inTag = false;

      for (var i = 0, len = markup.length; i < len; i += 1) {
        if (chars[i] === '<') inTag = true;

        if (!inTag) {
          if (i > charCounter) {
            chars[charCounter] = chars[i];
          }

          charCounter += 1;
        }

        if (chars[i] === '>') {
          inTag = false;
        }
      }

      if (i > charCounter) {
        chars.length = charCounter;
        return chars.join('');
      }

      return markup;
    };