baja/ord/ViewQuery.js

/**
 * @copyright 2015 Tridium, Inc. All Rights Reserved.
 * @author Gareth Johnson
 */

/**
 * Defines {@link baja.ViewQuery}.
 * @module baja/ord/ViewQuery
 */
define([ "bajaScript/sys",
    "bajaScript/baja/ord/OrdQuery" ],
  function (baja, OrdQuery) {

    "use strict";

    var subclass = baja.subclass,
      callSuper = baja.callSuper,
      strictArg = baja.strictArg;

    function parseViewQuery(body) {
      // Parse the view query (viewId?params)
      var res,
        view,
        regex,
        params;

      if (body) {
        res = /^([^?]*)(?:[?](.*))?$/.exec(body);
      }

      if (!res || (res && res.length < 2)) {
        throw new Error("Invalid view query: " + body);
      }

      // Note down the view query information onto the ORD target so it can be accessed
      view = {
        id: res[1] || "",
        params: {}
      };

      // If there are some view parameters then parse them
      if (res[2]) {
        regex = /([^=]+)=([^;]*);?/g;
        params = regex.exec(res[2]);

        while (params) {
          view.params[decodeURIComponent(params[1])] = decodeURIComponent(params[2]);
          params = regex.exec(res[2]);
        }
      }

      return view;
    }

    /**
     * `ViewQuery` defines user agent information.
     *
     * @class
     * @alias baja.ViewQuery
     * @extends OrdQuery
     *
     * @param {String|Object} body the view query body or an object literal for
     *                             the view id and parameters.
     * @param {String} [body.id] view id.
     * @param {Object} [body.params] view parameters (key value pairs in an Object Literal).
     */
    var ViewQuery = function ViewQuery(body) {
      // If an Object is passed in then attempt to get id and params from object
      if (body && typeof body === "object") {
        var params = body.params || {},
          i;

        this.$view = {
          id: body.id || "",
          params: params
        };

        // Build up a new view query body String
        i = 0;
        body = this.$view.id;

        baja.iterate(params, function (prop, propName) {
          if (i === 0) {
            body += "?";
          } else if (i > 0) {
            body += ";";
          }
          body += propName + "=" + prop;
          ++i;
        });
      } else {
        this.$view = parseViewQuery(body);
      }

      callSuper(ViewQuery, this, [ {
        scheme: baja.ViewScheme.DEFAULT,
        schemeName: "view",
        body: strictArg(body, String)
      } ]);
    };

    subclass(ViewQuery, OrdQuery);

    /**
     * Normalize the query and return true if modified.
     *
     * @private
     *
     * @param {baja.OrdQueryList} list
     * @param {Number} index
     *
     * @returns {Boolean}
     */
    ViewQuery.prototype.normalize = function (list, index) {
      var modified = false;
      if (list.get(index + 1) &&
        list.get(index + 1).getSchemeName().equals("view")) {

        //NCCB-20196: merge adjacent ViewQueries
        var first = list.get(index),
          firstParams = first.getParameters(),
          second = list.get(index + 1),
          secondParams = second.getParameters(),
          mergedViewId = second.getViewId() ? second.getViewId() : first.getViewId(), //use second if present
          mergeParams = {};

        Object.keys(firstParams).forEach(function (attr) {
          mergeParams[attr] = firstParams[attr];
        });

        Object.keys(secondParams).forEach(function (attr) {
          mergeParams[attr] = secondParams[attr];
        });

        list.set(index, new ViewQuery({
          id: mergedViewId,
          params: mergeParams
        }));

        // If the next scheme is the same as this one then
        list.remove(index + 1);
        modified = true;
      } else if (index < list.size() - 1) {
        // Ensure view query is always the last in the list
        list.remove(index);
        modified = true;
      }
      return modified;
    };

    /**
     * Return the view id (this could be view type spec or the name of a Px view).
     *
     * @returns {String}
     */
    ViewQuery.prototype.getViewId = function () {
      return this.$view.id;
    };

    /**
     * Return the view parameters as an object literal.
     *
     * Please note, this returns a defensive copy of the parameters.
     *
     * @returns {Object} the parameters.
     */
    ViewQuery.prototype.getParameters = function () {
      var o = {};
      baja.iterate(this.$view.params, function (prop, propName) {
        o[propName] = prop;
      });
      return o;
    };

    return ViewQuery;
  });