<commit_before>// Copyright 2013-2015, University of Colorado Boulder

/**
 * An observable array of items.
 *

 * Because the array is observable, we must be careful about the possibility of concurrent-modification errors.
 * Any time we iterate over the array, we must iterate over a copy, because callback may be modifying the array.
 *
 * @author Sam Reid
 * @author Chris Malley
 */
define( function( require ) {
  'use strict';

  // modules
  var Property = require( 'AXON/Property' );
  var axon = require( 'AXON/axon' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Emitter = require( 'AXON/Emitter' );

  /**
   * @param {[]} array
   * @param {Object} [options]
   * @constructor
   */
  function ObservableArray( array, options ) {

    // Special case that the user supplied options but no array
    if ( array instanceof Object && !(array instanceof Array) ) {
      options = array;
      array = null;
    }

    this._options = _.extend( {
      allowDuplicates: false, // are duplicate items allowed in the array?
      tandem: null            // Tandem is supported here.  This line doesn't do anything different than leaving tandem as undefined
                              // but this entry serves as an indicator that tandem is supported here.
    }, options );

    this._array = array || []; // @private internal, do not access directly
    this._addedListeners = []; // @private listeners called when an item is added
    this._removedListeners = []; // @private listeners called when an item is removed

    this.lengthProperty = new Property( this._array.length ); // @public (read-only) observe this, but don't set it

    // @private Store the initial array, if any, for resetting, see #4
    this.initialArray = array ? array.slice() : [];

    // @private Event stream for signifying begin/end of callbacks
    this.startedCallbacksForItemAddedEmitter = new Emitter();
    this.endedCallbacksForItemAddedEmitter = new Emitter();
    this.startedCallbacksForItemRemovedEmitter = new Emitter();
    this.endedCallbacksForItemRemovedEmitter = new Emitter();

    options && options.tandem && options.tandem.addInstance( this );
    this.disposeObservableArray = function() {
      options && options.tandem && options.tandem.removeInstance( this );
    };
  }

  axon.register( 'ObservableArray', ObservableArray );

  return inherit( Object, ObservableArray, {

    // @public
    dispose: function() {
      this.disposeObservableArray();
    },

    /**
     * Restore the array back to its initial state
     * Note: if an item is in the current array and original array, it is removed and added back
     * This may or may not change in the future, see #4
     * @public
     */
    reset: function() {
      for ( var i = 0; i < this._array.length; i++ ) {
        this._fireItemRemoved( this._array[ i ] );
      }
      this._array = this.initialArray.slice();
      for ( i = 0; i < this._array.length; i++ ) {
        this._fireItemAdded( this._array[ i ] );
      }
    },

    // @public
    get length() { return this._array.length; },

    /**
     * Adds a listener that will be notified when an item is added to the list.
     * @param listener function( item, observableArray )
     * @public
     */
    addItemAddedListener: function( listener ) {
      assert && assert( this._addedListeners.indexOf( listener ) === -1 ); // listener is not already registered
      this._addedListeners.push( listener );
    },

    /**
     * Removes a listener that was added via addItemAddedListener.
     * @param listener
     * @public
     */
    removeItemAddedListener: function( listener ) {
      var index = this._addedListeners.indexOf( listener );
      assert && assert( index !== -1 ); // listener is registered
      this._addedListeners.splice( index, 1 );
    },

    /**
     * Adds a listener that will be notified when an item is removed from the list.
     * @param listener function( item, observableArray )
     * @public
     */
    addItemRemovedListener: function( listener ) {
      assert && assert( this._removedListeners.indexOf( listener ) === -1 ); // listener is not already registered
      this._removedListeners.push( listener );
    },

    /**
     * Removes a listener that was added via addItemRemovedListener.
     * @param listener
     * @public
     */
    removeItemRemovedListener: function( listener ) {
      var index = this._removedListeners.indexOf( listener );
      assert && assert( index !== -1 ); // listener is registered
      this._removedListeners.splice( index, 1 );
    },

    /**
     * Convenience function for adding both types of listeners in one shot.
     * @param itemAddedListener
     * @param itemRemovedListener
     * @public
     */
    addListeners: function( itemAddedListener, itemRemovedListener ) {
      this.addItemAddedListener( itemAddedListener );
      this.addItemRemovedListener( itemRemovedListener );
    },

    // @private Internal: called when an item is added.
    _fireItemAdded: function( item ) {
      this.startedCallbacksForItemAddedEmitter.emit();

      //Signify that an item was added to the list
      var copy = this._addedListeners.slice( 0 ); // operate on a copy, firing could result in the listeners changing
      for ( var i = 0; i < copy.length; i++ ) {
        copy[ i ]( item, this );
      }

      this.endedCallbacksForItemAddedEmitter.emit();
    },

    // Internal: called when an item is removed.
    _fireItemRemoved: function( item ) {

      this.startedCallbacksForItemRemovedEmitter.emit();

      //Signify that an item was removed from the list
      var copy = this._removedListeners.slice( 0 ); // operate on a copy, firing could result in the listeners changing
      for ( var i = 0; i < copy.length; i++ ) {
        copy[ i ]( item, this );
      }

      this.endedCallbacksForItemRemovedEmitter.emit();
    },

    /**
     * Adds an item to the end of the array.
     * This is a convenience function, and is the same as push.
     * @param item
     * @public
     */
    add: function( item ) {
      this.push( item );
    },

    /**
     * Add items to the end of the array.
     * This is a convenience function, and is the same as push.
     * @param {Array} items
     * @public
     */
    addAll: function( items ) {
      for ( var i = 0; i < items.length; i++ ) {
        this.add( items[ i ] );
      }
    },

    /**
     * Removes the first occurrence of an item from the array.
     * If duplicates are allowed (see options.allowDuplicates) you may need to call this multiple
     * times to totally purge item from the array.
     * @param item
     * @public
     */
    remove: function( item ) {
      var index = this._array.indexOf( item );
      if ( index !== -1 ) {
        this._array.splice( index, 1 );
        this.lengthProperty.set( this._array.length );
        this._fireItemRemoved( item );
      }
    },

    /**
     * Removes the first occurrence of each item in the specified array.
     * @param {Array} list a list of items to remove
     * @see ObservableArray.remove
     * @public
     */
    removeAll: function( list ) {
      for ( var i = 0; i < list.length; i++ ) {
        var item = list[ i ];
        this.remove( item );
      }
    },

    /**
     * Pushes an item onto the end of the array.
     * @param item
     * @throws Error if duplicates are not allowed (see options.allowDuplicates) and item is already in the array
     * @public
     */
    push: function( item ) {
      if ( !this._options.allowDuplicates && this.contains( item ) ) {
        throw new Error( 'duplicates are not allowed' );
      }
      this._array.push( item );
      this.lengthProperty.set( this._array.length );
      this._fireItemAdded( item );
    },

    /**
     * Removes an item from the end of the array and returns it.
     * @returns {*}
     * @public
     */
    pop: function() {
      var item = this._array.pop();
      if ( item !== undefined ) {
        this.lengthProperty.set( this._array.length );
        this._fireItemRemoved( item );
      }
      return item;
    },

    /**
     * Removes an item from the beginning of the array and returns it.
     * @returns {*}
     * @public
     */
    shift: function() {
      var item = this._array.shift();
      if ( item !== undefined ) {
        this.lengthProperty.set( this._array.length );
        this._fireItemRemoved( item );
      }
      return item;
    },

    /**
     * Does the array contain the specified item?
     * @param item
     * @returns {boolean}
     * @public
     */
    contains: function( item ) {
      return this.indexOf( item ) !== -1;
    },

    /**
     * Gets an item at the specified index.
     * @param index
     * @returns {*} the item, or undefined if there is no item at the specified index
     * @public
     */
    get: function( index ) {
      return this._array[ index ];
    },

    /**
     * Gets the index of a specified item.
     * @param item
     * @returns {*} -1 if item is not in the array
     * @public
     */
    indexOf: function( item ) {
      return this._array.indexOf( item );
    },

    /**
     * Removes all items from the array.
     * @public
     */
    clear: function() {
      var copy = this._array.slice( 0 );
      for ( var i = 0; i < copy.length; i++ ) {
        this.remove( copy[ i ] );
      }
    },

    /**
     * Applies a callback function to each item in the array
     * @param callback function(item)
     * @public
     */
    forEach: function( callback ) {
      this._array.slice().forEach( callback ); // do this on a copy of the array, in case callbacks involve array modification
    },

    /**
     * Maps the values in this ObservableArray using the specified function, and returns a new ObservableArray for chaining.
     * @param mapFunction
     * @returns {axon.ObservableArray}
     * @public
     */
    map: function( mapFunction ) {
      return new axon.ObservableArray( this._array.map( mapFunction ) );
    },

    /**
     * Filters the values in this ObservableArray using the predicate function, and returns a new ObservableArray for chaining.
     * @param mapFunction
     * @returns {axon.ObservableArray}
     * @public
     */
    filter: function( mapFunction ) {
      return new axon.ObservableArray( this._array.filter( mapFunction ) );
    },

    /**
     * Starting with the initial value, combine values from this ObservableArray to come up with a composite result.
     * Same as foldLeft.  In underscore this is called _.reduce aka _.foldl or _.inject
     * @param value
     * @param combiner
     * @returns {*}
     * @public
     */
    reduce: function( value, combiner ) {
      for ( var i = 0; i < this._array.length; i++ ) {
        value = combiner( value, this._array[ i ] );
      }
      return value;
    },

    /**
     * Return the underlying array
     * @returns {*|Array}
     * @public
     */
    getArray: function() {
      return this._array;
    },

    /**
     * Replaces all items in the array
     * @param {Array} items
     * @public
     */
    setItems: function( items ) {

      // TODO: do a better diff here for efficiency
      this.clear();
      this.addAll( items );
    }
  } );
} );<commit_msg>Removed unused method in ObservableArray<commit_after>// Copyright 2013-2015, University of Colorado Boulder

/**
 * An observable array of items.
 *

 * Because the array is observable, we must be careful about the possibility of concurrent-modification errors.
 * Any time we iterate over the array, we must iterate over a copy, because callback may be modifying the array.
 *
 * @author Sam Reid
 * @author Chris Malley
 */
define( function( require ) {
  'use strict';

  // modules
  var Property = require( 'AXON/Property' );
  var axon = require( 'AXON/axon' );
  var inherit = require( 'PHET_CORE/inherit' );
  var Emitter = require( 'AXON/Emitter' );

  /**
   * @param {[]} array
   * @param {Object} [options]
   * @constructor
   */
  function ObservableArray( array, options ) {

    // Special case that the user supplied options but no array
    if ( array instanceof Object && !(array instanceof Array) ) {
      options = array;
      array = null;
    }

    this._options = _.extend( {
      allowDuplicates: false, // are duplicate items allowed in the array?
      tandem: null            // Tandem is supported here.  This line doesn't do anything different than leaving tandem as undefined
                              // but this entry serves as an indicator that tandem is supported here.
    }, options );

    this._array = array || []; // @private internal, do not access directly
    this._addedListeners = []; // @private listeners called when an item is added
    this._removedListeners = []; // @private listeners called when an item is removed

    this.lengthProperty = new Property( this._array.length ); // @public (read-only) observe this, but don't set it

    // @private Store the initial array, if any, for resetting, see #4
    this.initialArray = array ? array.slice() : [];

    // @private Event stream for signifying begin/end of callbacks
    this.startedCallbacksForItemAddedEmitter = new Emitter();
    this.endedCallbacksForItemAddedEmitter = new Emitter();
    this.startedCallbacksForItemRemovedEmitter = new Emitter();
    this.endedCallbacksForItemRemovedEmitter = new Emitter();

    options && options.tandem && options.tandem.addInstance( this );
    this.disposeObservableArray = function() {
      options && options.tandem && options.tandem.removeInstance( this );
    };
  }

  axon.register( 'ObservableArray', ObservableArray );

  return inherit( Object, ObservableArray, {

    // @public
    dispose: function() {
      this.disposeObservableArray();
    },

    /**
     * Restore the array back to its initial state
     * Note: if an item is in the current array and original array, it is removed and added back
     * This may or may not change in the future, see #4
     * @public
     */
    reset: function() {
      for ( var i = 0; i < this._array.length; i++ ) {
        this._fireItemRemoved( this._array[ i ] );
      }
      this._array = this.initialArray.slice();
      for ( i = 0; i < this._array.length; i++ ) {
        this._fireItemAdded( this._array[ i ] );
      }
    },

    // @public
    get length() { return this._array.length; },

    /**
     * Adds a listener that will be notified when an item is added to the list.
     * @param listener function( item, observableArray )
     * @public
     */
    addItemAddedListener: function( listener ) {
      assert && assert( this._addedListeners.indexOf( listener ) === -1 ); // listener is not already registered
      this._addedListeners.push( listener );
    },

    /**
     * Removes a listener that was added via addItemAddedListener.
     * @param listener
     * @public
     */
    removeItemAddedListener: function( listener ) {
      var index = this._addedListeners.indexOf( listener );
      assert && assert( index !== -1 ); // listener is registered
      this._addedListeners.splice( index, 1 );
    },

    /**
     * Adds a listener that will be notified when an item is removed from the list.
     * @param listener function( item, observableArray )
     * @public
     */
    addItemRemovedListener: function( listener ) {
      assert && assert( this._removedListeners.indexOf( listener ) === -1 ); // listener is not already registered
      this._removedListeners.push( listener );
    },

    /**
     * Removes a listener that was added via addItemRemovedListener.
     * @param listener
     * @public
     */
    removeItemRemovedListener: function( listener ) {
      var index = this._removedListeners.indexOf( listener );
      assert && assert( index !== -1 ); // listener is registered
      this._removedListeners.splice( index, 1 );
    },

    /**
     * Convenience function for adding both types of listeners in one shot.
     * @param itemAddedListener
     * @param itemRemovedListener
     * @public
     */
    addListeners: function( itemAddedListener, itemRemovedListener ) {
      this.addItemAddedListener( itemAddedListener );
      this.addItemRemovedListener( itemRemovedListener );
    },

    // @private Internal: called when an item is added.
    _fireItemAdded: function( item ) {
      this.startedCallbacksForItemAddedEmitter.emit();

      //Signify that an item was added to the list
      var copy = this._addedListeners.slice( 0 ); // operate on a copy, firing could result in the listeners changing
      for ( var i = 0; i < copy.length; i++ ) {
        copy[ i ]( item, this );
      }

      this.endedCallbacksForItemAddedEmitter.emit();
    },

    // Internal: called when an item is removed.
    _fireItemRemoved: function( item ) {

      this.startedCallbacksForItemRemovedEmitter.emit();

      //Signify that an item was removed from the list
      var copy = this._removedListeners.slice( 0 ); // operate on a copy, firing could result in the listeners changing
      for ( var i = 0; i < copy.length; i++ ) {
        copy[ i ]( item, this );
      }

      this.endedCallbacksForItemRemovedEmitter.emit();
    },

    /**
     * Adds an item to the end of the array.
     * This is a convenience function, and is the same as push.
     * @param item
     * @public
     */
    add: function( item ) {
      this.push( item );
    },

    /**
     * Add items to the end of the array.
     * This is a convenience function, and is the same as push.
     * @param {Array} items
     * @public
     */
    addAll: function( items ) {
      for ( var i = 0; i < items.length; i++ ) {
        this.add( items[ i ] );
      }
    },

    /**
     * Removes the first occurrence of an item from the array.
     * If duplicates are allowed (see options.allowDuplicates) you may need to call this multiple
     * times to totally purge item from the array.
     * @param item
     * @public
     */
    remove: function( item ) {
      var index = this._array.indexOf( item );
      if ( index !== -1 ) {
        this._array.splice( index, 1 );
        this.lengthProperty.set( this._array.length );
        this._fireItemRemoved( item );
      }
    },

    /**
     * Removes the first occurrence of each item in the specified array.
     * @param {Array} list a list of items to remove
     * @see ObservableArray.remove
     * @public
     */
    removeAll: function( list ) {
      for ( var i = 0; i < list.length; i++ ) {
        var item = list[ i ];
        this.remove( item );
      }
    },

    /**
     * Pushes an item onto the end of the array.
     * @param item
     * @throws Error if duplicates are not allowed (see options.allowDuplicates) and item is already in the array
     * @public
     */
    push: function( item ) {
      if ( !this._options.allowDuplicates && this.contains( item ) ) {
        throw new Error( 'duplicates are not allowed' );
      }
      this._array.push( item );
      this.lengthProperty.set( this._array.length );
      this._fireItemAdded( item );
    },

    /**
     * Removes an item from the end of the array and returns it.
     * @returns {*}
     * @public
     */
    pop: function() {
      var item = this._array.pop();
      if ( item !== undefined ) {
        this.lengthProperty.set( this._array.length );
        this._fireItemRemoved( item );
      }
      return item;
    },

    /**
     * Removes an item from the beginning of the array and returns it.
     * @returns {*}
     * @public
     */
    shift: function() {
      var item = this._array.shift();
      if ( item !== undefined ) {
        this.lengthProperty.set( this._array.length );
        this._fireItemRemoved( item );
      }
      return item;
    },

    /**
     * Does the array contain the specified item?
     * @param item
     * @returns {boolean}
     * @public
     */
    contains: function( item ) {
      return this.indexOf( item ) !== -1;
    },

    /**
     * Gets an item at the specified index.
     * @param index
     * @returns {*} the item, or undefined if there is no item at the specified index
     * @public
     */
    get: function( index ) {
      return this._array[ index ];
    },

    /**
     * Gets the index of a specified item.
     * @param item
     * @returns {*} -1 if item is not in the array
     * @public
     */
    indexOf: function( item ) {
      return this._array.indexOf( item );
    },

    /**
     * Removes all items from the array.
     * @public
     */
    clear: function() {
      var copy = this._array.slice( 0 );
      for ( var i = 0; i < copy.length; i++ ) {
        this.remove( copy[ i ] );
      }
    },

    /**
     * Applies a callback function to each item in the array
     * @param callback function(item)
     * @public
     */
    forEach: function( callback ) {
      this._array.slice().forEach( callback ); // do this on a copy of the array, in case callbacks involve array modification
    },

    /**
     * Maps the values in this ObservableArray using the specified function, and returns a new ObservableArray for chaining.
     * @param mapFunction
     * @returns {axon.ObservableArray}
     * @public
     */
    map: function( mapFunction ) {
      return new axon.ObservableArray( this._array.map( mapFunction ) );
    },

    /**
     * Filters the values in this ObservableArray using the predicate function, and returns a new ObservableArray for chaining.
     * @param mapFunction
     * @returns {axon.ObservableArray}
     * @public
     */
    filter: function( mapFunction ) {
      return new axon.ObservableArray( this._array.filter( mapFunction ) );
    },

    /**
     * Starting with the initial value, combine values from this ObservableArray to come up with a composite result.
     * Same as foldLeft.  In underscore this is called _.reduce aka _.foldl or _.inject
     * @param value
     * @param combiner
     * @returns {*}
     * @public
     */
    reduce: function( value, combiner ) {
      for ( var i = 0; i < this._array.length; i++ ) {
        value = combiner( value, this._array[ i ] );
      }
      return value;
    },

    /**
     * Return the underlying array
     * @returns {*|Array}
     * @public
     */
    getArray: function() {
      return this._array;
    }
  } );
} );<|endoftext|>


<commit_before>'use strict';

/**
 * @ngdoc function
 * @name ng.$exceptionHandler
 * @requires $log
 *
 * @description
 * Any uncaught exception in angular expressions is delegated to this service.
 * The default implementation simply delegates to `$log.error` which logs it into
 * the browser console.
 *
 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
 *
 * @param {Error} exception Exception associated with the error.
 * @param {string=} cause optional information about the context in which
 *       the error was thrown.
 *
 */
function $ExceptionHandlerProvider() {
  this.$get = ['$log', function($log){
    return function(exception, cause) {
      $log.error.apply($log, arguments);
    };
  }];
}
<commit_msg>style(exceptionHandler): add ws<commit_after>'use strict';

/**
 * @ngdoc function
 * @name ng.$exceptionHandler
 * @requires $log
 *
 * @description
 * Any uncaught exception in angular expressions is delegated to this service.
 * The default implementation simply delegates to `$log.error` which logs it into
 * the browser console.
 *
 * In unit tests, if `angular-mocks.js` is loaded, this service is overridden by
 * {@link ngMock.$exceptionHandler mock $exceptionHandler} which aids in testing.
 *
 * @param {Error} exception Exception associated with the error.
 * @param {string=} cause optional information about the context in which
 *       the error was thrown.
 *
 */
function $ExceptionHandlerProvider() {
  this.$get = ['$log', function($log) {
    return function(exception, cause) {
      $log.error.apply($log, arguments);
    };
  }];
}
<|endoftext|>


<commit_before>/**
 * Action module.js
 */

(function($, OC, app){

    // elimination of dependence this action object
    if(typeof app.action.sort !== 'object')
        app.action.sort = {};

    // alias of app.action.module
    var o = app.action.sort;

    /**
     * button for sorting columns grid
     * @type {{}}
     */
    o.icoSort = {};

    /**
     * button for filter columns grid
     * @type {{}}
     */
    o.icoFilter = {};

    o.init = function(){

        o.icoSort = {
            id: app.select('#ganttsort_id'),
            task: app.select('#ganttsort_task'),
            start: app.select('#ganttsort_start'),
            resource: app.select('#ganttsort_resource')
        };

        o.icoFilter = {
            task: app.select('#ganttfilter_task'),
            resource: app.select('#ganttfilter_resource')
        };
        o.icoSort.id.direction = false;
        o.icoSort.id.addEventListener('click', o.onSortById, false);
        o.icoSort.task.direction = false;
        o.icoSort.task.addEventListener('click', o.onSortByTask, false);
        o.icoSort.start.direction = false;
        o.icoSort.start.addEventListener('click', o.onSortByStart, false);
        o.icoSort.resource.direction = false;
        o.icoSort.resource.addEventListener('click', o.onSortByResource, false);

        o.icoFilter.task.addEventListener('click', o.onFilterForTask, false);
        o.icoFilter.resource.addEventListener('click', o.onFilterForResource, false);

        o.applyStyle();
    };

    o.applyStyle = function(){
        o.icoSort.id.style.width = '80px';
        o.icoSort.task.style.width = '15px';
        o.icoSort.start.style.width = '245px';
        o.icoSort.resource.style.width = '15px';

        o.icoFilter.task.style.width = '112px';
        o.icoFilter.resource.style.width = '90px';
    };

    /**
     * Sorted Event By Id
     * @param event
     */
    o.onSortById = function(event){
        o.icoSort.id.direction = !o.icoSort.id.direction;
        gantt.sort(sortById);
    };

    function sortById(task1, task2){
        task1 = task1.id;
        task2 = task2.id;

        if (o.icoSort.id.direction){
            return task1 > task2 ? 1 : (task1 < task2 ? -1 : 0);
        } else {
            return task1 > task2 ? -1 : (task1 < task2 ? 1 : 0);
        }
    }

    /**
     * Sorted Event By Task
     * @param event
     */
    o.onSortByTask = function(event){
        o.icoSort.task.direction = !o.icoSort.task.direction;
        gantt.sort(sortByTask);
    };

    function sortByTask(task1, task2){
        task1 = task1.text;
        task2 = task2.text;

        if (o.icoSort.task.direction){
            return task1 > task2 ? 1 : (task1 < task2 ? -1 : 0);
        } else {
            return task1 > task2 ? -1 : (task1 < task2 ? 1 : 0);
        }
    }

    /**
     * Sorted Event By Start
     * @param event
     */
    o.onSortByStart = function(event){
        o.icoSort.start.direction = !o.icoSort.start.direction;
        gantt.sort(sortByStart);
    };

    function sortByStart(task1, task2){
        task1 = task1.start_date;
        task2 = task2.start_date;

        console.log(task1);
        if (o.icoSort.start.direction){
            return task1 > task2 ? 1 : (task1 < task2 ? -1 : 0);
        } else {
            return task1 > task2 ? -1 : (task1 < task2 ? 1 : 0);
        }
    }

    /**
     * Sorted Event By Resource
     * @param event
     */
    o.onSortByResource = function(event){
        o.icoSort.resource.direction = !o.icoSort.resource.direction;
        gantt.sort(sortByResource);
    };

    function sortByResource(task1, task2){
        task1 = task1.users;
        task2 = task2.users;

        if (o.icoSort.resource.direction){
            return task1 > task2 ? 1 : (task1 < task2 ? -1 : 0);
        } else {
            return task1 > task2 ? -1 : (task1 < task2 ? 1 : 0);
        }
    }

    /**
     * Filter Event For Task
     * @param event
     */
    o.onFilterForTask = function(event){

        var div = document.createElement('div');
        div.innerHTML = '
Filter
';

        var popup = app.action.lightbox.showPopup(o.icoFilter.task, div);

        console.log(o.icoFilter.task);
    };

    /**
     * Filter Event For Resource
     * @param event
     */
    o.onFilterForResource = function(event){

    };

})(jQuery, OC, app);
<commit_msg>build<commit_after>/**
 * Action module.js
 */

(function($, OC, app){

    // elimination of dependence this action object
    if(typeof app.action.sort !== 'object')
        app.action.sort = {};

    // alias of app.action.module
    var o = app.action.sort;

    /**
     * button for sorting columns grid
     * @type {{}}
     */
    o.icoSort = {};

    /**
     * button for filter columns grid
     * @type {{}}
     */
    o.icoFilter = {};

    o.init = function(){

        o.icoSort = {
            id: app.select('#ganttsort_id'),
            task: app.select('#ganttsort_task'),
            start: app.select('#ganttsort_start'),
            resource: app.select('#ganttsort_resource')
        };

        o.icoFilter = {
            task: app.select('#ganttfilter_task'),
            resource: app.select('#ganttfilter_resource')
        };
        o.icoSort.id.direction = false;
        o.icoSort.id.addEventListener('click', o.onSortById, false);
        o.icoSort.task.direction = false;
        o.icoSort.task.addEventListener('click', o.onSortByTask, false);
        o.icoSort.start.direction = false;
        o.icoSort.start.addEventListener('click', o.onSortByStart, false);
        o.icoSort.resource.direction = false;
        o.icoSort.resource.addEventListener('click', o.onSortByResource, false);

        o.icoFilter.task.addEventListener('click', o.onFilterForTask, false);
        o.icoFilter.resource.addEventListener('click', o.onFilterForResource, false);

        o.applyStyle();
    };

    o.applyStyle = function(){
        o.icoSort.id.style.width = '80px';
        o.icoSort.task.style.width = '15px';
        o.icoSort.start.style.width = '245px';
        o.icoSort.resource.style.width = '15px';

        o.icoFilter.task.style.width = '112px';
        o.icoFilter.resource.style.width = '90px';
    };

    /**
     * Sorted Event By Id
     * @param event
     */
    o.onSortById = function(event){
        o.icoSort.id.direction = !o.icoSort.id.direction;
        gantt.sort(sortById);
    };

    function sortById(task1, task2){
        task1 = task1.id;
        task2 = task2.id;

        if (o.icoSort.id.direction){
            return task1 > task2 ? 1 : (task1 < task2 ? -1 : 0);
        } else {
            return task1 > task2 ? -1 : (task1 < task2 ? 1 : 0);
        }
    }

    /**
     * Sorted Event By Task
     * @param event
     */
    o.onSortByTask = function(event){
        o.icoSort.task.direction = !o.icoSort.task.direction;
        gantt.sort(sortByTask);
    };

    function sortByTask(task1, task2){
        task1 = task1.text;
        task2 = task2.text;

        if (o.icoSort.task.direction){
            return task1 > task2 ? 1 : (task1 < task2 ? -1 : 0);
        } else {
            return task1 > task2 ? -1 : (task1 < task2 ? 1 : 0);
        }
    }

    /**
     * Sorted Event By Start
     * @param event
     */
    o.onSortByStart = function(event){
        o.icoSort.start.direction = !o.icoSort.start.direction;
        gantt.sort(sortByStart);
    };

    function sortByStart(task1, task2){
        task1 = task1.start_date;
        task2 = task2.start_date;

        console.log(task1);
        if (o.icoSort.start.direction){
            return task1 > task2 ? 1 : (task1 < task2 ? -1 : 0);
        } else {
            return task1 > task2 ? -1 : (task1 < task2 ? 1 : 0);
        }
    }

    /**
     * Sorted Event By Resource
     * @param event
     */
    o.onSortByResource = function(event){
        o.icoSort.resource.direction = !o.icoSort.resource.direction;
        gantt.sort(sortByResource);
    };

    function sortByResource(task1, task2){
        task1 = task1.users;
        task2 = task2.users;

        if (o.icoSort.resource.direction){
            return task1 > task2 ? 1 : (task1 < task2 ? -1 : 0);
        } else {
            return task1 > task2 ? -1 : (task1 < task2 ? 1 : 0);
        }
    }

    /**
     * Filter Event For Task
     * @param event
     */
    o.onFilterForTask = function(event){

        var div = document.createElement('div'),
            inner = '
Filter by task groups or tasks
';

        inner += '
<input id="gantt_filter_name" type="text" placeholder="Enter passphrase to be part of task name">
';
        inner += '
and / or
';
        inner += '
<input id="gantt_filter_group" type="text" placeholder="Enter passphrase to be part of task group">
';

        div.innerHTML = inner;

        var popup = app.action.lightbox.showPopup(o.icoFilter.task, div);
        popup.style.width = '350px';
        popup.style.zIndex = '999';
        popup.style.left = '110px';
    };

    /**
     * Filter Event For Resource
     * @param event
     */
    o.onFilterForResource = function(event){

        var div = document.createElement('div'),
            inner = '
Filter by task groups or resource
';

        inner += '
<input id="gantt_filter_resource" type="text" placeholder="Enter passphrase to be part of task name">
';

        div.innerHTML = inner;

        var popup = app.action.lightbox.showPopup(o.icoFilter.task, div);
        popup.style.width = '350px';
        popup.style.zIndex = '999';
        popup.style.left = '490px';
    };

})(jQuery, OC, app);
<|endoftext|>


<commit_before>/*
 * @license MIT License (see license.txt)
 */

'use strict';

function SwiftClick (contextEl)
{
    // if SwiftClick has already been initialised on this element then return the instance that's already in the Dictionary.
    if (typeof SwiftClick.swiftDictionary[contextEl] !== 'undefined') return SwiftClick.swiftDictionary[contextEl];

    // add this instance of SwiftClick to the dictionary using the contextEl as the key.
    SwiftClick.swiftDictionary[contextEl] = this;

    this.options =
    {
        elements: {a:'a', div:'div', span:'span', button:'button'},
        minTouchDrift: 4,
        maxTouchDrift: 16,
        useCssParser: false
    };

        var _self                           = this;
        var _swiftContextEl                 = contextEl;
        var _swiftContextElOriginalClick    = _swiftContextEl.onclick;
        var _currentlyTrackingTouch         = false;
        var _touchStartPoint                = {x:0, y:0};
        var _scrollStartPoint               = {x:0, y:0};
        var _clickedAlready                 = false;

    // SwiftClick is only initialised if both touch and orientationchange are supported.
    if ('onorientationchange' in window && 'ontouchstart' in window)
    {
        init();
    }

    function init ()
    {
        // check if the swift el already has a click handler and if so hijack it so it get's fired after SwiftClick's, instead of beforehand.
        if (typeof _swiftContextElOriginalClick === 'function')
        {
            _swiftContextEl.addEventListener('click', hijackedSwiftElClickHandler, false);
            _swiftContextEl.onclick = null;
        }

        _swiftContextEl.addEventListener('touchstart', touchStartHandler, false);
        _swiftContextEl.addEventListener('click', clickHandler, true);
    }

    function hijackedSwiftElClickHandler (event)
    {
        _swiftContextElOriginalClick(event);
    }

    function touchStartHandler (event)
    {
        var targetEl = event.target;
        var nodeName = targetEl.nodeName.toLowerCase();
        var touch = event.changedTouches[0];

        // don't synthesize an event if the node is not an acceptable type (the type isn't in the dictionary).
        if (typeof _self.options.elements[nodeName] === 'undefined')
        {
            return true;
        }

        // don't synthesize an event if we are already tracking an element.
        if (_currentlyTrackingTouch)
        {
            return true;
        }

        // check parents for 'swiftclick-ignore' class name.
        if (_self.options.useCssParser && checkIfElementShouldBeIgnored(targetEl))
        {
            _clickedAlready = false;
            return true;
        }

        event.stopPropagation();

        _currentlyTrackingTouch = true;

        // store touchstart positions so we can check for changes later (within touchend handler).
        _touchStartPoint.x = touch.pageX;
        _touchStartPoint.y = touch.pageY;
        _scrollStartPoint = getScrollPoint();

        // only add the 'touchend' listener now that we know the element should be tracked.
        targetEl.removeEventListener('touchend', touchEndHandler, false);
        targetEl.addEventListener('touchend', touchEndHandler, false);
    }

    function touchEndHandler (event)
    {
        var targetEl = event.target;
        var touchend = event.changedTouches[0];

        targetEl.removeEventListener('touchend', touchEndHandler, false);

        _currentlyTrackingTouch = false;

        // don't synthesize a click event if the touchpoint position has drifted significantly, as the user is not trying to click.
        if (hasTouchDriftedTooFar(touchend))
        {
            return true;
        }

        // prevent default actions and create a synthetic click event before returning false.
        event.stopPropagation();
        event.preventDefault();

        _clickedAlready = false;

        targetEl.focus();
        synthesizeClickEvent(targetEl, touchend);

        // return false in order to surpress the regular click event.
        return false;
    }

    function clickHandler (event)
    {
        var targetEl = event.target;
        var nodeName = targetEl.nodeName.toLowerCase();

        if (typeof _self.options.elements[nodeName] !== 'undefined')
        {
            if (_clickedAlready)
            {
                _clickedAlready = false;

                event.stopPropagation();
                event.preventDefault();
                return false;
            }

            _clickedAlready = true;
        }
    }

    function synthesizeClickEvent (el, touchend)
    {
        var clickEvent = document.createEvent('MouseEvents');
        clickEvent.initMouseEvent('click', true, true, window, 1, touchend.screenX, touchend.screenY, touchend.clientX, touchend.clientY, false, false, false, false, 0, null);

        el.dispatchEvent(clickEvent);
    }

    function getScrollPoint ()
    {
        var scrollPoint =
        {
            x : window.pageXOffset ||
                document.body.scrollLeft ||
                document.documentElement.scrollLeft ||
                0,
            y : window.pageYOffset ||
                document.body.scrollTop ||
                document.documentElement.scrollTop ||
                0
        };

        return scrollPoint;
    }

    function checkIfElementShouldBeIgnored (el)
    {
        var classToIgnore = 'swiftclick-ignore';
        var classToForceClick = 'swiftclick-force';
        var parentEl = el.parentNode;
        var shouldIgnoreElement = false;

        // ignore the target el and return early if it has the 'swiftclick-ignore' class.
        if (hasClass(el, classToIgnore))
        {
            return true;
        }

        // don't ignore the target el and return early if it has the 'swiftclick-force' class.
        if (hasClass(el, classToForceClick))
        {
            return shouldIgnoreElement;
        }

        // the topmost element has been reached.
        if (parentEl === null)
        {
            return shouldIgnoreElement;
        }

        // ignore the target el if one of its parents has the 'swiftclick-ignore' class.
        while (parentEl)
        {
            if (hasClass(parentEl, classToIgnore))
            {
                parentEl = null;
                shouldIgnoreElement = true;
            }
            else
            {
                parentEl = parentEl.parentNode;
            }
        }

        return shouldIgnoreElement;
    }

    function hasTouchDriftedTooFar (touchend)
    {
        var maxDrift = _self.options.maxTouchDrift;
        var scrollPoint = getScrollPoint();

        return  Math.abs(touchend.pageX - _touchStartPoint.x) > maxDrift ||
                Math.abs(touchend.pageY - _touchStartPoint.y) > maxDrift ||
                Math.abs(scrollPoint.x - _scrollStartPoint.x) > maxDrift ||
                Math.abs(scrollPoint.y - _scrollStartPoint.y) > maxDrift;
    }

    function hasClass (el, className) {

        var classExists = typeof el.className !== 'undefined' ? (' ' + el.className + ' ').indexOf(' ' + className + ' ') > -1 : false;

        return classExists;
    }
}

SwiftClick.swiftDictionary = {};

SwiftClick.prototype.setMaxTouchDrift = function (maxTouchDrift)
{
    if (typeof maxTouchDrift !== 'number')
    {
        throw new TypeError ('expected "maxTouchDrift" to be of type "number"');
    }

    if (maxTouchDrift < this.options.minTouchDrift)
    {
        maxTouchDrift = this.options.minTouchDrift;
    }

    this.options.maxTouchDrift = maxTouchDrift;
};

// add an array of node names (strings) for which swift clicks should be synthesized.
SwiftClick.prototype.addNodeNamesToTrack = function (nodeNamesArray)
{
    var i = 0;
    var length = nodeNamesArray.length;
    var currentNodeName;

    for (i; i < length; i++)
    {
        if (typeof nodeNamesArray[i] !== 'string')
        {
            throw new TypeError ('all values within the "nodeNames" array must be of type "string"');
        }

        currentNodeName = nodeNamesArray[i].toLowerCase();
        this.options.elements[currentNodeName] = currentNodeName;
    }
};

SwiftClick.prototype.replaceNodeNamesToTrack = function (nodeNamesArray)
{
    this.options.elements = {};
    this.addNodeNamesToTrack(nodeNamesArray);
};

SwiftClick.prototype.useCssParser = function (useParser)
{
    this.options.useCssParser = useParser;
};

// use a basic implementation of the composition pattern in order to create new instances of SwiftClick.
SwiftClick.attach = function (contextEl)
{
    // if SwiftClick has already been initialised on this element then return the instance that's already in the Dictionary.
    if (typeof SwiftClick.swiftDictionary[contextEl] !== 'undefined')
    {
        return SwiftClick.swiftDictionary[contextEl];
    }

    return new SwiftClick(contextEl);
};

// check for AMD/Module support, otherwise define SwiftClick as a global variable.
if (typeof define !== 'undefined' && define.amd)
{
    // AMD. Register as an anonymous module.
    define (function()
    {
        return SwiftClick;
    });

}
else if (typeof module !== 'undefined' && module.exports)
{
    module.exports = SwiftClick;
}
else
{
    window.SwiftClick = SwiftClick;
}<commit_msg>Fix variable indentation<commit_after>/*
 * @license MIT License (see license.txt)
 */

'use strict';

function SwiftClick (contextEl)
{
    // if SwiftClick has already been initialised on this element then return the instance that's already in the Dictionary.
    if (typeof SwiftClick.swiftDictionary[contextEl] !== 'undefined') return SwiftClick.swiftDictionary[contextEl];

    // add this instance of SwiftClick to the dictionary using the contextEl as the key.
    SwiftClick.swiftDictionary[contextEl] = this;

    this.options =
    {
        elements: {a:'a', div:'div', span:'span', button:'button'},
        minTouchDrift: 4,
        maxTouchDrift: 16,
        useCssParser: false
    };

    var _self                           = this;
    var _swiftContextEl                 = contextEl;
    var _swiftContextElOriginalClick    = _swiftContextEl.onclick;
    var _currentlyTrackingTouch         = false;
    var _touchStartPoint                = {x:0, y:0};
    var _scrollStartPoint               = {x:0, y:0};
    var _clickedAlready                 = false;

    // SwiftClick is only initialised if both touch and orientationchange are supported.
    if ('onorientationchange' in window && 'ontouchstart' in window)
    {
        init();
    }

    function init ()
    {
        // check if the swift el already has a click handler and if so hijack it so it get's fired after SwiftClick's, instead of beforehand.
        if (typeof _swiftContextElOriginalClick === 'function')
        {
            _swiftContextEl.addEventListener('click', hijackedSwiftElClickHandler, false);
            _swiftContextEl.onclick = null;
        }

        _swiftContextEl.addEventListener('touchstart', touchStartHandler, false);
        _swiftContextEl.addEventListener('click', clickHandler, true);
    }

    function hijackedSwiftElClickHandler (event)
    {
        _swiftContextElOriginalClick(event);
    }

    function touchStartHandler (event)
    {
        var targetEl = event.target;
        var nodeName = targetEl.nodeName.toLowerCase();
        var touch = event.changedTouches[0];

        // don't synthesize an event if the node is not an acceptable type (the type isn't in the dictionary).
        if (typeof _self.options.elements[nodeName] === 'undefined')
        {
            return true;
        }

        // don't synthesize an event if we are already tracking an element.
        if (_currentlyTrackingTouch)
        {
            return true;
        }

        // check parents for 'swiftclick-ignore' class name.
        if (_self.options.useCssParser && checkIfElementShouldBeIgnored(targetEl))
        {
            _clickedAlready = false;
            return true;
        }

        event.stopPropagation();

        _currentlyTrackingTouch = true;

        // store touchstart positions so we can check for changes later (within touchend handler).
        _touchStartPoint.x = touch.pageX;
        _touchStartPoint.y = touch.pageY;
        _scrollStartPoint = getScrollPoint();

        // only add the 'touchend' listener now that we know the element should be tracked.
        targetEl.removeEventListener('touchend', touchEndHandler, false);
        targetEl.addEventListener('touchend', touchEndHandler, false);
    }

    function touchEndHandler (event)
    {
        var targetEl = event.target;
        var touchend = event.changedTouches[0];

        targetEl.removeEventListener('touchend', touchEndHandler, false);

        _currentlyTrackingTouch = false;

        // don't synthesize a click event if the touchpoint position has drifted significantly, as the user is not trying to click.
        if (hasTouchDriftedTooFar(touchend))
        {
            return true;
        }

        // prevent default actions and create a synthetic click event before returning false.
        event.stopPropagation();
        event.preventDefault();

        _clickedAlready = false;

        targetEl.focus();
        synthesizeClickEvent(targetEl, touchend);

        // return false in order to surpress the regular click event.
        return false;
    }

    function clickHandler (event)
    {
        var targetEl = event.target;
        var nodeName = targetEl.nodeName.toLowerCase();

        if (typeof _self.options.elements[nodeName] !== 'undefined')
        {
            if (_clickedAlready)
            {
                _clickedAlready = false;

                event.stopPropagation();
                event.preventDefault();
                return false;
            }

            _clickedAlready = true;
        }
    }

    function synthesizeClickEvent (el, touchend)
    {
        var clickEvent = document.createEvent('MouseEvents');
        clickEvent.initMouseEvent('click', true, true, window, 1, touchend.screenX, touchend.screenY, touchend.clientX, touchend.clientY, false, false, false, false, 0, null);

        el.dispatchEvent(clickEvent);
    }

    function getScrollPoint ()
    {
        var scrollPoint =
        {
            x : window.pageXOffset ||
                document.body.scrollLeft ||
                document.documentElement.scrollLeft ||
                0,
            y : window.pageYOffset ||
                document.body.scrollTop ||
                document.documentElement.scrollTop ||
                0
        };

        return scrollPoint;
    }

    function checkIfElementShouldBeIgnored (el)
    {
        var classToIgnore = 'swiftclick-ignore';
        var classToForceClick = 'swiftclick-force';
        var parentEl = el.parentNode;
        var shouldIgnoreElement = false;

        // ignore the target el and return early if it has the 'swiftclick-ignore' class.
        if (hasClass(el, classToIgnore))
        {
            return true;
        }

        // don't ignore the target el and return early if it has the 'swiftclick-force' class.
        if (hasClass(el, classToForceClick))
        {
            return shouldIgnoreElement;
        }

        // the topmost element has been reached.
        if (parentEl === null)
        {
            return shouldIgnoreElement;
        }

        // ignore the target el if one of its parents has the 'swiftclick-ignore' class.
        while (parentEl)
        {
            if (hasClass(parentEl, classToIgnore))
            {
                parentEl = null;
                shouldIgnoreElement = true;
            }
            else
            {
                parentEl = parentEl.parentNode;
            }
        }

        return shouldIgnoreElement;
    }

    function hasTouchDriftedTooFar (touchend)
    {
        var maxDrift = _self.options.maxTouchDrift;
        var scrollPoint = getScrollPoint();

        return  Math.abs(touchend.pageX - _touchStartPoint.x) > maxDrift ||
                Math.abs(touchend.pageY - _touchStartPoint.y) > maxDrift ||
                Math.abs(scrollPoint.x - _scrollStartPoint.x) > maxDrift ||
                Math.abs(scrollPoint.y - _scrollStartPoint.y) > maxDrift;
    }

    function hasClass (el, className) {

        var classExists = typeof el.className !== 'undefined' ? (' ' + el.className + ' ').indexOf(' ' + className + ' ') > -1 : false;

        return classExists;
    }
}

SwiftClick.swiftDictionary = {};

SwiftClick.prototype.setMaxTouchDrift = function (maxTouchDrift)
{
    if (typeof maxTouchDrift !== 'number')
    {
        throw new TypeError ('expected "maxTouchDrift" to be of type "number"');
    }

    if (maxTouchDrift < this.options.minTouchDrift)
    {
        maxTouchDrift = this.options.minTouchDrift;
    }

    this.options.maxTouchDrift = maxTouchDrift;
};

// add an array of node names (strings) for which swift clicks should be synthesized.
SwiftClick.prototype.addNodeNamesToTrack = function (nodeNamesArray)
{
    var i = 0;
    var length = nodeNamesArray.length;
    var currentNodeName;

    for (i; i < length; i++)
    {
        if (typeof nodeNamesArray[i] !== 'string')
        {
            throw new TypeError ('all values within the "nodeNames" array must be of type "string"');
        }

        currentNodeName = nodeNamesArray[i].toLowerCase();
        this.options.elements[currentNodeName] = currentNodeName;
    }
};

SwiftClick.prototype.replaceNodeNamesToTrack = function (nodeNamesArray)
{
    this.options.elements = {};
    this.addNodeNamesToTrack(nodeNamesArray);
};

SwiftClick.prototype.useCssParser = function (useParser)
{
    this.options.useCssParser = useParser;
};

// use a basic implementation of the composition pattern in order to create new instances of SwiftClick.
SwiftClick.attach = function (contextEl)
{
    // if SwiftClick has already been initialised on this element then return the instance that's already in the Dictionary.
    if (typeof SwiftClick.swiftDictionary[contextEl] !== 'undefined')
    {
        return SwiftClick.swiftDictionary[contextEl];
    }

    return new SwiftClick(contextEl);
};

// check for AMD/Module support, otherwise define SwiftClick as a global variable.
if (typeof define !== 'undefined' && define.amd)
{
    // AMD. Register as an anonymous module.
    define (function()
    {
        return SwiftClick;
    });

}
else if (typeof module !== 'undefined' && module.exports)
{
    module.exports = SwiftClick;
}
else
{
    window.SwiftClick = SwiftClick;
}<|endoftext|>


<commit_before>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
goog.require('goog.bind');

cr.define('apps_dev_tool', function() {
  'use strict';

  /** const*/ var AppsDevTool = apps_dev_tool.AppsDevTool;

  /**
   * Hides the present overlay showing.
   */
  var hideOverlay = function() {
    AppsDevTool.showOverlay(null);
  };

  /**
   * BehaviorWindow class
   * Encapsulated handling of the 'Behavior' overlay page.
   * @constructor
   */
  function BehaviorWindow() {}

  cr.addSingletonGetter(BehaviorWindow);

  BehaviorWindow.prototype = {
    initializePage: function() {
      var overlay = $('behaviorOverlay');
      cr.ui.overlay.setupOverlay(overlay);
      cr.ui.overlay.globalInitialization();
      $('close-behavior-overlay').addEventListener('click',
          hideOverlay.bind(this));
    },
  };

  /**
   * Enum for tab names. Used to show and hide the different information.
   * Only one should be shown at a time.
   * @enum {string}
   * @const
   */
  BehaviorWindow.TabIds = {
    HISTORY_MODE: 'history-mode-tab',
    STREAM_MODE: 'stream-mode-tab'
  };

  /**
   * Maximum number of notable calls to display on the UI.
   * @private {number}
   * @const
   */
  BehaviorWindow.MAX_NOTABLE_ = 10;

  /**
   * Maximum line length for activity information on the UI.
   * @private {number}
   * @const
   */
  BehaviorWindow.MAX_LINE_LENGTH_ = 80;

  /**
   * Name of tab that is currently being displayed.
   * @private {!watchdog.BehaviorWindow.TabIds}
   */
  BehaviorWindow.currentTab_ = BehaviorWindow.TabIds.HISTORY_MODE;

  /**
   * Id of the currently selected extension.
   * @private {string}
   */
  BehaviorWindow.currentExtensionId_ = '';

  /**
   * Filter to use when displaying activity info. See activityLogPrivate API
   * for details of valid filters.
   * @private {!ActivityFilter}
   */
  BehaviorWindow.activityFilter_ = /** @type {!ActivityFilter} */ ({
    activityType: 'any',
    extensionId: '',
    apiCall: null,
    pageUrl: null,
    argUrl: null
  });

  // Export
  return {
    BehaviorWindow: BehaviorWindow,
  };
});
<commit_msg>Correct code<commit_after>// Copyright 2014 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
goog.require('goog.bind');

cr.define('apps_dev_tool', function() {
  'use strict';

  /** const*/ var AppsDevTool = apps_dev_tool.AppsDevTool;

  /**
   * Hides the present overlay showing.
   */
  var hideOverlay = function() {
    AppsDevTool.showOverlay(null);
  };

  /**
   * BehaviorWindow class
   * Encapsulated handling of the 'Behavior' overlay page.
   * @constructor
   */
  function BehaviorWindow() {}

  cr.addSingletonGetter(BehaviorWindow);

  BehaviorWindow.prototype = {
    initializePage: function() {
      var overlay = $('behaviorOverlay');
      cr.ui.overlay.setupOverlay(overlay);
      cr.ui.overlay.globalInitialization();
      $('close-behavior-overlay').addEventListener(
          'click', hideOverlay.bind(this));
    }
  };

  /**
   * Enum for tab names. Used to show and hide the different information.
   * Only one should be shown at a time.
   * @enum {string}
   * @const
   */
  BehaviorWindow.TabIds = {
    HISTORY_MODE: 'history-mode-tab',
    STREAM_MODE: 'stream-mode-tab'
  };

  /**
   * Maximum number of notable calls to display on the UI.
   * @private {number}
   * @const
   */
  BehaviorWindow.MAX_NOTABLE_ = 10;

  /**
   * Maximum line length for activity information on the UI.
   * @private {number}
   * @const
   */
  BehaviorWindow.MAX_LINE_LENGTH_ = 80;

  /**
   * Name of tab that is currently being displayed.
   * @private {!watchdog.BehaviorWindow.TabIds}
   */
  BehaviorWindow.currentTab_ = BehaviorWindow.TabIds.HISTORY_MODE;

  /**
   * Id of the currently selected extension.
   * @private {string}
   */
  BehaviorWindow.currentExtensionId_ = '';

  /**
   * Filter to use when displaying activity info. See activityLogPrivate API
   * for details of valid filters.
   * @private {!ActivityFilter}
   */
  BehaviorWindow.activityFilter_ = /** @type {!ActivityFilter} */ ({
    activityType: 'any',
    extensionId: '',
    apiCall: null,
    pageUrl: null,
    argUrl: null
  });

  // Export
  return {
    BehaviorWindow: BehaviorWindow
  };
});
<|endoftext|>


<commit_before>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Path parsing and manipulation helpers
//>>label: Path Helpers
//>>group: Navigation
define([
	"jquery",
	"./../jquery.mobile.ns" ], function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");

(function( $, undefined ) {
		var path, documentBase, $base, dialogHashKey = "&ui-state=dialog";

		$.mobile.path = path = {
			uiStateKey: "&ui-state",

			// This scary looking regular expression parses an absolute URL or its relative
			// variants (protocol, site, document, query, and hash), into the various
			// components (protocol, host, path, query, fragment, etc that make up the
			// URL as well as some other commonly used sub-parts. When used with RegExp.exec()
			// or String.match, it parses the URL into a results array that looks like this:
			//
			//     [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
			//     [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
			//     [2]: http://jblas:password@mycompany.com:8080/mail/inbox
			//     [3]: http://jblas:password@mycompany.com:8080
			//     [4]: http:
			//     [5]: //
			//     [6]: jblas:password@mycompany.com:8080
			//     [7]: jblas:password
			//     [8]: jblas
			//     [9]: password
			//    [10]: mycompany.com:8080
			//    [11]: mycompany.com
			//    [12]: 8080
			//    [13]: /mail/inbox
			//    [14]: /mail/
			//    [15]: inbox
			//    [16]: ?msg=1234&type=unread
			//    [17]: #msg-content
			//
			urlParseRE: /^\s*(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,

			// Abstraction to address xss (Issue #4787) by removing the authority in
			// browsers that auto	decode it. All references to location.href should be
			// replaced with a call to this method so that it can be dealt with properly here
			getLocation: function( url ) {
				var uri = url ? this.parseUrl( url ) : location,
					hash = this.parseUrl( url || location.href ).hash;

				// mimic the browser with an empty string when the hash is empty
				hash = hash === "#" ? "" : hash;

				// Make sure to parse the url or the location object for the hash because using location.hash
				// is autodecoded in firefox, the rest of the url should be from the object (location unless
				// we're testing) to avoid the inclusion of the authority
				return uri.protocol + "//" + uri.host + uri.pathname + uri.search + hash;
			},

			parseLocation: function() {
				return this.parseUrl( this.getLocation() );
			},

			//Parse a URL into a structure that allows easy access to
			//all of the URL components by name.
			parseUrl: function( url ) {
				// If we're passed an object, we'll assume that it is
				// a parsed url object and just return it back to the caller.
				if ( $.type( url ) === "object" ) {
					return url;
				}

				var matches = path.urlParseRE.exec( url || "" ) || [];

					// Create an object that allows the caller to access the sub-matches
					// by name. Note that IE returns an empty string instead of undefined,
					// like all other browsers do, so we normalize everything so its consistent
					// no matter what browser we're running on.
					return {
						href:         matches[  0 ] || "",
						hrefNoHash:   matches[  1 ] || "",
						hrefNoSearch: matches[  2 ] || "",
						domain:       matches[  3 ] || "",
						protocol:     matches[  4 ] || "",
						doubleSlash:  matches[  5 ] || "",
						authority:    matches[  6 ] || "",
						username:     matches[  8 ] || "",
						password:     matches[  9 ] || "",
						host:         matches[ 10 ] || "",
						hostname:     matches[ 11 ] || "",
						port:         matches[ 12 ] || "",
						pathname:     matches[ 13 ] || "",
						directory:    matches[ 14 ] || "",
						filename:     matches[ 15 ] || "",
						search:       matches[ 16 ] || "",
						hash:         matches[ 17 ] || ""
					};
			},

			//Turn relPath into an asbolute path. absPath is
			//an optional absolute path which describes what
			//relPath is relative to.
			makePathAbsolute: function( relPath, absPath ) {
				if ( relPath && relPath.charAt( 0 ) === "/" ) {
					return relPath;
				}

				relPath = relPath || "";
				absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";

				var absStack = absPath ? absPath.split( "/" ) : [],
					relStack = relPath.split( "/" );
				for ( var i = 0; i < relStack.length; i++ ) {
					var d = relStack[ i ];
					switch ( d ) {
						case ".":
							break;
						case "..":
							if ( absStack.length ) {
								absStack.pop();
							}
							break;
						default:
							absStack.push( d );
							break;
					}
				}
				return "/" + absStack.join( "/" );
			},

			//Returns true if both urls have the same domain.
			isSameDomain: function( absUrl1, absUrl2 ) {
				return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
			},

			//Returns true for any relative variant.
			isRelativeUrl: function( url ) {
				// All relative Url variants have one thing in common, no protocol.
				return path.parseUrl( url ).protocol === "";
			},

			//Returns true for an absolute url.
			isAbsoluteUrl: function( url ) {
				return path.parseUrl( url ).protocol !== "";
			},

			//Turn the specified realtive URL into an absolute one. This function
			//can handle all relative variants (protocol, site, document, query, fragment).
			makeUrlAbsolute: function( relUrl, absUrl ) {
				if ( !path.isRelativeUrl( relUrl ) ) {
					return relUrl;
				}

				if ( absUrl === undefined ) {
					absUrl = this.documentBase;
				}

				var relObj = path.parseUrl( relUrl ),
					absObj = path.parseUrl( absUrl ),
					protocol = relObj.protocol || absObj.protocol,
					doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ),
					authority = relObj.authority || absObj.authority,
					hasPath = relObj.pathname !== "",
					pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
					search = relObj.search || ( !hasPath && absObj.search ) || "",
					hash = relObj.hash;

				return protocol + doubleSlash + authority + pathname + search + hash;
			},

			//Add search (aka query) params to the specified url.
			addSearchParams: function( url, params ) {
				var u = path.parseUrl( url ),
					p = ( typeof params === "object" ) ? $.param( params ) : params,
					s = u.search || "?";
				return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
			},

			convertUrlToDataUrl: function( absUrl ) {
				var u = path.parseUrl( absUrl );
				if ( path.isEmbeddedPage( u ) ) {
					// For embedded pages, remove the dialog hash key as in getFilePath(),
					// and remove otherwise the Data Url won't match the id of the embedded Page.
					return u.hash
						.split( dialogHashKey )[0]
						.replace( /^#/, "" )
						.replace( /\?.*$/, "" );
				} else if ( path.isSameDomain( u, this.documentBase ) ) {
					return u.hrefNoHash.replace( this.documentBase.domain, "" ).split( dialogHashKey )[0];
				}

				return window.decodeURIComponent(absUrl);
			},

			//get path from current hash, or from a file path
			get: function( newPath ) {
				if ( newPath === undefined ) {
					newPath = path.parseLocation().hash;
				}
				return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
			},

			//set location hash to path
			set: function( path ) {
				location.hash = path;
			},

			//test if a given url (string) is a path
			//NOTE might be exceptionally naive
			isPath: function( url ) {
				return ( /\// ).test( url );
			},

			//return a url path with the window's location protocol/hostname/pathname removed
			clean: function( url ) {
				return url.replace( this.documentBase.domain, "" );
			},

			//just return the url without an initial #
			stripHash: function( url ) {
				return url.replace( /^#/, "" );
			},

			stripQueryParams: function( url ) {
				return url.replace( /\?.*$/, "" );
			},

			//remove the preceding hash, any query params, and dialog notations
			cleanHash: function( hash ) {
				return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
			},

			isHashValid: function( hash ) {
				return ( /^#[^#]+$/ ).test( hash );
			},

			//check whether a url is referencing the same domain, or an external domain or different protocol
			//could be mailto, etc
			isExternal: function( url ) {
				var u = path.parseUrl( url );
				return u.protocol && u.domain !== this.documentUrl.domain ? true : false;
			},

			hasProtocol: function( url ) {
				return ( /^(:?\w+:)/ ).test( url );
			},

			isEmbeddedPage: function( url ) {
				var u = path.parseUrl( url );

				//if the path is absolute, then we need to compare the url against
				//both the this.documentUrl and the documentBase. The main reason for this
				//is that links embedded within external documents will refer to the
				//application document, whereas links embedded within the application
				//document will be resolved against the document base.
				if ( u.protocol !== "" ) {
					return ( !this.isPath(u.hash) && u.hash && ( u.hrefNoHash === this.documentUrl.hrefNoHash || ( this.documentBaseDiffers && u.hrefNoHash === this.documentBase.hrefNoHash ) ) );
				}
				return ( /^#/ ).test( u.href );
			},

			squash: function( url, resolutionUrl ) {
				var state, href, cleanedUrl, search, stateIndex,
					isPath = this.isPath( url ),
					uri = this.parseUrl( url ),
					preservedHash = uri.hash,
					uiState = "";

				// produce a url against which we can resole the provided path
				resolutionUrl = resolutionUrl || (path.isPath(url) ? path.getLocation() : path.getDocumentUrl());

				// If the url is anything but a simple string, remove any preceding hash
				// eg #foo/bar -> foo/bar
				//    #foo -> #foo
				cleanedUrl = isPath ? path.stripHash( url ) : url;

				// If the url is a full url with a hash check if the parsed hash is a path
				// if it is, strip the #, and use it otherwise continue without change
				cleanedUrl = path.isPath( uri.hash ) ? path.stripHash( uri.hash ) : cleanedUrl;

				// Split the UI State keys off the href
				stateIndex = cleanedUrl.indexOf( this.uiStateKey );

				// store the ui state keys for use
				if( stateIndex > -1 ){
					uiState = cleanedUrl.slice( stateIndex );
					cleanedUrl = cleanedUrl.slice( 0, stateIndex );
				}

				// make the cleanedUrl absolute relative to the resolution url
				href = path.makeUrlAbsolute( cleanedUrl, resolutionUrl );

				// grab the search from the resolved url since parsing from
				// the passed url may not yield the correct result
				search = this.parseUrl( href ).search;

				// TODO all this crap is terrible, clean it up
				if ( isPath ) {
					// Get a hash where possible and, as long as it's not a path
					// preserve it on the current url
					preservedHash = (uri.hash || path.parseLocation().hash);

					// reject the hash if it's a path or it's just a dialog key
					if( path.isPath( preservedHash ) || preservedHash.replace("#", "").indexOf( this.uiStateKey ) === 0) {
						preservedHash = "";
					}

					// Append the UI State keys where it exists and it's been removed
					// from the url
					if( uiState && preservedHash.indexOf( this.uiStateKey ) === -1){
						preservedHash += uiState;
					}

					// make sure that pound is on the front of the hash
					if( preservedHash.indexOf( "#" ) === -1 && preservedHash !== "" ){
						preservedHash = "#" + preservedHash;
					}

					// reconstruct each of the pieces with the new search string and hash
					href = path.parseUrl( href );
					href = href.protocol + "//" + href.host + href.pathname + search + preservedHash;
				} else {
					href += href.indexOf( "#" ) > -1 ? uiState : "#" + uiState;
				}

				return href;
			},

			isPreservableHash: function( hash ) {
				return hash.replace( "#", "" ).indexOf( this.uiStateKey ) === 0;
			}
		};

		path.documentUrl = path.parseLocation();

		$base = $( "head" ).find( "base" );

		path.documentBase = $base.length ?
			path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), path.documentUrl.href ) ) :
			path.documentUrl;

		path.documentBaseDiffers = (path.documentUrl.hrefNoHash !== path.documentBase.hrefNoHash);

		//return the original document url
		path.getDocumentUrl = function( asParsedObject ) {
			return asParsedObject ? $.extend( {}, path.documentUrl ) : path.documentUrl.href;
		};

		//return the original document base url
		path.getDocumentBase = function( asParsedObject ) {
			return asParsedObject ? $.extend( {}, path.documentBase ) : path.documentBase.href;
		};
})( jQuery );

//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<commit_msg>Navigation: Path: Do not append the preserved hash when going to a path, unless the path has such a hash<commit_after>//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
//>>description: Path parsing and manipulation helpers
//>>label: Path Helpers
//>>group: Navigation
define([
	"jquery",
	"./../jquery.mobile.ns" ], function( jQuery ) {
//>>excludeEnd("jqmBuildExclude");

(function( $, undefined ) {
		var path, documentBase, $base, dialogHashKey = "&ui-state=dialog";

		$.mobile.path = path = {
			uiStateKey: "&ui-state",

			// This scary looking regular expression parses an absolute URL or its relative
			// variants (protocol, site, document, query, and hash), into the various
			// components (protocol, host, path, query, fragment, etc that make up the
			// URL as well as some other commonly used sub-parts. When used with RegExp.exec()
			// or String.match, it parses the URL into a results array that looks like this:
			//
			//     [0]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread#msg-content
			//     [1]: http://jblas:password@mycompany.com:8080/mail/inbox?msg=1234&type=unread
			//     [2]: http://jblas:password@mycompany.com:8080/mail/inbox
			//     [3]: http://jblas:password@mycompany.com:8080
			//     [4]: http:
			//     [5]: //
			//     [6]: jblas:password@mycompany.com:8080
			//     [7]: jblas:password
			//     [8]: jblas
			//     [9]: password
			//    [10]: mycompany.com:8080
			//    [11]: mycompany.com
			//    [12]: 8080
			//    [13]: /mail/inbox
			//    [14]: /mail/
			//    [15]: inbox
			//    [16]: ?msg=1234&type=unread
			//    [17]: #msg-content
			//
			urlParseRE: /^\s*(((([^:\/#\?]+:)?(?:(\/\/)((?:(([^:@\/#\?]+)(?:\:([^:@\/#\?]+))?)@)?(([^:\/#\?\]\[]+|\[[^\/\]@#?]+\])(?:\:([0-9]+))?))?)?)?((\/?(?:[^\/\?#]+\/+)*)([^\?#]*)))?(\?[^#]+)?)(#.*)?/,

			// Abstraction to address xss (Issue #4787) by removing the authority in
			// browsers that auto	decode it. All references to location.href should be
			// replaced with a call to this method so that it can be dealt with properly here
			getLocation: function( url ) {
				var uri = url ? this.parseUrl( url ) : location,
					hash = this.parseUrl( url || location.href ).hash;

				// mimic the browser with an empty string when the hash is empty
				hash = hash === "#" ? "" : hash;

				// Make sure to parse the url or the location object for the hash because using location.hash
				// is autodecoded in firefox, the rest of the url should be from the object (location unless
				// we're testing) to avoid the inclusion of the authority
				return uri.protocol + "//" + uri.host + uri.pathname + uri.search + hash;
			},

			parseLocation: function() {
				return this.parseUrl( this.getLocation() );
			},

			//Parse a URL into a structure that allows easy access to
			//all of the URL components by name.
			parseUrl: function( url ) {
				// If we're passed an object, we'll assume that it is
				// a parsed url object and just return it back to the caller.
				if ( $.type( url ) === "object" ) {
					return url;
				}

				var matches = path.urlParseRE.exec( url || "" ) || [];

					// Create an object that allows the caller to access the sub-matches
					// by name. Note that IE returns an empty string instead of undefined,
					// like all other browsers do, so we normalize everything so its consistent
					// no matter what browser we're running on.
					return {
						href:         matches[  0 ] || "",
						hrefNoHash:   matches[  1 ] || "",
						hrefNoSearch: matches[  2 ] || "",
						domain:       matches[  3 ] || "",
						protocol:     matches[  4 ] || "",
						doubleSlash:  matches[  5 ] || "",
						authority:    matches[  6 ] || "",
						username:     matches[  8 ] || "",
						password:     matches[  9 ] || "",
						host:         matches[ 10 ] || "",
						hostname:     matches[ 11 ] || "",
						port:         matches[ 12 ] || "",
						pathname:     matches[ 13 ] || "",
						directory:    matches[ 14 ] || "",
						filename:     matches[ 15 ] || "",
						search:       matches[ 16 ] || "",
						hash:         matches[ 17 ] || ""
					};
			},

			//Turn relPath into an asbolute path. absPath is
			//an optional absolute path which describes what
			//relPath is relative to.
			makePathAbsolute: function( relPath, absPath ) {
				if ( relPath && relPath.charAt( 0 ) === "/" ) {
					return relPath;
				}

				relPath = relPath || "";
				absPath = absPath ? absPath.replace( /^\/|(\/[^\/]*|[^\/]+)$/g, "" ) : "";

				var absStack = absPath ? absPath.split( "/" ) : [],
					relStack = relPath.split( "/" );
				for ( var i = 0; i < relStack.length; i++ ) {
					var d = relStack[ i ];
					switch ( d ) {
						case ".":
							break;
						case "..":
							if ( absStack.length ) {
								absStack.pop();
							}
							break;
						default:
							absStack.push( d );
							break;
					}
				}
				return "/" + absStack.join( "/" );
			},

			//Returns true if both urls have the same domain.
			isSameDomain: function( absUrl1, absUrl2 ) {
				return path.parseUrl( absUrl1 ).domain === path.parseUrl( absUrl2 ).domain;
			},

			//Returns true for any relative variant.
			isRelativeUrl: function( url ) {
				// All relative Url variants have one thing in common, no protocol.
				return path.parseUrl( url ).protocol === "";
			},

			//Returns true for an absolute url.
			isAbsoluteUrl: function( url ) {
				return path.parseUrl( url ).protocol !== "";
			},

			//Turn the specified realtive URL into an absolute one. This function
			//can handle all relative variants (protocol, site, document, query, fragment).
			makeUrlAbsolute: function( relUrl, absUrl ) {
				if ( !path.isRelativeUrl( relUrl ) ) {
					return relUrl;
				}

				if ( absUrl === undefined ) {
					absUrl = this.documentBase;
				}

				var relObj = path.parseUrl( relUrl ),
					absObj = path.parseUrl( absUrl ),
					protocol = relObj.protocol || absObj.protocol,
					doubleSlash = relObj.protocol ? relObj.doubleSlash : ( relObj.doubleSlash || absObj.doubleSlash ),
					authority = relObj.authority || absObj.authority,
					hasPath = relObj.pathname !== "",
					pathname = path.makePathAbsolute( relObj.pathname || absObj.filename, absObj.pathname ),
					search = relObj.search || ( !hasPath && absObj.search ) || "",
					hash = relObj.hash;

				return protocol + doubleSlash + authority + pathname + search + hash;
			},

			//Add search (aka query) params to the specified url.
			addSearchParams: function( url, params ) {
				var u = path.parseUrl( url ),
					p = ( typeof params === "object" ) ? $.param( params ) : params,
					s = u.search || "?";
				return u.hrefNoSearch + s + ( s.charAt( s.length - 1 ) !== "?" ? "&" : "" ) + p + ( u.hash || "" );
			},

			convertUrlToDataUrl: function( absUrl ) {
				var u = path.parseUrl( absUrl );
				if ( path.isEmbeddedPage( u ) ) {
					// For embedded pages, remove the dialog hash key as in getFilePath(),
					// and remove otherwise the Data Url won't match the id of the embedded Page.
					return u.hash
						.split( dialogHashKey )[0]
						.replace( /^#/, "" )
						.replace( /\?.*$/, "" );
				} else if ( path.isSameDomain( u, this.documentBase ) ) {
					return u.hrefNoHash.replace( this.documentBase.domain, "" ).split( dialogHashKey )[0];
				}

				return window.decodeURIComponent(absUrl);
			},

			//get path from current hash, or from a file path
			get: function( newPath ) {
				if ( newPath === undefined ) {
					newPath = path.parseLocation().hash;
				}
				return path.stripHash( newPath ).replace( /[^\/]*\.[^\/*]+$/, '' );
			},

			//set location hash to path
			set: function( path ) {
				location.hash = path;
			},

			//test if a given url (string) is a path
			//NOTE might be exceptionally naive
			isPath: function( url ) {
				return ( /\// ).test( url );
			},

			//return a url path with the window's location protocol/hostname/pathname removed
			clean: function( url ) {
				return url.replace( this.documentBase.domain, "" );
			},

			//just return the url without an initial #
			stripHash: function( url ) {
				return url.replace( /^#/, "" );
			},

			stripQueryParams: function( url ) {
				return url.replace( /\?.*$/, "" );
			},

			//remove the preceding hash, any query params, and dialog notations
			cleanHash: function( hash ) {
				return path.stripHash( hash.replace( /\?.*$/, "" ).replace( dialogHashKey, "" ) );
			},

			isHashValid: function( hash ) {
				return ( /^#[^#]+$/ ).test( hash );
			},

			//check whether a url is referencing the same domain, or an external domain or different protocol
			//could be mailto, etc
			isExternal: function( url ) {
				var u = path.parseUrl( url );
				return u.protocol && u.domain !== this.documentUrl.domain ? true : false;
			},

			hasProtocol: function( url ) {
				return ( /^(:?\w+:)/ ).test( url );
			},

			isEmbeddedPage: function( url ) {
				var u = path.parseUrl( url );

				//if the path is absolute, then we need to compare the url against
				//both the this.documentUrl and the documentBase. The main reason for this
				//is that links embedded within external documents will refer to the
				//application document, whereas links embedded within the application
				//document will be resolved against the document base.
				if ( u.protocol !== "" ) {
					return ( !this.isPath(u.hash) && u.hash && ( u.hrefNoHash === this.documentUrl.hrefNoHash || ( this.documentBaseDiffers && u.hrefNoHash === this.documentBase.hrefNoHash ) ) );
				}
				return ( /^#/ ).test( u.href );
			},

			squash: function( url, resolutionUrl ) {
				var state, href, cleanedUrl, search, stateIndex,
					isPath = this.isPath( url ),
					uri = this.parseUrl( url ),
					preservedHash = uri.hash,
					uiState = "";

				// produce a url against which we can resole the provided path
				resolutionUrl = resolutionUrl || (path.isPath(url) ? path.getLocation() : path.getDocumentUrl());

				// If the url is anything but a simple string, remove any preceding hash
				// eg #foo/bar -> foo/bar
				//    #foo -> #foo
				cleanedUrl = isPath ? path.stripHash( url ) : url;

				// If the url is a full url with a hash check if the parsed hash is a path
				// if it is, strip the #, and use it otherwise continue without change
				cleanedUrl = path.isPath( uri.hash ) ? path.stripHash( uri.hash ) : cleanedUrl;

				// Split the UI State keys off the href
				stateIndex = cleanedUrl.indexOf( this.uiStateKey );

				// store the ui state keys for use
				if( stateIndex > -1 ){
					uiState = cleanedUrl.slice( stateIndex );
					cleanedUrl = cleanedUrl.slice( 0, stateIndex );
				}

				// make the cleanedUrl absolute relative to the resolution url
				href = path.makeUrlAbsolute( cleanedUrl, resolutionUrl );

				// grab the search from the resolved url since parsing from
				// the passed url may not yield the correct result
				search = this.parseUrl( href ).search;

				// TODO all this crap is terrible, clean it up
				if ( isPath ) {
					// reject the hash if it's a path or it's just a dialog key
					if( path.isPath( preservedHash ) || preservedHash.replace("#", "").indexOf( this.uiStateKey ) === 0) {
						preservedHash = "";
					}

					// Append the UI State keys where it exists and it's been removed
					// from the url
					if( uiState && preservedHash.indexOf( this.uiStateKey ) === -1){
						preservedHash += uiState;
					}

					// make sure that pound is on the front of the hash
					if( preservedHash.indexOf( "#" ) === -1 && preservedHash !== "" ){
						preservedHash = "#" + preservedHash;
					}

					// reconstruct each of the pieces with the new search string and hash
					href = path.parseUrl( href );
					href = href.protocol + "//" + href.host + href.pathname + search + preservedHash;
				} else {
					href += href.indexOf( "#" ) > -1 ? uiState : "#" + uiState;
				}

				return href;
			},

			isPreservableHash: function( hash ) {
				return hash.replace( "#", "" ).indexOf( this.uiStateKey ) === 0;
			}
		};

		path.documentUrl = path.parseLocation();

		$base = $( "head" ).find( "base" );

		path.documentBase = $base.length ?
			path.parseUrl( path.makeUrlAbsolute( $base.attr( "href" ), path.documentUrl.href ) ) :
			path.documentUrl;

		path.documentBaseDiffers = (path.documentUrl.hrefNoHash !== path.documentBase.hrefNoHash);

		//return the original document url
		path.getDocumentUrl = function( asParsedObject ) {
			return asParsedObject ? $.extend( {}, path.documentUrl ) : path.documentUrl.href;
		};

		//return the original document base url
		path.getDocumentBase = function( asParsedObject ) {
			return asParsedObject ? $.extend( {}, path.documentBase ) : path.documentBase.href;
		};
})( jQuery );

//>>excludeStart("jqmBuildExclude", pragmas.jqmBuildExclude);
});
//>>excludeEnd("jqmBuildExclude");
<|endoftext|>