<commit_before>'use strict';

angular.module('angularOauth', []).

  provider('Token', function() {

    /**
     * Given an flat object, returns a query string for use in URLs.  Note
     * that for a given object, the return value may be.
     *
     * @example
     *

         // returns 'color=red&size=large'
         objectToQueryString({color: 'red', size: 'large'})
     *

     *
     * @param {Object} obj A flat object containing keys for such a string.
     * @returns {string} A string suitable as a query string.
     */
    var objectToQueryString = function(obj) {
      var str = [];
      angular.forEach(obj, function(value, key) {
        str.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
      });
      return str.join("&");
    };

    // This response_type MUST be passed to the authorization endpoint using
    // the implicit grant flow (4.2.1 of RFC 6749).
    var RESPONSE_TYPE = 'token';

    // Create a special object for config fields that are required and missing.
    // If any config items still contain it when Token is used, raise an error.
    var REQUIRED_AND_MISSING = {};

    var config = {
      clientId: REQUIRED_AND_MISSING,
      redirectUri: REQUIRED_AND_MISSING,
      authorizationEndpoint: REQUIRED_AND_MISSING,
      localStorageName: 'accessToken',
      verifyFunc: REQUIRED_AND_MISSING,
      scopes: []
    };

    this.extendConfig = function(configExtension) {
      config = angular.extend(config, configExtension);
    };

    this.$get = function($q, $http, $window, $rootScope) {
      var requiredAndMissing = [];
      angular.forEach(config, function(value, key) {
        if (value === REQUIRED_AND_MISSING) {
          requiredAndMissing.push(key);
        }
      });

      if (requiredAndMissing.length) {
        throw new Error("TokenProvider is insufficiently configured.  Please " +
          "configure the following options using " +
          "TokenProvider.extendConfig: " + requiredAndMissing.join(", "))
      }

      if (!config.clientId) {
        throw new Error("clientId needs to be configured using TokenProvider.");
      }

      var getParams = function() {
        // TODO: Facebook uses comma-delimited scopes. This is not compliant with section 3.3 but perhaps support later.

        return {
          response_type: config.responseType || RESPONSE_TYPE,
          client_id: config.clientId,
          redirect_uri: config.redirectUri,
          scope: config.scopes.join(" ")
        }
      };

      return {
        // TODO: get/set might want to support expiration to reauthenticate
        // TODO: check for localStorage support and otherwise perhaps use other methods of storing data (e.g. cookie)

        /**
         * Returns the stored access token.
         *
         * @returns {string} The access token.
         */
        get: function() {
          return localStorage[config.localStorageName];
        },

        /**
         * Persist the access token so that it can be retrieved later by.
         *
         * @param accessToken
         */
        set: function(accessToken) {
          localStorage[config.localStorageName] = accessToken;
        },

        /**
         * Forgets the access token.
         */
        clear: function() {
          localStorage.removeItem(config.localStorageName);
        },

        /**
         * Verifies that the access token is was issued for the use of the current client.
         *
         * @param accessToken An access token received from the authorization server.
         * @returns {Promise} Promise that will be resolved when the authorization server has verified that the
         *  token is valid, and we've verified that the token is passed back has audience that matches our client
         *  ID (to prevent the Confused Deputy Problem).
         *
         *  If there's an error verifying the token, the promise is rejected with an object identifying the `name` error
         *  in the name member.  The `name` can be either:
         *
         *    - `invalid_audience`: The audience didn't match our client ID.
         *    - `error_response`: The server responded with an error, typically because the token was invalid.  In this
         *      case, the callback parameters to `error` callback on `$http` are available in the object (`data`,
         *      `status`, `headers`, `config`).
         */
        verifyAsync: function(accessToken) {
          return config.verifyFunc(config, accessToken);
        },

        /**
         * Verifies an access token asynchronously.
         *
         * @param extraParams Additional params to be appended to the query string of the request.
         * @param popupOptions Settings for the display of the popup.
         * @returns {Promise} Promise that will be resolved when the authorization server has verified that the
         *  token is valid, and we've verified that the token is passed back has audience that matches our client
         *  ID (to prevent the Confused Deputy Problem).
         *
         *  If there's an error verifying the token, the promise is rejected with an object identifying the `name` error
         *  in the name member.  The `name` can be either:
         *
         *    - `invalid_audience`: The audience didn't match our client ID.
         *    - `error_response`: The server responded with an error, typically because the token was invalid.  In this
         *      case, the callback parameters to `error` callback on `$http` are available in the object (`data`,
         *      `status`, `headers`, `config`).
         */
        getTokenByPopup: function(extraParams, popupOptions) {
          popupOptions = angular.extend({
            name: 'AuthPopup',
            openParams: {
              width: 650,
              height: 300,
              resizable: true,
              scrollbars: true,
              status: true
            }
          }, popupOptions);

          var deferred = $q.defer(),
            params = angular.extend(getParams(), extraParams),
            url = config.authorizationEndpoint + '?' + objectToQueryString(params),
            resolved = false;

          var formatPopupOptions = function(options) {
            var pairs = [];
            angular.forEach(options, function(value, key) {
              if (value || value === 0) {
                value = value === true ? 'yes' : value;
                pairs.push(key + '=' + value);
              }
            });
            return pairs.join(',');
          };

          var popup = window.open(url, popupOptions.name, formatPopupOptions(popupOptions.openParams));

          // TODO: binding occurs for each reauthentication, leading to leaks for long-running apps.

          angular.element($window).bind('message', function(event) {
            // Use JQuery originalEvent if present
            event = event.originalEvent || event;
            if (event.source == popup && event.origin == window.location.origin) {
              $rootScope.$apply(function() {
                if (event.data.access_token) {
                  deferred.resolve(event.data)
                } else {
                  deferred.reject(event.data)
                }
              })
            }
          });

          // TODO: reject deferred if the popup was closed without a message being delivered + maybe offer a timeout

          return deferred.promise;
        }
      }
    }
  }).

  /**
   * A controller for the redirect endpoint that inspects the URL redirected to by the authorization server and sends
   * it back to other windows using.
   */
  controller('CallbackCtrl', function($scope, $location) {

    /**
     * Parses an escaped url query string into key-value pairs.
     *
     * (Copied from Angular.js in the AngularJS project.)
     *
     * @returns Object.<(string|boolean)>
     */
    function parseKeyValue(/**string*/keyValue) {
      var obj = {}, key_value, key;
      angular.forEach((keyValue || "").split('&'), function(keyValue){
        if (keyValue) {
          key_value = keyValue.split('=');
          key = decodeURIComponent(key_value[0]);
          obj[key] = angular.isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
        }
      });
      return obj;
    }

    var queryString = $location.path().substring(1);  // preceding slash omitted
    var params = parseKeyValue(queryString);

    // TODO: The target origin should be set to an explicit origin.  Otherwise, a malicious site that can receive
    //       the token if it manages to change the location of the parent. (See:
    //       https://developer.mozilla.org/en/docs/DOM/window.postMessage#Security_concerns)

    window.opener.postMessage(params, "*");
    window.close();
  });
<commit_msg>Function to perform flow in same window<commit_after>'use strict';

angular.module('angularOauth', []).

  provider('Token', function() {

    /**
     * Given an flat object, returns a query string for use in URLs.  Note
     * that for a given object, the return value may be.
     *
     * @example
     *

         // returns 'color=red&size=large'
         objectToQueryString({color: 'red', size: 'large'})
     *

     *
     * @param {Object} obj A flat object containing keys for such a string.
     * @returns {string} A string suitable as a query string.
     */
    var objectToQueryString = function(obj) {
      var str = [];
      angular.forEach(obj, function(value, key) {
        str.push(encodeURIComponent(key) + "=" + encodeURIComponent(value));
      });
      return str.join("&");
    };

    // This response_type MUST be passed to the authorization endpoint using
    // the implicit grant flow (4.2.1 of RFC 6749).
    var RESPONSE_TYPE = 'token';

    // Create a special object for config fields that are required and missing.
    // If any config items still contain it when Token is used, raise an error.
    var REQUIRED_AND_MISSING = {};

    var config = {
      clientId: REQUIRED_AND_MISSING,
      redirectUri: REQUIRED_AND_MISSING,
      authorizationEndpoint: REQUIRED_AND_MISSING,
      localStorageName: 'accessToken',
      verifyFunc: REQUIRED_AND_MISSING,
      scopes: []
    };

    this.extendConfig = function(configExtension) {
      config = angular.extend(config, configExtension);
    };

    this.$get = function($q, $http, $window, $rootScope) {
      var requiredAndMissing = [];
      angular.forEach(config, function(value, key) {
        if (value === REQUIRED_AND_MISSING) {
          requiredAndMissing.push(key);
        }
      });

      if (requiredAndMissing.length) {
        throw new Error("TokenProvider is insufficiently configured.  Please " +
          "configure the following options using " +
          "TokenProvider.extendConfig: " + requiredAndMissing.join(", "))
      }

      if (!config.clientId) {
        throw new Error("clientId needs to be configured using TokenProvider.");
      }

      var getParams = function() {
        // TODO: Facebook uses comma-delimited scopes. This is not compliant with section 3.3 but perhaps support later.

        return {
          response_type: config.responseType || RESPONSE_TYPE,
          client_id: config.clientId,
          redirect_uri: config.redirectUri,
          scope: config.scopes.join(" ")
        }
      };

      var buildAuthorizationUrl = function(extraParams) {
        var params = angular.extend(getParams(), extraParams);
        return config.authorizationEndpoint + '?' + objectToQueryString(params);
      }

      return {
        // TODO: get/set might want to support expiration to reauthenticate
        // TODO: check for localStorage support and otherwise perhaps use other methods of storing data (e.g. cookie)

        /**
         * Returns the stored access token.
         *
         * @returns {string} The access token.
         */
        get: function() {
          return localStorage[config.localStorageName];
        },

        /**
         * Persist the access token so that it can be retrieved later by.
         *
         * @param accessToken
         */
        set: function(accessToken) {
          localStorage[config.localStorageName] = accessToken;
        },

        /**
         * Forgets the access token.
         */
        clear: function() {
          localStorage.removeItem(config.localStorageName);
        },

        /**
         * Verifies that the access token is was issued for the use of the current client.
         *
         * @param accessToken An access token received from the authorization server.
         * @returns {Promise} Promise that will be resolved when the authorization server has verified that the
         *  token is valid, and we've verified that the token is passed back has audience that matches our client
         *  ID (to prevent the Confused Deputy Problem).
         *
         *  If there's an error verifying the token, the promise is rejected with an object identifying the `name` error
         *  in the name member.  The `name` can be either:
         *
         *    - `invalid_audience`: The audience didn't match our client ID.
         *    - `error_response`: The server responded with an error, typically because the token was invalid.  In this
         *      case, the callback parameters to `error` callback on `$http` are available in the object (`data`,
         *      `status`, `headers`, `config`).
         */
        verifyAsync: function(accessToken) {
          return config.verifyFunc(config, accessToken);
        },

        /**
         * Verifies an access token asynchronously.
         *
         * @param extraParams Additional params to be appended to the query string of the request.
         * @param popupOptions Settings for the display of the popup.
         * @returns {Promise} Promise that will be resolved when the authorization server has verified that the
         *  token is valid, and we've verified that the token is passed back has audience that matches our client
         *  ID (to prevent the Confused Deputy Problem).
         *
         *  If there's an error verifying the token, the promise is rejected with an object identifying the `name` error
         *  in the name member.  The `name` can be either:
         *
         *    - `invalid_audience`: The audience didn't match our client ID.
         *    - `error_response`: The server responded with an error, typically because the token was invalid.  In this
         *      case, the callback parameters to `error` callback on `$http` are available in the object (`data`,
         *      `status`, `headers`, `config`).
         */
        getTokenByPopup: function(extraParams, popupOptions) {
          popupOptions = angular.extend({
            name: 'AuthPopup',
            openParams: {
              width: 650,
              height: 300,
              resizable: true,
              scrollbars: true,
              status: true
            }
          }, popupOptions);

          var deferred = $q.defer(),
            url = buildAuthorizationUrl(extraParams),
            resolved = false;

          var formatPopupOptions = function(options) {
            var pairs = [];
            angular.forEach(options, function(value, key) {
              if (value || value === 0) {
                value = value === true ? 'yes' : value;
                pairs.push(key + '=' + value);
              }
            });
            return pairs.join(',');
          };

          var popup = window.open(url, popupOptions.name, formatPopupOptions(popupOptions.openParams));

          // TODO: binding occurs for each reauthentication, leading to leaks for long-running apps.

          angular.element($window).bind('message', function(event) {
            // Use JQuery originalEvent if present
            event = event.originalEvent || event;
            if (event.source == popup && event.origin == window.location.origin) {
              $rootScope.$apply(function() {
                if (event.data.access_token) {
                  deferred.resolve(event.data)
                } else {
                  deferred.reject(event.data)
                }
              })
            }
          });

          // TODO: reject deferred if the popup was closed without a message being delivered + maybe offer a timeout

          return deferred.promise;
        },
        getTokenInSameWindow: function(extraParams) {
          var url = buildAuthorizationUrl(extraParams);
          $window.location.href = url;
        }
      }
    }
  }).

  /**
   * A controller for the redirect endpoint that inspects the URL redirected to by the authorization server and sends
   * it back to other windows using.
   */
  controller('CallbackCtrl', function($scope, $location) {

    /**
     * Parses an escaped url query string into key-value pairs.
     *
     * (Copied from Angular.js in the AngularJS project.)
     *
     * @returns Object.<(string|boolean)>
     */
    function parseKeyValue(/**string*/keyValue) {
      var obj = {}, key_value, key;
      angular.forEach((keyValue || "").split('&'), function(keyValue){
        if (keyValue) {
          key_value = keyValue.split('=');
          key = decodeURIComponent(key_value[0]);
          obj[key] = angular.isDefined(key_value[1]) ? decodeURIComponent(key_value[1]) : true;
        }
      });
      return obj;
    }

    var queryString = $location.path().substring(1);  // preceding slash omitted
    var params = parseKeyValue(queryString);

    // TODO: The target origin should be set to an explicit origin.  Otherwise, a malicious site that can receive
    //       the token if it manages to change the location of the parent. (See:
    //       https://developer.mozilla.org/en/docs/DOM/window.postMessage#Security_concerns)

    window.opener.postMessage(params, "*");
    window.close();
  });
<|endoftext|>


<commit_before>module.exports = function(options) {
  var Browser = require('zombie');
  var chai = require('chai');
  var CSSTest = require('css-tester')(chai);
  var expect = chai.expect;
  var execFile = require('child_process').execFile;
  var os = require('os');
  var _ = require('lodash');

  options = _.defaults(options, {
    hostname: os.hostname(),
    domains: {},
    debug: false
  });

  if (!options.domain && options.domains[options.hostname]) {
    options.domain = options.domains[options.hostname];
  }

  if (!options.domain) {
    throw new Error('you have to provide a (base-)domain for the world. No key "'+options.hostname+'" found for a domain in '+require('stringify-object')(options.domains, { indent: '  '}));
  }

  return function World(callback) {
    var that = this;

    this.util = require('./zombie-utils')(that);

    if (this.init) {
      this.init.call(this);
    }

    this.browser = new Browser({
      site: 'http://'+options.domain,
      debug: options.debug,
      headers: {
        'X-Environment-In-Tests': 'from-zombie'
      },
      maxWait: 7
    });

    _.each(options.cookies || {}, function(cookie) {
      that.browser.cookies.set(_.defaults(cookie, { domain: options.domain}));
    });

    this.debug = {};
    this.debug.log = function() {
      /* globals console */
      (console.log).apply(this, arguments);
    };

    this.css = function(selector) {
      if (!that.browser.window.jQuery) {
        throw new Error('cannot css() because jQuery is not defined');
      }

      return new CSSTest(that.browser.window.jQuery, selector);
    };

    this.visit = function(url, callback) {
      that.browser.visit(url, function(error) {
        /*
        if (error && error.filename === 'http://www.youtube.com/embed/tW2WGr--jy4:script') {
          that.debug.log('youtube error ignored');

          // just continue
          that.browser.wait(function() {
            callback.call(that, that.browser);
          });
        } else
        */
        if (error) {
          throw error;
        } else {
          callback.call(that, that.browser);
        }
      });
    };

    this.waitForjQuery = function(callback) {
      if (!that.browser.window) {
        throw new Error('cannot wait for jQuery, that.browser.window is not defined. Did you forget to visit a page before waiting for jQuery?');
      }

      that.browser.wait(
        function() {
          return that.browser.window.jQuery !== undefined;
        },
        function() {
          if (!that.browser.window) {
            throw new Error('cannot wait for jQuery, that.browser.window is not defined (after waiting)');
          }

          if (!that.browser.window.jQuery) {
            throw new Error('timed out while waiting for jQuery');
          }

          that.registerjQuery();
          callback.call(that, that.browser.window.jQuery);
        }
      );
    };

    this.requirejQuery = function(callback) {
      //that.browser.evaluate("window.require(['jquery']);");
      this.waitForjQuery(callback);
    };

    // should be called if for example a button has changed the site
    this.pageHasChanged = function(callback) {
      that.registerjQuery();
      callback.call(that);
    };

    this.getjQuery = function() {
      return that.browser.window.jQuery;
    };

    this.koContext = function($element) {
      var ko = that.browser.window.require('knockout');
      var context = ko.contextFor($element.jquery ? $element.get(0) : $element);

      expect(context, 'context from element: '+$element).to.be.ok;

      return context;
    };

    this.koData = function($element) {
      return that.koContext($element)['$data'];
    };

    this.registerjQuery = function() {
      if (that.browser.window.jQuery) {
        that.jQuery = that.browser.window.jQuery;

        that.ajaxRequests = [];

        that.jQuery(that.browser.document).ajaxSend( function(event, jqXHR, ajaxOptions) {
          that.ajaxRequests.push(ajaxOptions);
        });
      }
    };

    this.visitPage = function(path, callback) {
      return that.visit(path, function() {
        that.pageHasChanged(function() {
          callback.call(that, that.browser);
        });
      });
    };

    this.getLastAjaxRequest = function() {
      expect(that.ajaxRequests, 'list of made ajax Requests').to.be.ok.and.not.to.have.length(0);

      var lastRequest = this.ajaxRequests[this.ajaxRequests.length - 1];

      return lastRequest;
    };

    // expects something for the last ajax request done
    // .data an object, .url a string
    this.expectAjaxRequest = function(exp) {
      var lastRequest = this.getLastAjaxRequest();

      expect(lastRequest, 'lastAjaxRequest').to.have.property('url', exp.url);
      expect(lastRequest, 'lastAjaxRequest').to.have.property('data');
      expect(JSON.parse(lastRequest.data), 'lastAjaxRequest.data').to.be.eql(exp.data);
    };

    this.executeDQL = function(dql, parameters, callback, cucumberCallback) {
      execFile(options.cli, ["db:dql", dql, JSON.stringify(parameters)], function(error, stdout, stderr) {
        if (error) {
          console.log(stderr, stdout);
          expect(error).to.be.undefined;
        }

        var result = JSON.parse(stdout);

        if (cucumberCallback) {
          try {
            callback.call(that, result, dql);

            cucumberCallback();
          } catch (exc) {
            cucumberCallback.fail(exc);
          }
        } else {
          callback.call(that, result, dql);
        }
      });
    };

    this.retrieveMailSpool = function(callback, cucumberCallback) {
      execFile(options.cli, ["mail:spool"], function(error, stdout, stderr) {
        if (error) {
          that.debug.log(stderr, stdout);
          throw error;
        }

        var result = JSON.parse(stdout);

        if (cucumberCallback) {
          try {
            callback.call(that, result);

            cucumberCallback();
          } catch (exc) {
            cucumberCallback.fail(exc);
          }
        } else {
          callback.call(that, result);
        }
      });
    };

    this.clearMailSpool = function(callback) {
      execFile(options.cli, ["mail:spool", "--clear"], function(error, stdout, stderr) {
        if (error) {
          that.debug.log(stderr, stdout);
          throw error;
        }

        callback.call(that);
      });
    };

    this.loadFixture = function(name, callback) {
      execFile(options.cli, ["db:fixture", name], function(error, stdout, stderr) {
        if (error) {
          that.debug.log(stderr, stdout);
          throw error;
        }

        callback.call(that);
      });
    };

    this.loadFixtureParts = function(partsText, callback) {
      if (options.debug) {
        that.debug.log('loading fixture-parts:');
        that.debug.log(partsText);
      }

      partsText = partsText.replace(/\r?\n/g, '_');

      execFile(options.cli, ["db:fixture-parts", partsText, '--divider=_'], function(error, stdout, stderr) {
        if (error) {
          that.debug.log(stderr, stdout);
          throw error;
        }

        if (options.debug) {
          that.debug.log('fixture parts debug:');
          that.debug.log(stdout);
        }

        callback.call(that);
      });
    };

    callback(); // tell Cucumber we're finished and to use 'this' as the world instance
  };
};
<commit_msg>Update create-world.js<commit_after>module.exports = function(options) {
  var Browser = require('zombie');
  var chai = require('chai');
  var CSSTest = require('css-tester')(chai);
  var expect = chai.expect;
  var execFile = require('child_process').execFile;
  var os = require('os');
  var _ = require('lodash');

  options = _.defaults(options, {
    hostname: os.hostname(),
    domains: {},
    debug: false
  });

  if (!options.domain && options.domains[options.hostname]) {
    options.domain = options.domains[options.hostname];
  }

  if (!options.domain) {
    throw new Error('you have to provide a (base-)domain for the world. No key "'+options.hostname+'" found for a domain in '+require('stringify-object')(options.domains, { indent: '  '}));
  }

  return function World(callback) {
    var that = this;

    this.util = require('./zombie-utils')(that);

    if (this.init) {
      this.init.call(this);
    }

    this.browser = new Browser({
      site: 'http://'+options.domain,
      debug: options.debug,
      headers: {
        'X-Environment-In-Tests': 'from-zombie'
      },
      maxWait: 7
    });

    _.each(options.cookies || {}, function(cookie) {
      that.browser.cookies.set(_.defaults(cookie, { domain: options.domain}));
    });

    this.debug = {};
    this.debug.log = function() {
      /* globals console */
      (console.log).apply(this, arguments);
    };

    this.css = function(selector) {
      if (!that.browser.window.jQuery) {
        throw new Error('cannot css() because jQuery is not defined. Maybe you used this.css and forgot withCSS parameter after callback?');
      }

      return new CSSTest(that.browser.window.jQuery, selector);
    };

    this.visit = function(url, callback) {
      that.browser.visit(url, function(error) {
        /*
        if (error && error.filename === 'http://www.youtube.com/embed/tW2WGr--jy4:script') {
          that.debug.log('youtube error ignored');

          // just continue
          that.browser.wait(function() {
            callback.call(that, that.browser);
          });
        } else
        */
        if (error) {
          throw error;
        } else {
          callback.call(that, that.browser);
        }
      });
    };

    this.waitForjQuery = function(callback) {
      if (!that.browser.window) {
        throw new Error('cannot wait for jQuery, that.browser.window is not defined. Did you forget to visit a page before waiting for jQuery?');
      }

      that.browser.wait(
        function() {
          return that.browser.window.jQuery !== undefined;
        },
        function() {
          if (!that.browser.window) {
            throw new Error('cannot wait for jQuery, that.browser.window is not defined (after waiting)');
          }

          if (!that.browser.window.jQuery) {
            throw new Error('timed out while waiting for jQuery');
          }

          that.registerjQuery();
          callback.call(that, that.browser.window.jQuery);
        }
      );
    };

    this.requirejQuery = function(callback) {
      //that.browser.evaluate("window.require(['jquery']);");
      this.waitForjQuery(callback);
    };

    // should be called if for example a button has changed the site
    this.pageHasChanged = function(callback) {
      that.registerjQuery();
      callback.call(that);
    };

    this.getjQuery = function() {
      return that.browser.window.jQuery;
    };

    this.koContext = function($element) {
      var ko = that.browser.window.require('knockout');
      var context = ko.contextFor($element.jquery ? $element.get(0) : $element);

      expect(context, 'context from element: '+$element).to.be.ok;

      return context;
    };

    this.koData = function($element) {
      return that.koContext($element)['$data'];
    };

    this.registerjQuery = function() {
      if (that.browser.window.jQuery) {
        that.jQuery = that.browser.window.jQuery;

        that.ajaxRequests = [];

        that.jQuery(that.browser.document).ajaxSend( function(event, jqXHR, ajaxOptions) {
          that.ajaxRequests.push(ajaxOptions);
        });
      }
    };

    this.visitPage = function(path, callback) {
      return that.visit(path, function() {
        that.pageHasChanged(function() {
          callback.call(that, that.browser);
        });
      });
    };

    this.getLastAjaxRequest = function() {
      expect(that.ajaxRequests, 'list of made ajax Requests').to.be.ok.and.not.to.have.length(0);

      var lastRequest = this.ajaxRequests[this.ajaxRequests.length - 1];

      return lastRequest;
    };

    // expects something for the last ajax request done
    // .data an object, .url a string
    this.expectAjaxRequest = function(exp) {
      var lastRequest = this.getLastAjaxRequest();

      expect(lastRequest, 'lastAjaxRequest').to.have.property('url', exp.url);
      expect(lastRequest, 'lastAjaxRequest').to.have.property('data');
      expect(JSON.parse(lastRequest.data), 'lastAjaxRequest.data').to.be.eql(exp.data);
    };

    this.executeDQL = function(dql, parameters, callback, cucumberCallback) {
      execFile(options.cli, ["db:dql", dql, JSON.stringify(parameters)], function(error, stdout, stderr) {
        if (error) {
          console.log(stderr, stdout);
          expect(error).to.be.undefined;
        }

        var result = JSON.parse(stdout);

        if (cucumberCallback) {
          try {
            callback.call(that, result, dql);

            cucumberCallback();
          } catch (exc) {
            cucumberCallback.fail(exc);
          }
        } else {
          callback.call(that, result, dql);
        }
      });
    };

    this.retrieveMailSpool = function(callback, cucumberCallback) {
      execFile(options.cli, ["mail:spool"], function(error, stdout, stderr) {
        if (error) {
          that.debug.log(stderr, stdout);
          throw error;
        }

        var result = JSON.parse(stdout);

        if (cucumberCallback) {
          try {
            callback.call(that, result);

            cucumberCallback();
          } catch (exc) {
            cucumberCallback.fail(exc);
          }
        } else {
          callback.call(that, result);
        }
      });
    };

    this.clearMailSpool = function(callback) {
      execFile(options.cli, ["mail:spool", "--clear"], function(error, stdout, stderr) {
        if (error) {
          that.debug.log(stderr, stdout);
          throw error;
        }

        callback.call(that);
      });
    };

    this.loadFixture = function(name, callback) {
      execFile(options.cli, ["db:fixture", name], function(error, stdout, stderr) {
        if (error) {
          that.debug.log(stderr, stdout);
          throw error;
        }

        callback.call(that);
      });
    };

    this.loadFixtureParts = function(partsText, callback) {
      if (options.debug) {
        that.debug.log('loading fixture-parts:');
        that.debug.log(partsText);
      }

      partsText = partsText.replace(/\r?\n/g, '_');

      execFile(options.cli, ["db:fixture-parts", partsText, '--divider=_'], function(error, stdout, stderr) {
        if (error) {
          that.debug.log(stderr, stdout);
          throw error;
        }

        if (options.debug) {
          that.debug.log('fixture parts debug:');
          that.debug.log(stdout);
        }

        callback.call(that);
      });
    };

    callback(); // tell Cucumber we're finished and to use 'this' as the world instance
  };
};
<|endoftext|>


<commit_before>/**
 * The `proact-dsl` module provides DSL for creating and managing different ProAct objects.
 *
 *
 * @module proact-dsl
 * @main proact-dsl
 */

/**
 *

 *  Constructs a `ProAct.Registry`.
 *  It is used to store/create objects that can be referenced or configured using the {{#crossLink "ProAct.DSL"}}{{/crossLink}}.
 *

 *

 *  `ProAct.Registry` is part of the `proact-dsl` module of ProAct.js.
 *

 *
 * @class ProAct.Registry
 * @constructor
 */
function Registry () {
  this.providers = {};
}
ProAct.Registry = P.R = Registry;

ProAct.Registry.prototype = rProto = {

  /**
   * Reference to the constructor of this object.
   *
   * @memberof ProAct.Registry
   * @instance
   * @constant
   * @default ProAct.Registry
   */
  constructor: ProAct.Registry,

  /**
   * Registers a {@link ProAct.Registry.Provider} for the passed namespace in the registry.
   *
   * @memberof ProAct.Registry
   * @instance
   * @method register
   * @param {String} namespace
   *      The namespace to register the provider in.
   * @param {ProAct.Registry.Provider} provider
   *      The {@link ProAct.Registry.Provider} to register.
   * @return {ProAct.Registers}
   *      this
   * @throws {Error}
   *      If a {@link ProAct.Registry.Provider} is already registered for the passed namespace.
   * @see {@link ProAct.Registry.Provider}
   */
  register: function (namespace, provider) {
    if (this.providers[namespace]) {
      throw new Error(namespace + 'is already registered in this registry.');
    }
    this.providers[namespace] = provider;
    if (provider.registered) {
      provider.registered(this);
    }
    return this;
  },

  /**
   * Retrieves the right {@link ProAct.Registry.Provider} using the name of stored
   * in this ProAct.Registry object, or the name of an object to be stored
   *
   * @memberof ProAct.Registry
   * @instance
   * @method getProviderByName
   * @param {String} name
   *      The name of storable object.
   *

   *        It must be in the format '{namespace}:{key}'.
   *

   *

   *        Here the namespace is the namespace the {@link ProAct.Registry.Provider} manages.
   *

   * @return {Array}
   *      The first element in the result is the {@link ProAct.Registry.Provider} or undefined if not found.
   *

   *        The second one is the key at which an object is stored or will be stored in the provider.
   *

   *

   *        The third element is an array with options for storing/creating an object passed to the provider using
   *        the name string.
   *

   * @see {@link ProAct.Registry.Provider}
   */
  getProviderByName: function (name) {
    var parts = name.split(':');

    return [this.providers[parts[0]], parts[1], parts.slice(2)];
  },

  /**
   * Configures an object to be stored using {{#crossLink "ProAct.DSL"}}{{/crossLink}} passed through options and DSL arguments.
   *

   *  Example usage:
   *

   *

   *  A {@link ProAct.Stream} is passed to the registry for setup with DSL data.
   *

   *

   *  The data passed through the options parameter is
   *

   *    '<<(s:foo)|map(-)|filter($1)'
   *

   *

   *

   *  And the arguments for the DSL machine passed through the args parameter are
   *

   *    [function (v) {
   *      return v % 2 === 0;
   *    }]
   *

   *

   *

   *  This means that a {@link ProAct.Stream} stored in this registry by the key 'foo' should be set
   *  as a source to the passed as the object parameter simple {@link ProAct.Stream}.
   *

   *

   *  It also means that for every value comming in the object parameter's stream there should be mapping of negativity and
   *  only even values should be passed to it.
   *

   *

   *  So if we trigger in the 'foo' stream the value of 4 in our stream we will get -4, and if we trigger 5, we won't get anything.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method setup
   * @param {Object} object
   *      The object to setup.
   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object.
   * @param {Array} args
   *      Arguments to be used by the {@link ProAct.DSL#run} method while configuring the passed object.
   * @return {Object}
   *      Ready to strore object.
   * @see {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   * @see {@link ProAct.DSL#run}
   */
  setup: function (object, options, args) {
    return dsl.run.apply(null, [object, options, this].concat(args));
  },

  /**
   * Creates a new object and stores it in this registry, using the right provider for the creation
   * and configuring it using the DSL passed through the options parameter.
   *

   *  {@link ProAct.Registry#getProviderByName} is used to locate the right provider to create the object with.
   *

   *

   *  {@link ProAct.Registry#setup} is used to setup the newly created object using the {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   *

   *

   *  The idea of this method is to create and configure {@link ProAct.Actor} objects.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method make
   * @param {String} name
   *      Name of the object to create and store.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object to be created.
   * @param [...]
   *      Arguments to be used by the {@link ProAct.DSL#run} method while configuring the newly created object.
   * @return {Object}
   *      The newly created, stored and configured object, or null if there was no {@link ProAct.Registry.Provider} register for its type.
   * @see {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   * @see {@link ProAct.Registry#getProviderByName}
   * @see {@link ProAct.Registry#setup}
   * @see {@link ProAct.Actor}
   */
  make: function (name, options) {
    var args = slice.call(arguments, 2),
        p = this.getProviderByName(name),
        actor;

    if (p[0]) {
      actor = p[0].make.apply(p[0], [p[1], p[2]].concat(args));
      return this.setup(actor, options, args);
    }
    return null;
  },

  /**
   * Stores an object  in this registry, using the right provider to configure it using the DSL passed through the options parameter.
   *

   *  {@link ProAct.Registry#getProviderByName} is used to locate the right provider to store the object to.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method store
   * @param {String} name
   *      Name of the object to store.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @param {Object} object
   *      The object to store.
   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object to be stored (optional).
   * @param [...]
   *      Arguments to be used by the {@link ProAct.DSL#run} method while configuring the object.
   * @return {Object}
   *      The stored and configured object, or null if there was no {@link ProAct.Registry.Provider} register for its type.
   * @see {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   * @see {@link ProAct.Registry#getProviderByName}
   */
  store: function (name, object, options) {
    var args = slice.call(arguments, 2),
        p = this.getProviderByName(name);

    if (p[0]) {
      return p[0].store.apply(p[0], [p[1], object, p[2]].concat(args));
    }
    return null;
  },

  /**
   * Retrieves an object, stored this registry.
   *

   *  {@link ProAct.Registry#getProviderByName} is used to locate the right provider to retrieve the object from.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method get
   * @param {String} name
   *      Name of the object to find.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @return {Object}
   *      The stored object, or null if there was no {@link ProAct.Registry.Provider} register for its type or no object registered for the passed name.
   * @see {@link ProAct.Registry#getProviderByName}
   */
  get: function (name) {
    var p = this.getProviderByName(name);

    if (p[0]) {
      return p[0].get(p[1]);
    }
    return null;
  },

  /**
   * Helper method for transforming an array of keys of stored items in this ProAct.Registry to an array of the actual items.
   *

   *  Mainly used by the {{#crossLink "ProAct.DSL"}}{{/crossLink}} logic.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method toObjectArray
   * @param {Array} array
   *      Array of string keys to objects stored in this registry to be retrieved using {@link ProAct.Registry#toObject}.
   *

   *        If object is not stored on some key, the key itself is returned in the same possition in the result array.
   *

   * @return {Array}
   *      Of the retrieved objects, in the same order as the keys.
   * @see {@link ProAct.Registry#toObject}
   * @see {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   */
  toObjectArray: function (array) {
    var self = this;
    if (!P.U.isArray(array)) {
      return this.toObject(array);
    }
    return map.call(array, function (el) {
      return self.toObject(el);
    });
  },

  /**
   * Helper method for transforming a key of stored item in this ProAct.Registry to the actual item or returning the key, if
   * the item is not found in the ProAct.Registry.
   *

   *  Mainly used by the {{#crossLink "ProAct.DSL"}}{{/crossLink}} logic.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method toObject
   * @param {String|Object} data
   *      Key of strored object or something else. If the key is valid and there is something stored on it, the stored object is retrieved.
   *

   *        If there is nothing stored for this data, the data itself is returned.
   *

   * @return {Object}
   *      Stored object, if found using the passed data or the data itself.
   * @see {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   * @see {@link ProAct.Registry#get}
   */
  toObject: function (data) {
    if (P.U.isString(data)) {
      var result = this.get(data);
      return result ? result : data;
    }

    return data;
  }
};
<commit_msg>More ProAct.Registry docs.<commit_after>/**
 * The `proact-dsl` module provides DSL for creating and managing different ProAct objects.
 *
 *
 * @module proact-dsl
 * @main proact-dsl
 */

/**
 *

 *  Constructs a `ProAct.Registry`.
 *  It is used to store/create objects that can be referenced or configured using the {{#crossLink "ProAct.DSL"}}{{/crossLink}}.
 *

 *

 *  `ProAct.Registry` is part of the `proact-dsl` module of ProAct.js.
 *

 *
 * @class ProAct.Registry
 * @constructor
 */
function Registry () {
  this.providers = {};
}
ProAct.Registry = P.R = Registry;

ProAct.Registry.prototype = rProto = {

  /**
   * Reference to the constructor of this object.
   *
   * @property constructor
   * @type ProAct.Registry
   * @final
   * @for ProAct.Registry
   */
  constructor: ProAct.Registry,

  /**
   * Registers a {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} for the passed namespace in the registry.
   *
   * @for ProAct.Registry
   * @instance
   * @method register
   * @param {String} namespace
   *      The namespace to register the provider in.
   * @param {ProAct.Registry.Provider} provider
   *      The {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} to register.
   * @return {ProAct.Registers}
   *      this
   * @throws {Error}
   *      If a {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} is already registered for the passed namespace.
   */
  register: function (namespace, provider) {
    if (this.providers[namespace]) {
      throw new Error(namespace + 'is already registered in this registry.');
    }
    this.providers[namespace] = provider;
    if (provider.registered) {
      provider.registered(this);
    }
    return this;
  },

  /**
   * Retrieves the right {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} using the name of stored
   * in this ProAct.Registry object, or the name of an object to be stored
   *
   * @for ProAct.Registry
   * @instance
   * @method getProviderByName
   * @param {String} name
   *      The name of storable object.
   *

   *        It must be in the format '{namespace}:{key}'.
   *

   *

   *        Here the namespace is the namespace the {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} manages.
   *

   * @return {Array}
   *      The first element in the result is the {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} or undefined if not found.
   *

   *        The second one is the key at which an object is stored or will be stored in the provider.
   *

   *

   *        The third element is an array with options for storing/creating an object passed to the provider using
   *        the name string.
   *

   */
  getProviderByName: function (name) {
    var parts = name.split(':');

    return [this.providers[parts[0]], parts[1], parts.slice(2)];
  },

  /**
   * Configures an object to be stored using {{#crossLink "ProAct.DSL"}}{{/crossLink}} passed through options and DSL arguments.
   *

   *  Example usage:
   *

   *

   *  A {{#crossLink "ProAct.Stream"}}{{/crossLink}} is passed to the registry for setup with DSL data.
   *

   *

   *  The data passed through the options parameter is
   *

   *    '<<(s:foo)|map(-)|filter($1)'
   *

   *

   *

   *  And the arguments for the DSL machine passed through the args parameter are
   *

   *    [function (v) {
   *      return v % 2 === 0;
   *    }]
   *

   *

   *

   *  This means that a {{#crossLink "ProAct.Stream"}}{{/crossLink}} stored in this registry by the key 'foo' should be set
   *  as a source to the passed as the object parameter simple {{#crossLink "ProAct.Stream"}}{{/crossLink}}.
   *

   *

   *  It also means that for every value comming in the object parameter's stream there should be mapping of negativity and
   *  only even values should be passed to it.
   *

   *

   *  So if we trigger in the 'foo' stream the value of 4 in our stream we will get -4, and if we trigger 5, we won't get anything.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method setup
   * @param {Object} object
   *      The object to setup.
   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object.
   * @param {Array} args
   *      Arguments to be used by the {{#crossLink "ProAct.DSL/run:method"}}{{/crossLink}} method while configuring the passed object.
   * @return {Object}
   *      Ready to strore object.
   */
  setup: function (object, options, args) {
    return dsl.run.apply(null, [object, options, this].concat(args));
  },

  /**
   * Creates a new object and stores it in this registry, using the right provider for the creation
   * and configuring it using the DSL passed through the options parameter.
   *

   *  {@link ProAct.Registry#getProviderByName} is used to locate the right provider to create the object with.
   *

   *

   *  {@link ProAct.Registry#setup} is used to setup the newly created object using the {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   *

   *

   *  The idea of this method is to create and configure {@link ProAct.Actor} objects.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method make
   * @param {String} name
   *      Name of the object to create and store.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object to be created.
   * @param [...]
   *      Arguments to be used by the {{#crossLink "ProAct.DSL/run:method"}}{{/crossLink}} method while configuring the newly created object.
   * @return {Object}
   *      The newly created, stored and configured object, or null if there was no {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} register for its type.
   * @see {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   * @see {@link ProAct.Registry#getProviderByName}
   * @see {@link ProAct.Registry#setup}
   * @see {@link ProAct.Actor}
   */
  make: function (name, options) {
    var args = slice.call(arguments, 2),
        p = this.getProviderByName(name),
        actor;

    if (p[0]) {
      actor = p[0].make.apply(p[0], [p[1], p[2]].concat(args));
      return this.setup(actor, options, args);
    }
    return null;
  },

  /**
   * Stores an object  in this registry, using the right provider to configure it using the DSL passed through the options parameter.
   *

   *  {@link ProAct.Registry#getProviderByName} is used to locate the right provider to store the object to.
   *

   *
   * @for ProAct.Registry
   * @instance
   * @method store
   * @param {String} name
   *      Name of the object to store.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @param {Object} object
   *      The object to store.
   * @param {String|Object} options
   *      A {{#crossLink "ProAct.DSL"}}{{/crossLink}} data object or string used to setup the object to be stored (optional).
   * @param [...]
   *      Arguments to be used by the {{#crossLink "ProAct.DSL/run:method"}}{{/crossLink}} method while configuring the object.
   * @return {Object}
   *      The stored and configured object, or null if there was no {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} register for its type.
   */
  store: function (name, object, options) {
    var args = slice.call(arguments, 2),
        p = this.getProviderByName(name);

    if (p[0]) {
      return p[0].store.apply(p[0], [p[1], object, p[2]].concat(args));
    }
    return null;
  },

  /**
   * Retrieves an object, stored this registry.
   *

   *  {@link ProAct.Registry#getProviderByName} is used to locate the right provider to retrieve the object from.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method get
   * @param {String} name
   *      Name of the object to find.
   *

   *        It must be in the format '{namespace}:{key}'
   *

   * @return {Object}
   *      The stored object, or null if there was no {{#crossLink "ProAct.Registry.Provider"}}{{/crossLink}} register for its type or no object registered for the passed name.
   */
  get: function (name) {
    var p = this.getProviderByName(name);

    if (p[0]) {
      return p[0].get(p[1]);
    }
    return null;
  },

  /**
   * Helper method for transforming an array of keys of stored items in this ProAct.Registry to an array of the actual items.
   *

   *  Mainly used by the {{#crossLink "ProAct.DSL"}}{{/crossLink}} logic.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method toObjectArray
   * @param {Array} array
   *      Array of string keys to objects stored in this registry to be retrieved using {@link ProAct.Registry#toObject}.
   *

   *        If object is not stored on some key, the key itself is returned in the same possition in the result array.
   *

   * @return {Array}
   *      Of the retrieved objects, in the same order as the keys.
   * @see {@link ProAct.Registry#toObject}
   * @see {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   */
  toObjectArray: function (array) {
    var self = this;
    if (!P.U.isArray(array)) {
      return this.toObject(array);
    }
    return map.call(array, function (el) {
      return self.toObject(el);
    });
  },

  /**
   * Helper method for transforming a key of stored item in this ProAct.Registry to the actual item or returning the key, if
   * the item is not found in the ProAct.Registry.
   *

   *  Mainly used by the {{#crossLink "ProAct.DSL"}}{{/crossLink}} logic.
   *

   *
   * @memberof ProAct.Registry
   * @instance
   * @method toObject
   * @param {String|Object} data
   *      Key of strored object or something else. If the key is valid and there is something stored on it, the stored object is retrieved.
   *

   *        If there is nothing stored for this data, the data itself is returned.
   *

   * @return {Object}
   *      Stored object, if found using the passed data or the data itself.
   * @see {{#crossLink "ProAct.DSL"}}{{/crossLink}}
   * @see {@link ProAct.Registry#get}
   */
  toObject: function (data) {
    if (P.U.isString(data)) {
      var result = this.get(data);
      return result ? result : data;
    }

    return data;
  }
};
<|endoftext|>


<commit_before>/**
 * Created by huangxinghui on 2015/6/24.
 */

var _ = require('underscore');

module.exports = {
  _create: function() {
    this._opened = false;

    this.$input = this.$element.find('input').attr({
      autocomplete: "off",
      spellcheck: false
    });
  },

  dropdown: $.noop,

  isOpen: function() {
    return this._opened;
  },

  open: function() {
    if (this.isOpen()) return;

    this.$element.append(this.dropdown().$element);
    this._opened = true;
    this._trigger('open');
  },

  close: function() {
    if (!this.isOpen()) return;

    this.dropdown().$element.detach();
    this._opened = false;
    this._trigger('close');
  },

  _onKeyDown: function(e) {
    var c = e.keyCode;

    // If the dropdown `ul` is in view, then act on keydown for the following keys:
    // Enter / Esc / Up / Down
    if (this.isOpen()) {
      if (c === 13) { // Enter
        e.preventDefault();
        this._onEnter();
      }
      else if (c === 27) { // Esc
        this.close();
      }
      else if (c === 38 || c === 40) { // Down/Up arrow
        e.preventDefault();
        this.dropdown()[c === 38 ? "previous" : "next"]();
      }
    }
  },

  _onMouseDown: function(e) {
    var $li = $(e.currentTarget),
        dropDownInstance = this.dropdown(),
        index = dropDownInstance.$element.find('li').index($li);

    var item = dropDownInstance.dataSource().get(index);
    this.$input.val(dropDownInstance.itemToLabel(item));
    this.close();
  },

  _onEnter: function() {
    this.$input.val(this.dropdown().text());
    this.close();
  }
};<commit_msg>revert<commit_after>/**
 * Created by huangxinghui on 2015/6/24.
 */

var _ = require('underscore');

module.exports = {
  _create: function() {
    this._opened = false;

    this.$input = this.$element.find('input').attr({
      autocomplete: "off",
      spellcheck: false
    });
  },

  dropdown: $.noop,

  isOpen: function() {
    return this._opened;
  },

  open: function() {
    if (this.isOpen()) return;

    this.$element.append(this.dropdown().$element);
    this.$element.addClass('open');
    this._opened = true;
    this._trigger('open');
  },

  close: function() {
    if (!this.isOpen()) return;

    this.dropdown().$element.detach();
    this.$element.removeClass('open');
    this._opened = false;
    this._trigger('close');
  },

  _onKeyDown: function(e) {
    var c = e.keyCode;

    // If the dropdown `ul` is in view, then act on keydown for the following keys:
    // Enter / Esc / Up / Down
    if (this.isOpen()) {
      if (c === 13) { // Enter
        e.preventDefault();
        this._onEnter();
      }
      else if (c === 27) { // Esc
        this.close();
      }
      else if (c === 38 || c === 40) { // Down/Up arrow
        e.preventDefault();
        this.dropdown()[c === 38 ? "previous" : "next"]();
      }
    }
  },

  _onMouseDown: function(e) {
    var $li = $(e.currentTarget),
        dropDownInstance = this.dropdown(),
        index = dropDownInstance.$element.find('li').index($li);

    var item = dropDownInstance.dataSource().get(index);
    this.$input.val(dropDownInstance.itemToLabel(item));
    this.close();
  },

  _onEnter: function() {
    this.$input.val(this.dropdown().text());
    this.close();
  }
};<|endoftext|>


<commit_before>class Reference {
  constructor(shrId, entryId, entryType) {
    this._shrId = shrId;
    this._entryId = entryId;
    this._entryType = entryType;
  }

  /**
   * Getter for shr.base.ShrId
   */
  get shrId() {
    return this._shrId;
  }

  /**
   * Setter for shr.base.ShrId
   */
  set shrId(shrIdVal) {
    this._shrId = shrIdVal;
  }

  /**
   * Getter for shr.base.EntryId
   */
  get entryId() {
    return this._entryId;
  }

  /**
   * Setter for shr.base.EntryId
   */
  set entryId(entryIdVal) {
    this._entryId = entryIdVal;
  }

  /**
   * Getter for shr.base.EntryType
   */
  get entryType() {
    return this._entryType;
  }

  /**
   * Setter for shr.base.EntryType
   */
  set entryType(entryTypeVal) {
    this._entryType = entryTypeVal;
  }
}

export default Reference;<commit_msg>Updated Reference.js to have a second constructor that takes in entryInfo<commit_after>class Reference {
  constructor(shrId, entryId, entryType) {
    this._shrId = shrId;
    this._entryId = entryId;
    this._entryType = entryType;
  }

  constructor(entryInfo) {
    this._shrId = entryInfo.shrId;
    this._entryId = entryInfo.entryId;
    this._entryType = entryInfo.entryType;
  }

  /**
   * Getter for shr.base.ShrId
   */
  get shrId() {
    return this._shrId;
  }

  /**
   * Setter for shr.base.ShrId
   */
  set shrId(shrIdVal) {
    this._shrId = shrIdVal;
  }

  /**
   * Getter for shr.base.EntryId
   */
  get entryId() {
    return this._entryId;
  }

  /**
   * Setter for shr.base.EntryId
   */
  set entryId(entryIdVal) {
    this._entryId = entryIdVal;
  }

  /**
   * Getter for shr.base.EntryType
   */
  get entryType() {
    return this._entryType;
  }

  /**
   * Setter for shr.base.EntryType
   */
  set entryType(entryTypeVal) {
    this._entryType = entryTypeVal;
  }
}

export default Reference;<|endoftext|>


<commit_before>;(function(window){
    'use strict';
    var doc = window.document;

    var PartyLetterz = {
        config: {
            version: '0.0.1',
            imgPath:  '../src/img/'
        },
        partyHard: function() {
            console.log("When it's time to party we will party hard.");
            console.log(this.config);
            var elements = doc.querySelectorAll('.partyletter');

            for( var i = 0, len = elements.length; i < len; i++) {
                var current = elements[i];
                if (   current.tagName === 'P'
                    || current.tagName === 'H1'
                    || current.tagName === 'H2'
                    || current.tagName === 'H3'
                    || current.tagName === 'H4'
                    || current.tagName === 'SPAN'
                    ) {
                    var text = current.childNodes[0].nodeValue;

                    var imageBackground = '';
                    var imagePositions  = '';
                    var currentPosition = 0;
                    var currentAcc      = 0;

                    switch (current.tagName) {
                        case 'H1':
                            currentAcc = 110;
                            break;
                        case 'H2':
                            currentAcc = 105;
                            break;
                        case 'H3':
                            currentAcc = 70;
                            break;
                        case 'H4':
                            currentAcc = 60;
                            break;
                        case 'P':
                            currentAcc = 20;
                            break;
                    }

                    for (var x = 0, txtlen = text.length; x < txtlen; x++) {
                        var char = text[x];
                            currentPosition += currentAcc;

                            if (char != ' ') {
                                imageBackground += 'url(' + "'" + this.config.imgPath + char.toUpperCase() + ".gif'" + ')';
                            } else {
                                imageBackground += "url('"+ this.config.imgPath +"')";
                            }

                            imagePositions += currentPosition + 'px 0px';
                            if (x < txtlen - 1) {
                                imageBackground += ', ';
                                imagePositions  += ', ';
                            }

                    }

                    current.style['background-image']    = imageBackground;
                    current.style['background-position'] = imagePositions;
                    current.childNodes[0].nodeValue = "";
                }
            }
        }
    };

    if (!window.PartyLetterz) {
        window.PartyLetterz = PartyLetterz;
    } else {console.error("PartyLetterz already included once on page!")}

})(window);<commit_msg>Style h1 better<commit_after>;(function(window){
    'use strict';
    var doc = window.document;

    var PartyLetterz = {
        config: {
            version: '0.0.1',
            imgPath:  '../src/img/'
        },
        partyHard: function() {
            console.log("When it's time to party we will party hard.");
            console.log(this.config);
            var elements = doc.querySelectorAll('.partyletter');

            for( var i = 0, len = elements.length; i < len; i++) {
                var current = elements[i];
                if (   current.tagName === 'P'
                    || current.tagName === 'H1'
                    || current.tagName === 'H2'
                    || current.tagName === 'H3'
                    || current.tagName === 'H4'
                    || current.tagName === 'SPAN'
                    ) {
                    var text = current.childNodes[0].nodeValue;

                    var imageBackground = '';
                    var imagePositions  = '';
                    var currentPosition = 0;
                    var currentAcc      = 0;

                    switch (current.tagName) {
                        case 'H1':
                            currentAcc = 120;
                            break;
                        case 'H2':
                            currentAcc = 105;
                            break;
                        case 'H3':
                            currentAcc = 70;
                            break;
                        case 'H4':
                            currentAcc = 60;
                            break;
                        case 'P':
                            currentAcc = 20;
                            break;
                    }

                    for (var x = 0, txtlen = text.length; x < txtlen; x++) {
                        var char = text[x];
                            currentPosition += currentAcc;

                            if (char != ' ') {
                                imageBackground += 'url(' + "'" + this.config.imgPath + char.toUpperCase() + ".gif'" + ')';
                            } else {
                                imageBackground += "url('"+ this.config.imgPath +"')";
                            }

                            imagePositions += currentPosition + 'px 0px';
                            if (x < txtlen - 1) {
                                imageBackground += ', ';
                                imagePositions  += ', ';
                            }

                    }

                    current.style['background-image']    = imageBackground;
                    current.style['background-position'] = imagePositions;
                    current.childNodes[0].nodeValue = "";
                }
            }
        }
    };

    if (!window.PartyLetterz) {
        window.PartyLetterz = PartyLetterz;
    } else {console.error("PartyLetterz already included once on page!")}

})(window);<|endoftext|>


<commit_before>
	// Handler for attaching events trough a proxy.
	function attach ( events, element, callback, data ) {

		// This function can be used to 'filter' events to the slider.
		// element is a node, not a nodeList

		var method = function ( e ){

			if ( scope_Target.hasAttribute('disabled') ) {
				return false;
			}

			// Stop if an active 'tap' transition is taking place.
			if ( hasClass(scope_Target, options.cssClasses.tap) ) {
				return false;
			}

			e = fixEvent(e, data.pageOffset);

			// Ignore right or middle clicks on start #454
			if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) {
				return false;
			}

			// Ignore right or middle clicks on start #454
			if ( data.hover && e.buttons ) {
				return false;
			}

			e.calcPoint = e.points[ options.ort ];

			// Call the event handler with the event [ and additional data ].
			callback ( e, data );

		}, methods = [];

		// Bind a closure on the target for every event type.
		events.split(' ').forEach(function( eventName ){
			element.addEventListener(eventName, method, false);
			methods.push([eventName, method]);
		});

		return methods;
	}

	// Handle movement on document for handle and range drag.
	function move ( event, data ) {

		// Fix #498
		// Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty).
		// https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero
		// IE9 has .buttons and .which zero on mousemove.
		// Firefox breaks the spec MDN defines.
		if ( navigator.appVersion.indexOf("MSIE 9") === -1 && event.buttons === 0 && data.buttonsProperty !== 0 ) {
			return end(event, data);
		}

		var handles = data.handles || scope_Handles, positions, state = false,
			proposal = ((event.calcPoint - data.start) * 100) / data.baseSize, handleNumber, i;

		for (handleNumber = 0 ; scope_Handles[handleNumber] !== handles[0] ; handleNumber++) { }

		// Calculate relative positions for the handles.
		positions = getPositions( proposal, data.positions );

		state = setHandle ( handles[0], positions[handleNumber], handles.length === 1 );

		if ( handles.length > 1 ) {

			state = setHandle ( handles[1], positions[handleNumber?0:1], false ) || state;

			if ( state ) {
				// fire for both handles
				for ( i = 0; i < data.handles.length; i++ ) {
					fireEvent('slide', i);
				}
			}
		} else if ( state ) {
			// Fire for a single handle
			fireEvent('slide', handleNumber);
		}
	}

	// Unbind move events on document, call callbacks.
	function end ( event, data ) {

		// The handle is no longer active, so remove the class.
		var active = scope_Base.querySelector( '.' + options.cssClasses.active ),
			handleNumber = data.handles[0] === scope_Handles[0] ? 0 : 1;

		if ( active !== null ) {
			removeClass(active, options.cssClasses.active);
		}

		// Remove cursor styles and text-selection events bound to the body.
		if ( event.cursor ) {
			document.body.style.cursor = '';
			document.body.removeEventListener('selectstart', document.body.noUiListener);
		}

		var d = document.documentElement;

		// Unbind the move and end events, which are added on 'start'.
		d.noUiListeners.forEach(function( c ) {
			d.removeEventListener(c[0], c[1]);
		});

		// Remove dragging class.
		removeClass(scope_Target, options.cssClasses.drag);

		// Fire the change and set events.
		fireEvent('set', handleNumber);
		fireEvent('change', handleNumber);

		// If this is a standard handle movement, fire the end event.
		if ( data.handleNumber !== undefined ) {
			fireEvent('end', data.handleNumber);
		}
	}

	// Fire 'end' when a mouse or pen leaves the document.
	function documentLeave ( event, data ) {
		if ( event.type === "mouseout" && event.target.nodeName === "HTML" && event.relatedTarget === null ){
			end ( event, data );
		}
	}

	// Bind move events on document.
	function start ( event, data ) {

		var d = document.documentElement;

		// Mark the handle as 'active' so it can be styled.
		if ( data.handles.length === 1 ) {
			// Support 'disabled' handles
			if ( data.handles[0].hasAttribute('disabled') ) {
				return false;
			}

			addClass(data.handles[0].children[0], options.cssClasses.active);
		}

		// Fix #551, where a handle gets selected instead of dragged.
		event.preventDefault();

		// A drag should never propagate up to the 'tap' event.
		event.stopPropagation();

		// Attach the move and end events.
		var moveEvent = attach(actions.move, d, move, {
			start: event.calcPoint,
			baseSize: baseSize(),
			pageOffset: event.pageOffset,
			handles: data.handles,
			handleNumber: data.handleNumber,
			buttonsProperty: event.buttons,
			positions: scope_Locations.slice()
		}), endEvent = attach(actions.end, d, end, {
			handles: data.handles,
			handleNumber: data.handleNumber
		});

		var outEvent = attach("mouseout", d, documentLeave, {
			handles: data.handles,
			handleNumber: data.handleNumber
		});

		d.noUiListeners = moveEvent.concat(endEvent, outEvent);

		// Text selection isn't an issue on touch devices,
		// so adding cursor styles can be skipped.
		if ( event.cursor ) {

			// Prevent the 'I' cursor and extend the range-drag cursor.
			document.body.style.cursor = getComputedStyle(event.target).cursor;

			// Mark the target with a dragging state.
			if ( scope_Handles.length > 1 ) {
				addClass(scope_Target, options.cssClasses.drag);
			}

			var f = function(){
				return false;
			};

			document.body.noUiListener = f;

			// Prevent text selection when dragging the handles.
			document.body.addEventListener('selectstart', f, false);
		}

		if ( data.handleNumber !== undefined ) {
			fireEvent('start', data.handleNumber);
		}
	}

	// Move closest handle to tapped location.
	function tap ( event ) {

		var location = event.calcPoint, total = 0, handleNumber, to;

		// The tap event shouldn't propagate up and cause 'edge' to run.
		event.stopPropagation();

		// Add up the handle offsets.
		scope_Handles.forEach(function(a){
			total += offset(a)[ options.style ];
		});

		// Find the handle closest to the tapped position.
		handleNumber = ( location < total/2 || scope_Handles.length === 1 ) ? 0 : 1;

		// Check if handler is not disablet if yes set number to the next handler
		if (scope_Handles[handleNumber].hasAttribute('disabled')) {
			handleNumber = handleNumber ? 0 : 1;
		}

		location -= offset(scope_Base)[ options.style ];

		// Calculate the new position.
		to = ( location * 100 ) / baseSize();

		if ( !options.events.snap ) {
			// Flag the slider as it is now in a transitional state.
			// Transition takes a configurable amount of ms (default 300). Re-enable the slider after that.
			addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration );
		}

		// Support 'disabled' handles
		if ( scope_Handles[handleNumber].hasAttribute('disabled') ) {
			return false;
		}

		// Find the closest handle and calculate the tapped point.
		// The set handle to the new position.
		setHandle( scope_Handles[handleNumber], to );

		fireEvent('slide', handleNumber, true);
		fireEvent('set', handleNumber, true);
		fireEvent('change', handleNumber, true);

		if ( options.events.snap ) {
			start(event, { handles: [scope_Handles[handleNumber]] });
		}
	}

	// Fires a 'hover' event for a hovered mouse/pen position.
	function hover ( event ) {

		var location = event.calcPoint - offset(scope_Base)[ options.style ],
			to = scope_Spectrum.getStep(( location * 100 ) / baseSize()),
			value = scope_Spectrum.fromStepping( to );

		Object.keys(scope_Events).forEach(function( targetEvent ) {
			if ( 'hover' === targetEvent.split('.')[0] ) {
				scope_Events[targetEvent].forEach(function( callback ) {
					callback.call( scope_Self, value );
				});
			}
		});
	}

	// Attach events to several slider parts.
	function events ( behaviour ) {

		// Attach the standard drag event to the handles.
		if ( !behaviour.fixed ) {

			scope_Handles.forEach(function( handle, index ){

				// These events are only bound to the visual handle
				// element, not the 'real' origin element.
				attach ( actions.start, handle.children[0], start, {
					handles: [ handle ],
					handleNumber: index
				});
			});
		}

		// Attach the tap event to the slider base.
		if ( behaviour.tap ) {

			attach ( actions.start, scope_Base, tap, {
				handles: scope_Handles
			});
		}

		// Fire hover events
		if ( behaviour.hover ) {
			attach ( actions.move, scope_Base, hover, { hover: true } );
		}

		// Make the range draggable.
		if ( behaviour.drag ){

			var drag = [scope_Base.querySelector( '.' + options.cssClasses.connect )];
			addClass(drag[0], options.cssClasses.draggable);

			// When the range is fixed, the entire range can
			// be dragged by the handles. The handle in the first
			// origin will propagate the start event upward,
			// but it needs to be bound manually on the other.
			if ( behaviour.fixed ) {
				drag.push(scope_Handles[(drag[0] === scope_Handles[0] ? 1 : 0)].children[0]);
			}

			drag.forEach(function( element ) {
				attach ( actions.start, element, start, {
					handles: scope_Handles
				});
			});
		}
	}
<commit_msg>Select correct handle to move on slider tap, when multiple handles are present, even when they overlap.<commit_after>
	// Handler for attaching events trough a proxy.
	function attach ( events, element, callback, data ) {

		// This function can be used to 'filter' events to the slider.
		// element is a node, not a nodeList

		var method = function ( e ){

			if ( scope_Target.hasAttribute('disabled') ) {
				return false;
			}

			// Stop if an active 'tap' transition is taking place.
			if ( hasClass(scope_Target, options.cssClasses.tap) ) {
				return false;
			}

			e = fixEvent(e, data.pageOffset);

			// Ignore right or middle clicks on start #454
			if ( events === actions.start && e.buttons !== undefined && e.buttons > 1 ) {
				return false;
			}

			// Ignore right or middle clicks on start #454
			if ( data.hover && e.buttons ) {
				return false;
			}

			e.calcPoint = e.points[ options.ort ];

			// Call the event handler with the event [ and additional data ].
			callback ( e, data );

		}, methods = [];

		// Bind a closure on the target for every event type.
		events.split(' ').forEach(function( eventName ){
			element.addEventListener(eventName, method, false);
			methods.push([eventName, method]);
		});

		return methods;
	}

	// Handle movement on document for handle and range drag.
	function move ( event, data ) {

		// Fix #498
		// Check value of .buttons in 'start' to work around a bug in IE10 mobile (data.buttonsProperty).
		// https://connect.microsoft.com/IE/feedback/details/927005/mobile-ie10-windows-phone-buttons-property-of-pointermove-event-always-zero
		// IE9 has .buttons and .which zero on mousemove.
		// Firefox breaks the spec MDN defines.
		if ( navigator.appVersion.indexOf("MSIE 9") === -1 && event.buttons === 0 && data.buttonsProperty !== 0 ) {
			return end(event, data);
		}

		var handles = data.handles || scope_Handles, positions, state = false,
			proposal = ((event.calcPoint - data.start) * 100) / data.baseSize, handleNumber, i;

		for (handleNumber = 0 ; scope_Handles[handleNumber] !== handles[0] ; handleNumber++) { }

		// Calculate relative positions for the handles.
		positions = getPositions( proposal, data.positions );

		state = setHandle ( handles[0], positions[handleNumber], handles.length === 1 );

		if ( handles.length > 1 ) {

			state = setHandle ( handles[1], positions[handleNumber?0:1], false ) || state;

			if ( state ) {
				// fire for both handles
				for ( i = 0; i < data.handles.length; i++ ) {
					fireEvent('slide', i);
				}
			}
		} else if ( state ) {
			// Fire for a single handle
			fireEvent('slide', handleNumber);
		}
	}

	// Unbind move events on document, call callbacks.
	function end ( event, data ) {

		// The handle is no longer active, so remove the class.
		var active = scope_Base.querySelector( '.' + options.cssClasses.active ),
			handleNumber = data.handles[0] === scope_Handles[0] ? 0 : 1;

		if ( active !== null ) {
			removeClass(active, options.cssClasses.active);
		}

		// Remove cursor styles and text-selection events bound to the body.
		if ( event.cursor ) {
			document.body.style.cursor = '';
			document.body.removeEventListener('selectstart', document.body.noUiListener);
		}

		var d = document.documentElement;

		// Unbind the move and end events, which are added on 'start'.
		d.noUiListeners.forEach(function( c ) {
			d.removeEventListener(c[0], c[1]);
		});

		// Remove dragging class.
		removeClass(scope_Target, options.cssClasses.drag);

		// Fire the change and set events.
		fireEvent('set', handleNumber);
		fireEvent('change', handleNumber);

		// If this is a standard handle movement, fire the end event.
		if ( data.handleNumber !== undefined ) {
			fireEvent('end', data.handleNumber);
		}
	}

	// Fire 'end' when a mouse or pen leaves the document.
	function documentLeave ( event, data ) {
		if ( event.type === "mouseout" && event.target.nodeName === "HTML" && event.relatedTarget === null ){
			end ( event, data );
		}
	}

	// Bind move events on document.
	function start ( event, data ) {

		var d = document.documentElement;

		// Mark the handle as 'active' so it can be styled.
		if ( data.handles.length === 1 ) {
			// Support 'disabled' handles
			if ( data.handles[0].hasAttribute('disabled') ) {
				return false;
			}

			addClass(data.handles[0].children[0], options.cssClasses.active);
		}

		// Fix #551, where a handle gets selected instead of dragged.
		event.preventDefault();

		// A drag should never propagate up to the 'tap' event.
		event.stopPropagation();

		// Attach the move and end events.
		var moveEvent = attach(actions.move, d, move, {
			start: event.calcPoint,
			baseSize: baseSize(),
			pageOffset: event.pageOffset,
			handles: data.handles,
			handleNumber: data.handleNumber,
			buttonsProperty: event.buttons,
			positions: scope_Locations.slice()
		}), endEvent = attach(actions.end, d, end, {
			handles: data.handles,
			handleNumber: data.handleNumber
		});

		var outEvent = attach("mouseout", d, documentLeave, {
			handles: data.handles,
			handleNumber: data.handleNumber
		});

		d.noUiListeners = moveEvent.concat(endEvent, outEvent);

		// Text selection isn't an issue on touch devices,
		// so adding cursor styles can be skipped.
		if ( event.cursor ) {

			// Prevent the 'I' cursor and extend the range-drag cursor.
			document.body.style.cursor = getComputedStyle(event.target).cursor;

			// Mark the target with a dragging state.
			if ( scope_Handles.length > 1 ) {
				addClass(scope_Target, options.cssClasses.drag);
			}

			var f = function(){
				return false;
			};

			document.body.noUiListener = f;

			// Prevent text selection when dragging the handles.
			document.body.addEventListener('selectstart', f, false);
		}

		if ( data.handleNumber !== undefined ) {
			fireEvent('start', data.handleNumber);
		}
	}

	// Move closest handle to tapped location.
	function tap ( event ) {

		var location = event.calcPoint, handleNumber = -1, minDistance = Number.MAX_VALUE, to;

		// The tap event shouldn't propagate up and cause 'edge' to run.
		event.stopPropagation();

		// Iterate all handles.
		for ( var handleIndex = 0; handleIndex < scope_Handles.length; handleIndex++ ) {
			var a = scope_Handles[handleIndex];
			// If the handle is not disabled (disabled handles are ignored).
			if ( !scope_Handles[handleIndex].hasAttribute('disabled') ) {
				var candidateMinDistance = Math.abs( offset(a)[ options.style ] - location );
				// If the candidate is better, then update the minimum distance as well as the handle number.
				if ( candidateMinDistance < minDistance ) {
					minDistance = candidateMinDistance;
					handleNumber = handleIndex;
				}
				// If they are the same, the relative positions of handle and location decide whether there is an update.
				// This is needed for totally overlapping handles.
				else if ( candidateMinDistance == minDistance ) {
					// If this handle is before the location, then this handle should be selected.
					if ( offset(a)[ options.style ] < location ) {
						handleNumber = handleIndex;
					}
				}
				// Else, that is the candidate is worse, then the candidates will be getting even worse from there on.
				else {
					break;
				}
			}
		}

		location -= offset(scope_Base)[ options.style ];

		// Calculate the new position.
		to = ( location * 100 ) / baseSize();

		if ( !options.events.snap ) {
			// Flag the slider as it is now in a transitional state.
			// Transition takes a configurable amount of ms (default 300). Re-enable the slider after that.
			addClassFor( scope_Target, options.cssClasses.tap, options.animationDuration );
		}

		// Tackle the case that all handles are 'disabled'.
		if ( handleNumber == -1 ) {
			return false;
		}

		// Find the closest handle and calculate the tapped point.
		// The set handle to the new position.
		setHandle( scope_Handles[handleNumber], to );

		fireEvent('slide', handleNumber, true);
		fireEvent('set', handleNumber, true);
		fireEvent('change', handleNumber, true);

		if ( options.events.snap ) {
			start(event, { handles: [scope_Handles[handleNumber]] });
		}
	}

	// Fires a 'hover' event for a hovered mouse/pen position.
	function hover ( event ) {

		var location = event.calcPoint - offset(scope_Base)[ options.style ],
			to = scope_Spectrum.getStep(( location * 100 ) / baseSize()),
			value = scope_Spectrum.fromStepping( to );

		Object.keys(scope_Events).forEach(function( targetEvent ) {
			if ( 'hover' === targetEvent.split('.')[0] ) {
				scope_Events[targetEvent].forEach(function( callback ) {
					callback.call( scope_Self, value );
				});
			}
		});
	}

	// Attach events to several slider parts.
	function events ( behaviour ) {

		// Attach the standard drag event to the handles.
		if ( !behaviour.fixed ) {

			scope_Handles.forEach(function( handle, index ){

				// These events are only bound to the visual handle
				// element, not the 'real' origin element.
				attach ( actions.start, handle.children[0], start, {
					handles: [ handle ],
					handleNumber: index
				});
			});
		}

		// Attach the tap event to the slider base.
		if ( behaviour.tap ) {

			attach ( actions.start, scope_Base, tap, {
				handles: scope_Handles
			});
		}

		// Fire hover events
		if ( behaviour.hover ) {
			attach ( actions.move, scope_Base, hover, { hover: true } );
		}

		// Make the range draggable.
		if ( behaviour.drag ){

			var drag = [scope_Base.querySelector( '.' + options.cssClasses.connect )];
			addClass(drag[0], options.cssClasses.draggable);

			// When the range is fixed, the entire range can
			// be dragged by the handles. The handle in the first
			// origin will propagate the start event upward,
			// but it needs to be bound manually on the other.
			if ( behaviour.fixed ) {
				drag.push(scope_Handles[(drag[0] === scope_Handles[0] ? 1 : 0)].children[0]);
			}

			drag.forEach(function( element ) {
				attach ( actions.start, element, start, {
					handles: scope_Handles
				});
			});
		}
	}
<|endoftext|>


<commit_before>import {routerRedux} from 'dva/router';
import {getItemInfoById} from '../services/appService';
import {config, storeage, model, urlMap, action, fun} from '../common';

export default {
	namespace: model.app,
	state: {
		user: {},
	},
	reducers: {
		init( state, { payload: user } ) {
			console.log('===appModel===init===');
			return {
				...state, user
			}
		}
	},
	effects: {
		*checkLogin( {}, { call, put } ) {
			let user = storeage.get( config.local.user );
			fun.print( user, '存储在浏览器内的user数据' );
			if ( user && user.userType === config.userType.doctor ) {
				yield put( { type: action.app_init, payload: user } );
			}
			else {
				yield put( routerRedux.push( urlMap.login ) );
			}
		},
		*logout( {}, { put } ) {
			storeage.set( config.local.user, null );
			yield put( routerRedux.push( urlMap.login ) );
		},
		*getItemPrice( { payload }, { call } ){
			const data = yield call( getItemInfoById, { itemId: payload.itemId } );
			if ( data.success ) {
				payload.fun( data.entity.itemMoney );
			} else {
				throw data
			}
		}
	},
	subscriptions: {
		setup ( { dispatch, history } ) {
			history.listen( ( { pathname, query } ) => {
				if ( pathname === '/orderList' ) {
					let user = { userType: config.userType.worker };
					user = Object.assign( {}, user, query );
					storeage.set( config.local.user, user );
					dispatch( { type: action.app_init, payload: user } );
				} else if ( pathname !== '/login' && pathname.indexOf( 'worker' ) < 0 ) {
					dispatch( { type: action.checkLogin } );
				}
			} )
		},
	},
};
<commit_msg>appModel<commit_after>import {routerRedux} from 'dva/router';
import {getItemInfoById} from '../services/appService';
import {config, storeage, model, urlMap, action, fun} from '../common';

export default {
	namespace: model.app,
	state: {
		user: {},
	},
	reducers: {
		init( state, { payload: user } ) {
			return {
				...state, user
			}
		}
	},
	effects: {
		*checkLogin( {}, { select, put } ) {
			let user = storeage.get( config.local.user );
			fun.print( user, '存储在浏览器内的user数据' );
			if ( user && user.userType === config.userType.doctor ) {
				const stateUser = yield select( state => state.appModel.user );
				if ( !stateUser || fun.isEmptyObject( stateUser ) ) {
					yield put( { type: action.app_init, payload: user } );
				}
			}
			else {
				yield put( routerRedux.push( urlMap.login ) );
			}
		},
		*logout( {}, { put } ) {
			storeage.set( config.local.user, null );
			yield put( routerRedux.push( urlMap.login ) );
		},
		*getItemPrice( { payload }, { call } ){
			const data = yield call( getItemInfoById, { itemId: payload.itemId } );
			if ( data.success ) {
				payload.fun( data.entity.itemMoney );
			} else {
				throw data
			}
		}
	},
	subscriptions: {
		setup ( { dispatch, history } ) {
			history.listen( ( { pathname, query } ) => {
				if ( pathname === '/orderList') {
					if(query.orderHandlerId){
						let user = { userType: config.userType.worker };
						user = Object.assign( {}, user, query );
						storeage.set( config.local.user, user );
						dispatch( { type: action.app_init, payload: user } );
					}
				} else if ( pathname !== '/login' && pathname.indexOf( 'worker' ) < 0 ) {
					dispatch( { type: action.checkLogin } );
				}
			} )
		},
	},
};
<|endoftext|>


<commit_before>(function(){

  'use strict';

  // the register trigger to flip the auth component.
  // and show the register form instead of login.
  let registerButton = document.querySelector('.js-register-open'),
      authComponent = document.querySelector('.c-authentication');

  registerButton.addEventListener('click', function (e) {
    e.preventDefault();
    authComponent.classList.add('state-register');
  });

})();
<commit_msg>restructure variables<commit_after>(function(){

  'use strict';

  // the register trigger to flip the auth component.
  // and show the register form instead of login.
  let authComponent = document.querySelector('.c-authentication'),
      LoginBtn = document.querySelector('.c-authentication__submit button'),
      registerBtnOpen = document.querySelector('.js-register-open'),
      registerBtnClose = document.querySelector('.js-register-close');

  registerButton.addEventListener('click', function (e) {
    e.preventDefault();
    authComponent.classList.add('state-register');
  });

})();
<|endoftext|>