<commit_before>'use strict';

import $ from 'jquery';
import { Plugin } from './foundation.core.plugin';
import { onLoad, GetYoDigits } from './foundation.core.utils';
import { Keyboard } from './foundation.util.keyboard';

/**
 * Accordion module.
 * @module foundation.accordion
 * @requires foundation.util.keyboard
 */

class Accordion extends Plugin {
  /**
   * Creates a new instance of an accordion.
   * @class
   * @name Accordion
   * @fires Accordion#init
   * @param {jQuery} element - jQuery object to make into an accordion.
   * @param {Object} options - a plain object with settings to override the default options.
   */
  _setup(element, options) {
    this.$element = element;
    this.options = $.extend({}, Accordion.defaults, this.$element.data(), options);

    this.className = 'Accordion'; // ie9 back compat
    this._init();

    Keyboard.register('Accordion', {
      'ENTER': 'toggle',
      'SPACE': 'toggle',
      'ARROW_DOWN': 'next',
      'ARROW_UP': 'previous'
    });
  }

  /**
   * Initializes the accordion by animating the preset active pane(s).
   * @private
   */
  _init() {
    this.$element.attr('role', 'tablist');
    this.$tabs = this.$element.children('[data-accordion-item]');

    this.$tabs.each(function(idx, el) {
      var $el = $(el),
          $content = $el.children('[data-tab-content]'),
          id = $content[0].id || GetYoDigits(6, 'accordion'),
          linkId = (el.id) ? `${el.id}-label` : `${id}-label`;

      $el.find('a:first').attr({
        'aria-controls': id,
        'role': 'tab',
        'id': linkId,
        'aria-expanded': false,
        'aria-selected': false
      });

      $content.attr({'role': 'tabpanel', 'aria-labelledby': linkId, 'aria-hidden': true, 'id': id});
    });

    var $initActive = this.$element.find('.is-active').children('[data-tab-content]');
    this.firstTimeInit = true;
    if ($initActive.length) {
      // Save up the initial hash to return to it later when going back in history
      this._initialAnchor = $initActive.prev('a').attr('href');

      this.down($initActive, this.firstTimeInit);
      this.firstTimeInit = false;
    }

    this._checkDeepLink = () => {
      var anchor = window.location.hash;

      // if there is no anchor, return to the initial panel
      if (!anchor.length && this._initialAnchor) {
        anchor = this._initialAnchor;
      }

      //need a hash and a relevant anchor in this tabset
      if(anchor.length) {
        var $link = this.$element.find('[href$="'+anchor+'"]'),
        $anchor = $(anchor);

        if ($link.length && $anchor) {
          if (!$link.parent('[data-accordion-item]').hasClass('is-active')) {
            this.down($anchor, this.firstTimeInit);
            this.firstTimeInit = false;
          };

          //roll up a little to show the titles
          if (this.options.deepLinkSmudge) {
            var _this = this;
            onLoad($(window), function() {
              var offset = _this.$element.offset();
              $('html, body').animate({ scrollTop: offset.top }, _this.options.deepLinkSmudgeDelay);
            });
          }

          /**
            * Fires when the zplugin has deeplinked at pageload
            * @event Accordion#deeplink
            */
          this.$element.trigger('deeplink.zf.accordion', [$link, $anchor]);
        }
      }
    }

    //use browser to open a tab, if it exists in this tabset
    if (this.options.deepLink) {
      this._checkDeepLink();
    }

    this._events();
  }

  /**
   * Adds event handlers for items within the accordion.
   * @private
   */
  _events() {
    var _this = this;

    this.$tabs.each(function() {
      var $elem = $(this);
      var $tabContent = $elem.children('[data-tab-content]');
      if ($tabContent.length) {
        $elem.children('a').off('click.zf.accordion keydown.zf.accordion')
               .on('click.zf.accordion', function(e) {
          e.preventDefault();
          _this.toggle($tabContent);
        }).on('keydown.zf.accordion', function(e){
          Keyboard.handleKey(e, 'Accordion', {
            toggle: function() {
              _this.toggle($tabContent);
            },
            next: function() {
              var $a = $elem.next().find('a').focus();
              if (!_this.options.multiExpand) {
                $a.trigger('click.zf.accordion')
              }
            },
            previous: function() {
              var $a = $elem.prev().find('a').focus();
              if (!_this.options.multiExpand) {
                $a.trigger('click.zf.accordion')
              }
            },
            handled: function() {
              e.preventDefault();
            }
          });
        });
      }
    });
    if(this.options.deepLink) {
      $(window).on('hashchange', this._checkDeepLink);
    }
  }

  /**
   * Toggles the selected content pane's open/close state.
   * @param {jQuery} $target - jQuery object of the pane to toggle (`.accordion-content`).
   * @function
   */
  toggle($target) {
    if ($target.closest('[data-accordion]').is('[disabled]')) {
      console.info('Cannot toggle an accordion that is disabled.');
      return;
    }
    if($target.parent().hasClass('is-active')) {
      this.up($target);
    } else {
      this.down($target);
    }
    //either replace or update browser history
    if (this.options.deepLink) {
      var anchor = $target.prev('a').attr('href');

      if (this.options.updateHistory) {
        history.pushState({}, '', anchor);
      } else {
        history.replaceState({}, '', anchor);
      }
    }
  }

  /**
   * Opens the accordion tab defined by `$target`.
   * @param {jQuery} $target - Accordion pane to open (`.accordion-content`).
   * @param {Boolean} firstTime - flag to determine if reflow should happen.
   * @fires Accordion#down
   * @function
   */
  down($target, firstTime) {
    /**
     * checking firstTime allows for initial render of the accordion
     * to render preset is-active panes.
     */
    if ($target.closest('[data-accordion]').is('[disabled]') && !firstTime)  {
      console.info('Cannot call down on an accordion that is disabled.');
      return;
    }
    $target
      .attr('aria-hidden', false)
      .parent('[data-tab-content]')
      .addBack()
      .parent().addClass('is-active');

    if (!this.options.multiExpand && !firstTime) {
      var $currentActive = this.$element.children('.is-active').children('[data-tab-content]');
      if ($currentActive.length) {
        this.up($currentActive.not($target));
      }
    }

    $target.slideDown(this.options.slideSpeed, () => {
      /**
       * Fires when the tab is done opening.
       * @event Accordion#down
       */
      this.$element.trigger('down.zf.accordion', [$target]);
    });

    $(`#${$target.attr('aria-labelledby')}`).attr({
      'aria-expanded': true,
      'aria-selected': true
    });
  }

  /**
   * Closes the tab defined by `$target`.
   * @param {jQuery} $target - Accordion tab to close (`.accordion-content`).
   * @fires Accordion#up
   * @function
   */
  up($target) {
    if ($target.closest('[data-accordion]').is('[disabled]')) {
      console.info('Cannot call up on an accordion that is disabled.');
      return;
    }

    var $aunts = $target.parent().siblings(),
        _this = this;

    if((!this.options.allowAllClosed && !$aunts.hasClass('is-active')) || !$target.parent().hasClass('is-active')) {
      return;
    }

    $target.slideUp(_this.options.slideSpeed, function () {
      /**
       * Fires when the tab is done collapsing up.
       * @event Accordion#up
       */
      _this.$element.trigger('up.zf.accordion', [$target]);
    });

    $target.attr('aria-hidden', true)
           .parent().removeClass('is-active');

    $(`#${$target.attr('aria-labelledby')}`).attr({
     'aria-expanded': false,
     'aria-selected': false
   });
  }

  /**
   * Destroys an instance of an accordion.
   * @fires Accordion#destroyed
   * @function
   */
  _destroy() {
    this.$element.find('[data-tab-content]').stop(true).slideUp(0).css('display', '');
    this.$element.find('a').off('.zf.accordion');
    if(this.options.deepLink) {
      $(window).off('hashchange', this._checkDeepLink);
    }

  }
}

Accordion.defaults = {
  /**
   * Amount of time to animate the opening of an accordion pane.
   * @option
   * @type {number}
   * @default 250
   */
  slideSpeed: 250,
  /**
   * Allow the accordion to have multiple open panes.
   * @option
   * @type {boolean}
   * @default false
   */
  multiExpand: false,
  /**
   * Allow the accordion to close all panes.
   * @option
   * @type {boolean}
   * @default false
   */
  allowAllClosed: false,
  /**
   * Link the location hash to the open pane.
   * Set the location hash when the opened pane changes, and open and scroll to the corresponding pane when the location changes.
   * @option
   * @type {boolean}
   * @default false
   */
  deepLink: false,
  /**
   * If `deepLink` is enabled, adjust the deep link scroll to make sure the top of the accordion panel is visible
   * @option
   * @type {boolean}
   * @default false
   */
  deepLinkSmudge: false,
  /**
   * If `deepLinkSmudge` is enabled, animation time (ms) for the deep link adjustment
   * @option
   * @type {number}
   * @default 300
   */
  deepLinkSmudgeDelay: 300,
  /**
   * If `deepLink` is enabled, update the browser history with the open accordion
   * @option
   * @type {boolean}
   * @default false
   */
  updateHistory: false
};

export {Accordion};
<commit_msg>fix: fix initial state for Accordion without any panel active<commit_after>'use strict';

import $ from 'jquery';
import { Plugin } from './foundation.core.plugin';
import { onLoad, GetYoDigits } from './foundation.core.utils';
import { Keyboard } from './foundation.util.keyboard';

/**
 * Accordion module.
 * @module foundation.accordion
 * @requires foundation.util.keyboard
 */

class Accordion extends Plugin {
  /**
   * Creates a new instance of an accordion.
   * @class
   * @name Accordion
   * @fires Accordion#init
   * @param {jQuery} element - jQuery object to make into an accordion.
   * @param {Object} options - a plain object with settings to override the default options.
   */
  _setup(element, options) {
    this.$element = element;
    this.options = $.extend({}, Accordion.defaults, this.$element.data(), options);

    this.className = 'Accordion'; // ie9 back compat
    this._init();

    Keyboard.register('Accordion', {
      'ENTER': 'toggle',
      'SPACE': 'toggle',
      'ARROW_DOWN': 'next',
      'ARROW_UP': 'previous'
    });
  }

  /**
   * Initializes the accordion by animating the preset active pane(s).
   * @private
   */
  _init() {
    this.$element.attr('role', 'tablist');
    this.$tabs = this.$element.children('[data-accordion-item]');

    this.$tabs.each(function(idx, el) {
      var $el = $(el),
          $content = $el.children('[data-tab-content]'),
          id = $content[0].id || GetYoDigits(6, 'accordion'),
          linkId = (el.id) ? `${el.id}-label` : `${id}-label`;

      $el.find('a:first').attr({
        'aria-controls': id,
        'role': 'tab',
        'id': linkId,
        'aria-expanded': false,
        'aria-selected': false
      });

      $content.attr({'role': 'tabpanel', 'aria-labelledby': linkId, 'aria-hidden': true, 'id': id});
    });

    var $initActive = this.$element.find('.is-active').children('[data-tab-content]');
    // Remember if we already set up the initial state of the Accordion as it
    // gives additional privileges in the Accordion methods (like opening
    // multiple panels even with the "multiExpand" option is disabled)
    // TODO: refactor and clean this
    this.firstTimeInit = true;
    if ($initActive.length) {
      // Save up the initial hash to return to it later when going back in history
      this._initialAnchor = $initActive.prev('a').attr('href');

      this.down($initActive, this.firstTimeInit);
      this.firstTimeInit = false;
    }

    this._checkDeepLink = () => {
      var anchor = window.location.hash;

      // if there is no anchor, return to the initial panel
      if (!anchor.length && this._initialAnchor) {
        anchor = this._initialAnchor;
      }

      //need a hash and a relevant anchor in this tabset
      if(anchor.length) {
        var $link = this.$element.find('[href$="'+anchor+'"]'),
        $anchor = $(anchor);

        if ($link.length && $anchor) {
          if (!$link.parent('[data-accordion-item]').hasClass('is-active')) {
            this.down($anchor, this.firstTimeInit);
            this.firstTimeInit = false;
          };

          //roll up a little to show the titles
          if (this.options.deepLinkSmudge) {
            var _this = this;
            onLoad($(window), function() {
              var offset = _this.$element.offset();
              $('html, body').animate({ scrollTop: offset.top }, _this.options.deepLinkSmudgeDelay);
            });
          }

          /**
            * Fires when the zplugin has deeplinked at pageload
            * @event Accordion#deeplink
            */
          this.$element.trigger('deeplink.zf.accordion', [$link, $anchor]);
        }
      }
    }

    //use browser to open a tab, if it exists in this tabset
    if (this.options.deepLink) {
      this._checkDeepLink();
    }

    this._events();
    this.firstTimeInit = false;
  }

  /**
   * Adds event handlers for items within the accordion.
   * @private
   */
  _events() {
    var _this = this;

    this.$tabs.each(function() {
      var $elem = $(this);
      var $tabContent = $elem.children('[data-tab-content]');
      if ($tabContent.length) {
        $elem.children('a').off('click.zf.accordion keydown.zf.accordion')
               .on('click.zf.accordion', function(e) {
          e.preventDefault();
          _this.toggle($tabContent);
        }).on('keydown.zf.accordion', function(e){
          Keyboard.handleKey(e, 'Accordion', {
            toggle: function() {
              _this.toggle($tabContent);
            },
            next: function() {
              var $a = $elem.next().find('a').focus();
              if (!_this.options.multiExpand) {
                $a.trigger('click.zf.accordion')
              }
            },
            previous: function() {
              var $a = $elem.prev().find('a').focus();
              if (!_this.options.multiExpand) {
                $a.trigger('click.zf.accordion')
              }
            },
            handled: function() {
              e.preventDefault();
            }
          });
        });
      }
    });
    if(this.options.deepLink) {
      $(window).on('hashchange', this._checkDeepLink);
    }
  }

  /**
   * Toggles the selected content pane's open/close state.
   * @param {jQuery} $target - jQuery object of the pane to toggle (`.accordion-content`).
   * @function
   */
  toggle($target) {
    if ($target.closest('[data-accordion]').is('[disabled]')) {
      console.info('Cannot toggle an accordion that is disabled.');
      return;
    }
    if($target.parent().hasClass('is-active')) {
      this.up($target);
    } else {
      this.down($target);
    }
    //either replace or update browser history
    if (this.options.deepLink) {
      var anchor = $target.prev('a').attr('href');

      if (this.options.updateHistory) {
        history.pushState({}, '', anchor);
      } else {
        history.replaceState({}, '', anchor);
      }
    }
  }

  /**
   * Opens the accordion tab defined by `$target`.
   * @param {jQuery} $target - Accordion pane to open (`.accordion-content`).
   * @param {Boolean} firstTime - flag to determine if reflow should happen.
   * @fires Accordion#down
   * @function
   */
  down($target, firstTime) {
    /**
     * checking firstTime allows for initial render of the accordion
     * to render preset is-active panes.
     */
    if ($target.closest('[data-accordion]').is('[disabled]') && !firstTime)  {
      console.info('Cannot call down on an accordion that is disabled.');
      return;
    }
    $target
      .attr('aria-hidden', false)
      .parent('[data-tab-content]')
      .addBack()
      .parent().addClass('is-active');

    if (!this.options.multiExpand && !firstTime) {
      var $currentActive = this.$element.children('.is-active').children('[data-tab-content]');
      if ($currentActive.length) {
        this.up($currentActive.not($target));
      }
    }

    $target.slideDown(this.options.slideSpeed, () => {
      /**
       * Fires when the tab is done opening.
       * @event Accordion#down
       */
      this.$element.trigger('down.zf.accordion', [$target]);
    });

    $(`#${$target.attr('aria-labelledby')}`).attr({
      'aria-expanded': true,
      'aria-selected': true
    });
  }

  /**
   * Closes the tab defined by `$target`.
   * @param {jQuery} $target - Accordion tab to close (`.accordion-content`).
   * @fires Accordion#up
   * @function
   */
  up($target) {
    if ($target.closest('[data-accordion]').is('[disabled]')) {
      console.info('Cannot call up on an accordion that is disabled.');
      return;
    }

    var $aunts = $target.parent().siblings(),
        _this = this;

    if((!this.options.allowAllClosed && !$aunts.hasClass('is-active')) || !$target.parent().hasClass('is-active')) {
      return;
    }

    $target.slideUp(_this.options.slideSpeed, function () {
      /**
       * Fires when the tab is done collapsing up.
       * @event Accordion#up
       */
      _this.$element.trigger('up.zf.accordion', [$target]);
    });

    $target.attr('aria-hidden', true)
           .parent().removeClass('is-active');

    $(`#${$target.attr('aria-labelledby')}`).attr({
     'aria-expanded': false,
     'aria-selected': false
   });
  }

  /**
   * Destroys an instance of an accordion.
   * @fires Accordion#destroyed
   * @function
   */
  _destroy() {
    this.$element.find('[data-tab-content]').stop(true).slideUp(0).css('display', '');
    this.$element.find('a').off('.zf.accordion');
    if(this.options.deepLink) {
      $(window).off('hashchange', this._checkDeepLink);
    }

  }
}

Accordion.defaults = {
  /**
   * Amount of time to animate the opening of an accordion pane.
   * @option
   * @type {number}
   * @default 250
   */
  slideSpeed: 250,
  /**
   * Allow the accordion to have multiple open panes.
   * @option
   * @type {boolean}
   * @default false
   */
  multiExpand: false,
  /**
   * Allow the accordion to close all panes.
   * @option
   * @type {boolean}
   * @default false
   */
  allowAllClosed: false,
  /**
   * Link the location hash to the open pane.
   * Set the location hash when the opened pane changes, and open and scroll to the corresponding pane when the location changes.
   * @option
   * @type {boolean}
   * @default false
   */
  deepLink: false,
  /**
   * If `deepLink` is enabled, adjust the deep link scroll to make sure the top of the accordion panel is visible
   * @option
   * @type {boolean}
   * @default false
   */
  deepLinkSmudge: false,
  /**
   * If `deepLinkSmudge` is enabled, animation time (ms) for the deep link adjustment
   * @option
   * @type {number}
   * @default 300
   */
  deepLinkSmudgeDelay: 300,
  /**
   * If `deepLink` is enabled, update the browser history with the open accordion
   * @option
   * @type {boolean}
   * @default false
   */
  updateHistory: false
};

export {Accordion};
<|endoftext|>


<commit_before>/*
 * inputFile v0.1
 * Requires jQuery v1.32+
 * Created by Scott Greenfield
 *
 * Copyright 2011, Scott Greenfield
 * https://github.com/sgreenfield/
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 *
 */
(function($){$.fn.inputFile=function(c){var d={btnClass:'btn-gray',btnText:'Browse...'},browser=$.browser,iecatch=browser.msie+browser.version;$.extend(d,c);return this.each(function(i){var b=$(this),wrapper=$('
'+d.btnText+'
').addClass('jquery-input-file-wrapper'),id='file_'+i,$fakeInputFile=$('<input class="jquery-input-file-fake-file" id="'+id+'">'),inputFileWidth,inputFileHeight;if(iecatch.indexOf("true6")!==-1)return;$fakeInputFile.insertBefore(b).focus(function(){if(iecatch.indexOf("true")===0)$fakeInputFile.blur();b.click()}).keydown(function(e){var a=e.keyCode||e.which;if(a!==9&&a!==13)return false});b.add($fakeInputFile).wrapAll('
');b.wrap(wrapper).addClass('jquery-input-file').fadeTo(0,0).change(function(){$fakeInputFile.val(b.val())});b.parent('.jquery-input-file-wrapper').after('

');inputFileWidth=b.parent('.jquery-input-file-wrapper').outerWidth()+$fakeInputFile.outerWidth();inputFileHeight=$fakeInputFile.outerHeight();b.css('height',inputFileHeight);if(browser.mozilla){b.css({width:'auto',fontSize:inputFileHeight}).attr('size',Math.ceil(inputFileWidth/inputFileHeight/0.613))}else{b.css('width',inputFileWidth+10)}})}})(jQuery);<commit_msg>Updated minified JS.<commit_after>/*
 * inputFile v0.1
 * Requires jQuery v1.32+
 * Created by Scott Greenfield
 *
 * Copyright 2011, Scott Greenfield
 * https://github.com/sgreenfield/
 *
 * Licensed under the MIT license.
 * http://www.opensource.org/licenses/mit-license.php
 *
 */
(function($){$.fn.inputFile=function(c){var d={btnClass:'btn-gray',btnText:'Browse...'},browser=$.browser,iecatch=browser.msie+browser.version;$.extend(d,c);return this.each(function(i){var b=$(this),wrapper=$('
'+d.btnText+'
').addClass('jquery-input-file-wrapper'),id='file_'+i,$fakeInputFile=$('<input class="jquery-input-file-fake-file" id="'+id+'">'),inputFileWidth,inputFileHeight;if(iecatch.indexOf("true6")!==-1)return;$fakeInputFile.insertBefore(b).focus(function(){if(iecatch.indexOf("true")===0)$fakeInputFile.blur()}).keydown(function(e){var a=e.keyCode||e.which;if(a!==9&&a!==13)return false});b.add($fakeInputFile).wrapAll('
');b.wrap(wrapper).addClass('jquery-input-file').fadeTo(0,0).change(function(){$fakeInputFile.val(b.val())});b.parent('.jquery-input-file-wrapper').after('

');inputFileWidth=b.parent('.jquery-input-file-wrapper').outerWidth()+$fakeInputFile.outerWidth();inputFileHeight=$fakeInputFile.outerHeight();b.css('height',inputFileHeight);if(browser.mozilla){b.css({width:'auto',fontSize:inputFileHeight}).attr('size',Math.ceil(inputFileWidth/inputFileHeight/0.613))}else{b.css('width',inputFileWidth+10)}})}})(jQuery);<|endoftext|>


<commit_before>/*
* "mouse" plugin
*/

// This plugin is an experiment for abstracting away the touch and mouse
// events so that developers don't have to worry about which method of input
// the device their document is loaded on supports.
//
// The idea here is to allow the developer to register listeners for the
// basic mouse events, such as mousedown, mousemove, mouseup, and click,
// and the plugin will take care of registering the correct listeners
// behind the scenes to invoke the listener at the fastest possible time
// for that device, while still retaining the order of event firing in
// the traditional mouse environment, should multiple handlers be registered
// on the same element for different events.
//
// The current version exposes the following virtual events to jQuery bind methods:
// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"

(function( $, window, document, undefined ) {

var dataPropertyName = "virtualMouseBindings",
	touchTargetPropertyName = "virtualTouchID",
	virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ),
	touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ),
	activeDocHandlers = {},
	resetTimerID = 0,
	startX = 0,
	startY = 0,
	didScroll = false,
	clickBlockList = [],
	blockMouseTriggers = false,
	blockTouchTriggers = false,
	eventCaptureSupported = "addEventListener" in document,
	$document = $( document ),
	nextTouchID = 1,
	lastTouchID = 0;

$.vmouse = {
	moveDistanceThreshold: 10,
	clickDistanceThreshold: 10,
	resetTimerDuration: 1500
};

function getNativeEvent( event ) {

	while ( event && typeof event.originalEvent !== "undefined" ) {
		event = event.originalEvent;
	}
	return event;
}

function createVirtualEvent( event, eventType ) {

	var t = event.type,
		oe, props, ne, prop, ct, touch, i, j;

	event = $.Event(event);
	event.type = eventType;

	oe = event.originalEvent;
	props = $.event.props;

	// copy original event properties over to the new event
	// this would happen if we could call $.event.fix instead of $.Event
	// but we don't have a way to force an event to be fixed multiple times
	if ( oe ) {
		for ( i = props.length, prop; i; ) {
			prop = props[ --i ];
			event[ prop ] = oe[ prop ];
		}
	}

	// make sure that if the mouse and click virtual events are generated
	// without a .which one is defined
	if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ){
		event.which = 1;
	}

	if ( t.search(/^touch/) !== -1 ) {
		ne = getNativeEvent( oe );
		t = ne.touches;
		ct = ne.changedTouches;
		touch = ( t && t.length ) ? t[0] : ( (ct && ct.length) ? ct[ 0 ] : undefined );

		if ( touch ) {
			for ( j = 0, len = touchEventProps.length; j < len; j++){
				prop = touchEventProps[ j ];
				event[ prop ] = touch[ prop ];
			}
		}
	}

	return event;
}

function getVirtualBindingFlags( element ) {

	var flags = {},
		b, k;

	while ( element ) {

		b = $.data( element, dataPropertyName );

		for (  k in b ) {
			if ( b[ k ] ) {
				flags[ k ] = flags.hasVirtualBinding = true;
			}
		}
		element = element.parentNode;
	}
	return flags;
}

function getClosestElementWithVirtualBinding( element, eventType ) {
	var b;
	while ( element ) {

		b = $.data( element, dataPropertyName );

		if ( b && ( !eventType || b[ eventType ] ) ) {
			return element;
		}
		element = element.parentNode;
	}
	return null;
}

function enableTouchBindings() {
	blockTouchTriggers = false;
}

function disableTouchBindings() {
	blockTouchTriggers = true;
}

function enableMouseBindings() {
	lastTouchID = 0;
	clickBlockList.length = 0;
	blockMouseTriggers = false;

	// When mouse bindings are enabled, our
	// touch bindings are disabled.
	disableTouchBindings();
}

function disableMouseBindings() {
	// When mouse bindings are disabled, our
	// touch bindings are enabled.
	enableTouchBindings();
}

function startResetTimer() {
	clearResetTimer();
	resetTimerID = setTimeout(function(){
		resetTimerID = 0;
		enableMouseBindings();
	}, $.vmouse.resetTimerDuration );
}

function clearResetTimer() {
	if ( resetTimerID ){
		clearTimeout( resetTimerID );
		resetTimerID = 0;
	}
}

function triggerVirtualEvent( eventType, event, flags ) {
	var ve;

	if ( ( flags && flags[ eventType ] ) ||
				( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {

		ve = createVirtualEvent( event, eventType );

		$( event.target).trigger( ve );
	}

	return ve;
}

function mouseEventCallback( event ) {
	var touchID = $.data(event.target, touchTargetPropertyName);

	if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ){
		var ve = triggerVirtualEvent( "v" + event.type, event );
		if ( ve ) {
			if ( ve.isDefaultPrevented() ) {
				event.preventDefault();
			}
			if ( ve.isPropagationStopped() ) {
				event.stopPropagation();
			}
			if ( ve.isImmediatePropagationStopped() ) {
				event.stopImmediatePropagation();
			}
		}
	}
}

function handleTouchStart( event ) {

	var touches = getNativeEvent( event ).touches,
		target, flags;

	if ( touches && touches.length === 1 ) {

		target = event.target;
		flags = getVirtualBindingFlags( target );

		if ( flags.hasVirtualBinding ) {

			lastTouchID = nextTouchID++;
			$.data( target, touchTargetPropertyName, lastTouchID );

			clearResetTimer();

			disableMouseBindings();
			didScroll = false;

			var t = getNativeEvent( event ).touches[ 0 ];
			startX = t.pageX;
			startY = t.pageY;

			triggerVirtualEvent( "vmouseover", event, flags );
			triggerVirtualEvent( "vmousedown", event, flags );
		}
	}
}

function handleScroll( event ) {
	if ( blockTouchTriggers ) {
		return;
	}

	if ( !didScroll ) {
		triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) );
	}

	didScroll = true;
	startResetTimer();
}

function handleTouchMove( event ) {
	if ( blockTouchTriggers ) {
		return;
	}

	var t = getNativeEvent( event ).touches[ 0 ],
		didCancel = didScroll,
		moveThreshold = $.vmouse.moveDistanceThreshold;
		didScroll = didScroll ||
			( Math.abs(t.pageX - startX) > moveThreshold ||
				Math.abs(t.pageY - startY) > moveThreshold ),
		flags = getVirtualBindingFlags( event.target );

	if ( didScroll && !didCancel ) {
		triggerVirtualEvent( "vmousecancel", event, flags );
	}

	triggerVirtualEvent( "vmousemove", event, flags );
	startResetTimer();
}

function handleTouchEnd( event ) {
	if ( blockTouchTriggers ) {
		return;
	}

	disableTouchBindings();

	var flags = getVirtualBindingFlags( event.target ),
		t;
	triggerVirtualEvent( "vmouseup", event, flags );

	if ( !didScroll ) {
		var ve = triggerVirtualEvent( "vclick", event, flags );
		if ( ve && ve.isDefaultPrevented() ) {
			// The target of the mouse events that follow the touchend
			// event don't necessarily match the target used during the
			// touch. This means we need to rely on coordinates for blocking
			// any click that is generated.
			t = getNativeEvent( event ).changedTouches[ 0 ];
			clickBlockList.push({
				touchID: lastTouchID,
				x: t.clientX,
				y: t.clientY
			});

			// Prevent any mouse events that follow from triggering
			// virtual event notifications.
			blockMouseTriggers = true;
		}
	}
	triggerVirtualEvent( "vmouseout", event, flags);
	didScroll = false;

	startResetTimer();
}

function hasVirtualBindings( ele ) {
	var bindings = $.data( ele, dataPropertyName ),
		k;

	if ( bindings ) {
		for ( k in bindings ) {
			if ( bindings[ k ] ) {
				return true;
			}
		}
	}
	return false;
}

function dummyMouseHandler(){}

function getSpecialEventObject( eventType ) {
	var realType = eventType.substr( 1 );

	return {
		setup: function( data, namespace ) {
			// If this is the first virtual mouse binding for this element,
			// add a bindings object to its data.

			if ( !hasVirtualBindings( this ) ) {
				$.data( this, dataPropertyName, {});
			}

			// If setup is called, we know it is the first binding for this
			// eventType, so initialize the count for the eventType to zero.
			var bindings = $.data( this, dataPropertyName );
			bindings[ eventType ] = true;

			// If this is the first virtual mouse event for this type,
			// register a global handler on the document.

			activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1;

			if ( activeDocHandlers[ eventType ] === 1 ) {
				$document.bind( realType, mouseEventCallback );
			}

			// Some browsers, like Opera Mini, won't dispatch mouse/click events
			// for elements unless they actually have handlers registered on them.
			// To get around this, we register dummy handlers on the elements.

			$( this ).bind( realType, dummyMouseHandler );

			// For now, if event capture is not supported, we rely on mouse handlers.
			if ( eventCaptureSupported ) {
				// If this is the first virtual mouse binding for the document,
				// register our touchstart handler on the document.

				activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1;

				if (activeDocHandlers[ "touchstart" ] === 1) {
					$document.bind( "touchstart", handleTouchStart )
						.bind( "touchend", handleTouchEnd )

						// On touch platforms, touching the screen and then dragging your finger
						// causes the window content to scroll after some distance threshold is
						// exceeded. On these platforms, a scroll prevents a click event from being
						// dispatched, and on some platforms, even the touchend is suppressed. To
						// mimic the suppression of the click event, we need to watch for a scroll
						// event. Unfortunately, some platforms like iOS don't dispatch scroll
						// events until *AFTER* the user lifts their finger (touchend). This means
						// we need to watch both scroll and touchmove events to figure out whether
						// or not a scroll happenens before the touchend event is fired.

						.bind( "touchmove", handleTouchMove )
						.bind( "scroll", handleScroll );
				}
			}
		},

		teardown: function( data, namespace ) {
			// If this is the last virtual binding for this eventType,
			// remove its global handler from the document.

			--activeDocHandlers[ eventType ];

			if ( !activeDocHandlers[ eventType ] ) {
				$document.unbind( realType, mouseEventCallback );
			}

			if ( eventCaptureSupported ) {
				// If this is the last virtual mouse binding in existence,
				// remove our document touchstart listener.

				--activeDocHandlers[ "touchstart" ];

				if ( !activeDocHandlers[ "touchstart" ] ) {
					$document.unbind( "touchstart", handleTouchStart )
						.unbind( "touchmove", handleTouchMove )
						.unbind( "touchend", handleTouchEnd )
						.unbind( "scroll", handleScroll );
				}
			}

			var $this = $( this ),
				bindings = $.data( this, dataPropertyName );

			// teardown may be called when an element was
			// removed from the DOM. If this is the case,
			// jQuery core may have already stripped the element
			// of any data bindings so we need to check it before
			// using it.
			if ( bindings ) {
				bindings[ eventType ] = false;
			}

			// Unregister the dummy event handler.

			$this.unbind( realType, dummyMouseHandler );

			// If this is the last virtual mouse binding on the
			// element, remove the binding data from the element.

			if ( !hasVirtualBindings( this ) ) {
				$this.removeData( dataPropertyName );
			}
		}
	};
}

// Expose our custom events to the jQuery bind/unbind mechanism.

for ( var i = 0; i < virtualEventNames.length; i++ ){
	$.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] );
}

// Add a capture click handler to block clicks.
// Note that we require event capture support for this so if the device
// doesn't support it, we punt for now and rely solely on mouse events.
if ( eventCaptureSupported ) {
	document.addEventListener( "click", function( e ){
		var cnt = clickBlockList.length,
			target = e.target,
			x, y, ele, i, o, touchID;

		if ( cnt ) {
			x = e.clientX;
			y = e.clientY;
			threshold = $.vmouse.clickDistanceThreshold;

			// The idea here is to run through the clickBlockList to see if
			// the current click event is in the proximity of one of our
			// vclick events that had preventDefault() called on it. If we find
			// one, then we block the click.
			//
			// Why do we have to rely on proximity?
			//
			// Because the target of the touch event that triggered the vclick
			// can be different from the target of the click event synthesized
			// by the browser. The target of a mouse/click event that is syntehsized
			// from a touch event seems to be implementation specific. For example,
			// some browsers will fire mouse/click events for a link that is near
			// a touch event, even though the target of the touchstart/touchend event
			// says the user touched outside the link. Also, it seems that with most
			// browsers, the target of the mouse/click event is not calculated until the
			// time it is dispatched, so if you replace an element that you touched
			// with another element, the target of the mouse/click will be the new
			// element underneath that point.
			//
			// Aside from proximity, we also check to see if the target and any
			// of its ancestors were the ones that blocked a click. This is necessary
			// because of the strange mouse/click target calculation done in the
			// Android 2.1 browser, where if you click on an element, and there is a
			// mouse/click handler on one of its ancestors, the target will be the
			// innermost child of the touched element, even if that child is no where
			// near the point of touch.

			ele = target;

			while ( ele ) {
				for ( i = 0; i < cnt; i++ ) {
					o = clickBlockList[ i ];
					touchID = 0;

					if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) ||
								$.data( ele, touchTargetPropertyName ) === o.touchID ) {
						// XXX: We may want to consider removing matches from the block list
						//      instead of waiting for the reset timer to fire.
						e.preventDefault();
						e.stopPropagation();
						return;
					}
				}
				ele = ele.parentNode;
			}
		}
	}, true);
}
})( jQuery, window, document );
<commit_msg>add mouse event props to virtual mouse events Fixes #3280<commit_after>/*
* "mouse" plugin
*/

// This plugin is an experiment for abstracting away the touch and mouse
// events so that developers don't have to worry about which method of input
// the device their document is loaded on supports.
//
// The idea here is to allow the developer to register listeners for the
// basic mouse events, such as mousedown, mousemove, mouseup, and click,
// and the plugin will take care of registering the correct listeners
// behind the scenes to invoke the listener at the fastest possible time
// for that device, while still retaining the order of event firing in
// the traditional mouse environment, should multiple handlers be registered
// on the same element for different events.
//
// The current version exposes the following virtual events to jQuery bind methods:
// "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel"

(function( $, window, document, undefined ) {

var dataPropertyName = "virtualMouseBindings",
	touchTargetPropertyName = "virtualTouchID",
	virtualEventNames = "vmouseover vmousedown vmousemove vmouseup vclick vmouseout vmousecancel".split( " " ),
	touchEventProps = "clientX clientY pageX pageY screenX screenY".split( " " ),
	mouseEventProps = $.event.props.concat( $.event.mouseHooks.props ),
	activeDocHandlers = {},
	resetTimerID = 0,
	startX = 0,
	startY = 0,
	didScroll = false,
	clickBlockList = [],
	blockMouseTriggers = false,
	blockTouchTriggers = false,
	eventCaptureSupported = "addEventListener" in document,
	$document = $( document ),
	nextTouchID = 1,
	lastTouchID = 0;

$.vmouse = {
	moveDistanceThreshold: 10,
	clickDistanceThreshold: 10,
	resetTimerDuration: 1500
};

function getNativeEvent( event ) {

	while ( event && typeof event.originalEvent !== "undefined" ) {
		event = event.originalEvent;
	}
	return event;
}

function createVirtualEvent( event, eventType ) {

	var t = event.type,
		oe, props, ne, prop, ct, touch, i, j;

	event = $.Event(event);
	event.type = eventType;

	oe = event.originalEvent;
	props = $.event.props;

	// addresses separation of $.event.props in to $.event.mouseHook.props and Issue 3280
	// https://github.com/jquery/jquery-mobile/issues/3280
	if ( t.search(/mouse/) >-1 ) {
		props = mouseEventProps;
	}

	// copy original event properties over to the new event
	// this would happen if we could call $.event.fix instead of $.Event
	// but we don't have a way to force an event to be fixed multiple times
	if ( oe ) {
		for ( i = props.length, prop; i; ) {
			prop = props[ --i ];
			event[ prop ] = oe[ prop ];
		}
	}

	// make sure that if the mouse and click virtual events are generated
	// without a .which one is defined
	if ( t.search(/mouse(down|up)|click/) > -1 && !event.which ){
		event.which = 1;
	}

	if ( t.search(/^touch/) !== -1 ) {
		ne = getNativeEvent( oe );
		t = ne.touches;
		ct = ne.changedTouches;
		touch = ( t && t.length ) ? t[0] : ( (ct && ct.length) ? ct[ 0 ] : undefined );

		if ( touch ) {
			for ( j = 0, len = touchEventProps.length; j < len; j++){
				prop = touchEventProps[ j ];
				event[ prop ] = touch[ prop ];
			}
		}
	}

	return event;
}

function getVirtualBindingFlags( element ) {

	var flags = {},
		b, k;

	while ( element ) {

		b = $.data( element, dataPropertyName );

		for (  k in b ) {
			if ( b[ k ] ) {
				flags[ k ] = flags.hasVirtualBinding = true;
			}
		}
		element = element.parentNode;
	}
	return flags;
}

function getClosestElementWithVirtualBinding( element, eventType ) {
	var b;
	while ( element ) {

		b = $.data( element, dataPropertyName );

		if ( b && ( !eventType || b[ eventType ] ) ) {
			return element;
		}
		element = element.parentNode;
	}
	return null;
}

function enableTouchBindings() {
	blockTouchTriggers = false;
}

function disableTouchBindings() {
	blockTouchTriggers = true;
}

function enableMouseBindings() {
	lastTouchID = 0;
	clickBlockList.length = 0;
	blockMouseTriggers = false;

	// When mouse bindings are enabled, our
	// touch bindings are disabled.
	disableTouchBindings();
}

function disableMouseBindings() {
	// When mouse bindings are disabled, our
	// touch bindings are enabled.
	enableTouchBindings();
}

function startResetTimer() {
	clearResetTimer();
	resetTimerID = setTimeout(function(){
		resetTimerID = 0;
		enableMouseBindings();
	}, $.vmouse.resetTimerDuration );
}

function clearResetTimer() {
	if ( resetTimerID ){
		clearTimeout( resetTimerID );
		resetTimerID = 0;
	}
}

function triggerVirtualEvent( eventType, event, flags ) {
	var ve;

	if ( ( flags && flags[ eventType ] ) ||
				( !flags && getClosestElementWithVirtualBinding( event.target, eventType ) ) ) {

		ve = createVirtualEvent( event, eventType );

		$( event.target).trigger( ve );
	}

	return ve;
}

function mouseEventCallback( event ) {
	var touchID = $.data(event.target, touchTargetPropertyName);

	if ( !blockMouseTriggers && ( !lastTouchID || lastTouchID !== touchID ) ){
		var ve = triggerVirtualEvent( "v" + event.type, event );
		if ( ve ) {
			if ( ve.isDefaultPrevented() ) {
				event.preventDefault();
			}
			if ( ve.isPropagationStopped() ) {
				event.stopPropagation();
			}
			if ( ve.isImmediatePropagationStopped() ) {
				event.stopImmediatePropagation();
			}
		}
	}
}

function handleTouchStart( event ) {

	var touches = getNativeEvent( event ).touches,
		target, flags;

	if ( touches && touches.length === 1 ) {

		target = event.target;
		flags = getVirtualBindingFlags( target );

		if ( flags.hasVirtualBinding ) {

			lastTouchID = nextTouchID++;
			$.data( target, touchTargetPropertyName, lastTouchID );

			clearResetTimer();

			disableMouseBindings();
			didScroll = false;

			var t = getNativeEvent( event ).touches[ 0 ];
			startX = t.pageX;
			startY = t.pageY;

			triggerVirtualEvent( "vmouseover", event, flags );
			triggerVirtualEvent( "vmousedown", event, flags );
		}
	}
}

function handleScroll( event ) {
	if ( blockTouchTriggers ) {
		return;
	}

	if ( !didScroll ) {
		triggerVirtualEvent( "vmousecancel", event, getVirtualBindingFlags( event.target ) );
	}

	didScroll = true;
	startResetTimer();
}

function handleTouchMove( event ) {
	if ( blockTouchTriggers ) {
		return;
	}

	var t = getNativeEvent( event ).touches[ 0 ],
		didCancel = didScroll,
		moveThreshold = $.vmouse.moveDistanceThreshold;
		didScroll = didScroll ||
			( Math.abs(t.pageX - startX) > moveThreshold ||
				Math.abs(t.pageY - startY) > moveThreshold ),
		flags = getVirtualBindingFlags( event.target );

	if ( didScroll && !didCancel ) {
		triggerVirtualEvent( "vmousecancel", event, flags );
	}

	triggerVirtualEvent( "vmousemove", event, flags );
	startResetTimer();
}

function handleTouchEnd( event ) {
	if ( blockTouchTriggers ) {
		return;
	}

	disableTouchBindings();

	var flags = getVirtualBindingFlags( event.target ),
		t;
	triggerVirtualEvent( "vmouseup", event, flags );

	if ( !didScroll ) {
		var ve = triggerVirtualEvent( "vclick", event, flags );
		if ( ve && ve.isDefaultPrevented() ) {
			// The target of the mouse events that follow the touchend
			// event don't necessarily match the target used during the
			// touch. This means we need to rely on coordinates for blocking
			// any click that is generated.
			t = getNativeEvent( event ).changedTouches[ 0 ];
			clickBlockList.push({
				touchID: lastTouchID,
				x: t.clientX,
				y: t.clientY
			});

			// Prevent any mouse events that follow from triggering
			// virtual event notifications.
			blockMouseTriggers = true;
		}
	}
	triggerVirtualEvent( "vmouseout", event, flags);
	didScroll = false;

	startResetTimer();
}

function hasVirtualBindings( ele ) {
	var bindings = $.data( ele, dataPropertyName ),
		k;

	if ( bindings ) {
		for ( k in bindings ) {
			if ( bindings[ k ] ) {
				return true;
			}
		}
	}
	return false;
}

function dummyMouseHandler(){}

function getSpecialEventObject( eventType ) {
	var realType = eventType.substr( 1 );

	return {
		setup: function( data, namespace ) {
			// If this is the first virtual mouse binding for this element,
			// add a bindings object to its data.

			if ( !hasVirtualBindings( this ) ) {
				$.data( this, dataPropertyName, {});
			}

			// If setup is called, we know it is the first binding for this
			// eventType, so initialize the count for the eventType to zero.
			var bindings = $.data( this, dataPropertyName );
			bindings[ eventType ] = true;

			// If this is the first virtual mouse event for this type,
			// register a global handler on the document.

			activeDocHandlers[ eventType ] = ( activeDocHandlers[ eventType ] || 0 ) + 1;

			if ( activeDocHandlers[ eventType ] === 1 ) {
				$document.bind( realType, mouseEventCallback );
			}

			// Some browsers, like Opera Mini, won't dispatch mouse/click events
			// for elements unless they actually have handlers registered on them.
			// To get around this, we register dummy handlers on the elements.

			$( this ).bind( realType, dummyMouseHandler );

			// For now, if event capture is not supported, we rely on mouse handlers.
			if ( eventCaptureSupported ) {
				// If this is the first virtual mouse binding for the document,
				// register our touchstart handler on the document.

				activeDocHandlers[ "touchstart" ] = ( activeDocHandlers[ "touchstart" ] || 0) + 1;

				if (activeDocHandlers[ "touchstart" ] === 1) {
					$document.bind( "touchstart", handleTouchStart )
						.bind( "touchend", handleTouchEnd )

						// On touch platforms, touching the screen and then dragging your finger
						// causes the window content to scroll after some distance threshold is
						// exceeded. On these platforms, a scroll prevents a click event from being
						// dispatched, and on some platforms, even the touchend is suppressed. To
						// mimic the suppression of the click event, we need to watch for a scroll
						// event. Unfortunately, some platforms like iOS don't dispatch scroll
						// events until *AFTER* the user lifts their finger (touchend). This means
						// we need to watch both scroll and touchmove events to figure out whether
						// or not a scroll happenens before the touchend event is fired.

						.bind( "touchmove", handleTouchMove )
						.bind( "scroll", handleScroll );
				}
			}
		},

		teardown: function( data, namespace ) {
			// If this is the last virtual binding for this eventType,
			// remove its global handler from the document.

			--activeDocHandlers[ eventType ];

			if ( !activeDocHandlers[ eventType ] ) {
				$document.unbind( realType, mouseEventCallback );
			}

			if ( eventCaptureSupported ) {
				// If this is the last virtual mouse binding in existence,
				// remove our document touchstart listener.

				--activeDocHandlers[ "touchstart" ];

				if ( !activeDocHandlers[ "touchstart" ] ) {
					$document.unbind( "touchstart", handleTouchStart )
						.unbind( "touchmove", handleTouchMove )
						.unbind( "touchend", handleTouchEnd )
						.unbind( "scroll", handleScroll );
				}
			}

			var $this = $( this ),
				bindings = $.data( this, dataPropertyName );

			// teardown may be called when an element was
			// removed from the DOM. If this is the case,
			// jQuery core may have already stripped the element
			// of any data bindings so we need to check it before
			// using it.
			if ( bindings ) {
				bindings[ eventType ] = false;
			}

			// Unregister the dummy event handler.

			$this.unbind( realType, dummyMouseHandler );

			// If this is the last virtual mouse binding on the
			// element, remove the binding data from the element.

			if ( !hasVirtualBindings( this ) ) {
				$this.removeData( dataPropertyName );
			}
		}
	};
}

// Expose our custom events to the jQuery bind/unbind mechanism.

for ( var i = 0; i < virtualEventNames.length; i++ ){
	$.event.special[ virtualEventNames[ i ] ] = getSpecialEventObject( virtualEventNames[ i ] );
}

// Add a capture click handler to block clicks.
// Note that we require event capture support for this so if the device
// doesn't support it, we punt for now and rely solely on mouse events.
if ( eventCaptureSupported ) {
	document.addEventListener( "click", function( e ){
		var cnt = clickBlockList.length,
			target = e.target,
			x, y, ele, i, o, touchID;

		if ( cnt ) {
			x = e.clientX;
			y = e.clientY;
			threshold = $.vmouse.clickDistanceThreshold;

			// The idea here is to run through the clickBlockList to see if
			// the current click event is in the proximity of one of our
			// vclick events that had preventDefault() called on it. If we find
			// one, then we block the click.
			//
			// Why do we have to rely on proximity?
			//
			// Because the target of the touch event that triggered the vclick
			// can be different from the target of the click event synthesized
			// by the browser. The target of a mouse/click event that is syntehsized
			// from a touch event seems to be implementation specific. For example,
			// some browsers will fire mouse/click events for a link that is near
			// a touch event, even though the target of the touchstart/touchend event
			// says the user touched outside the link. Also, it seems that with most
			// browsers, the target of the mouse/click event is not calculated until the
			// time it is dispatched, so if you replace an element that you touched
			// with another element, the target of the mouse/click will be the new
			// element underneath that point.
			//
			// Aside from proximity, we also check to see if the target and any
			// of its ancestors were the ones that blocked a click. This is necessary
			// because of the strange mouse/click target calculation done in the
			// Android 2.1 browser, where if you click on an element, and there is a
			// mouse/click handler on one of its ancestors, the target will be the
			// innermost child of the touched element, even if that child is no where
			// near the point of touch.

			ele = target;

			while ( ele ) {
				for ( i = 0; i < cnt; i++ ) {
					o = clickBlockList[ i ];
					touchID = 0;

					if ( ( ele === target && Math.abs( o.x - x ) < threshold && Math.abs( o.y - y ) < threshold ) ||
								$.data( ele, touchTargetPropertyName ) === o.touchID ) {
						// XXX: We may want to consider removing matches from the block list
						//      instead of waiting for the reset timer to fire.
						e.preventDefault();
						e.stopPropagation();
						return;
					}
				}
				ele = ele.parentNode;
			}
		}
	}, true);
}
})( jQuery, window, document );
<|endoftext|>


<commit_before>/*!
 * jQuery Plugin Creator @VERSION
 * https://github.com/OOPMan/jquery-plugin-creator
 *
 * Copyright 2014 Adam Jorgensen
 * Released under the MIT license.
 * http://github.com/OOPMan/jquery-plugin-creator/LICENSE
 *
 */
/**
 * TODO: Add checks to prevent over-writing plugins
 * TODO: Add checks to prevent re-instantating plugins
 * TODO: Add plugin destruction handling
 * TODO: Add ability to control whether extendPlugin calls parent constructor
 * TODO: Add ability to not specify plugin name and have a randomly generated name assigned
 */
"use strict";
(function () {
    /**
     *
     * @param {jQuery} jQuery
     * @returns {{addPlugin: addPlugin}}
     */
    function pluginCreatorFactory(jQuery) {
        var $ = jQuery,
            /**
             *
             * @type {{addPlugin: addPlugin}}
             */
            pluginCreator = {
                /**
                 * Adds a new stateful plugin to jQuery.
                 *
                 * A stateful plugin consists of the following optional components:
                 * - A constructor function to be executed when the plugin is instantiated on a given element.
                 * - An object defining default properties to be associated with a plugin instance via its options member
                 * - An object defining member functions and values to be associated with a plugin instances prototype.
                 * - A prototype function to be used as the plugin instances prototype when the plugin is instantiate on a given element.
                 *
                 * @param {string} name
                 * @param {function} [constructor]
                 * @param {Object} [defaults]
                 * @param {Object} [members]
                 * @param {function} [prototype]
                 * @return {string}
                 */
                addPlugin: function (name, constructor, defaults, members, prototype) {
                    var constructor = constructor || function () {},
                        defaults = $.extend({}, defaults || {}),
                        members = $.extend({}, members || {}),
                        prototype = prototype || function () {},
                        prototypes = [prototype],
                        readonlyMembers = {
                            /**
                             *
                             * @param {Object} options
                             * @returns {Object}
                             */
                            update: function (options) {
                                $.extend(true, this.options, options);
                                return this.options;
                            },
                            /**
                             *
                             * @param {Object} members
                             * @returns {boolean}
                             */
                            extend: function (members) {
                                $.extend(true, this, attachSuperFunctions(this, members), readonlyMembers);
                                return true;
                            }
                        };
                    $.extend(true, prototype, members, readonlyMembers);

                    /**
                     * This function is used to instantiate an instance of the plugin on a given element.
                     *
                     * @param {Object} element
                     * @param {Object} [options]
                     * @param {Array} [constructorArguments]
                     */
                    function instantiatePlugin(element, options, constructorArguments) {
                        var options = options || {},
                            innerConstructor = function () {
                                this.element = element;
                                this.context = $(element).addClass(name);
                                this.options = $.extend(true, {}, $.fn[name].defaults, options);
                                constructor.apply(this, constructorArguments);
                            };
                        innerConstructor.prototype = new prototypes[0]();
                        $.data(element, "jquery-plugincreator-" + name, new innerConstructor());
                    }

                    // Add Plugin
                    /**
                     *
                     * @param {Object|string} options
                     * @returns {jQuery}
                     */
                    $.fn[name] = function(options) {
                        var args = $.makeArray(arguments);
                        return this.each(function() {
                            var instance = $.data(this, "jquery-plugincreator-" + name);
                            if (instance) {
                                if (typeof options == "string") { // call a method on the instance
                                    instance[options].apply(instance, args.slice(1));
                                } else if (instance.update) { // call update on the instance
                                    instance.update.apply(instance, args);
                                }
                            } else {
                                instantiatePlugin(this, options, args.slice(1));
                            }
                        })
                    };
                    /**
                     *
                     * @type {Object}
                     */
                    $.fn[name].defaults = defaults;
                    /**
                     *
                     * @param {Object} options
                     * @returns {Object}
                     */
                    $.fn[name].updateDefaultsWith = function(options) {
                        $.extend(true, $.fn[name].defaults, options);
                        return $.fn[name].defaults;
                    };
                    /**
                     *
                     * @param {Object} members
                     * @param {function} [prototype]
                     * @returns {function}
                     */
                    $.fn[name].extendMembersWith = function(members, prototype) {
                        var prototype = prototype || function prototype() {};
                        prototype.prototype = new prototypes[0]();
                        $.extend(true, prototype, members, readonlyMembers);
                        prototypes.unshift(prototype);
                        return prototype;
                    };
                    /**
                     * Clones a plugin added using jQuery PluginCreator.
                     *
                     * While the defaults and members are cloned completely and are independent, the constructor is shared.
                     *
                     * @param {string} name
                     * @param {string} newName
                     * @returns {string}
                     */
                    $.fn[name].cloneTo = function (newName) {
                        return pluginCreator.addPlugin(newName, constructor, defaults, members, prototype);
                    };
                    /**
                     * Extends a plugin added using jQuery PluginCreator.
                     *
                     * Defaults and members are cloned and extended from the original plugin while the extended constructor
                     * functions such that the constructor for the original plugin is called first, then new new
                     * constructor, if present.
                     *
                     * @param {string} name
                     * @param {string} newName
                     * @param {function()} [constructor]
                     * @param {Object} [defaults]
                     * @param {Object} [members]
                     * @return {string}
                     */
                     $.fn[name].extendTo = function (newName, members, prototype) {
                        var prototype = prototype || function () {};
                        $.fn[name].cloneTo(newName);
                        $.fn[newName].extendMembersWith(members, prototype);
                     };
                    return name;
                }
        };
        return pluginCreator;
    }
    // Export jQuery Plugin Creator
    if (typeof module !== "undefined") {
        var jQuery = require("jquery"),
            pluginCreator = pluginCreatorFactory(jQuery);
        jQuery.extend(jQuery, pluginCreator);
        module.exports = pluginCreator;
    } else if (typeof define === "function" && define.amd) {
        define(["jquery"], function(jQuery) {
            var pluginCreator = pluginCreatorFactory(jQuery);
            jQuery.extend(jQuery, pluginCreator);
            return pluginCreator;
        });
    } else if (typeof jQuery !== "undefined")  {
        jQuery.extend(jQuery, pluginCreatorFactory(jQuery));
    } else {
        throw "jQuery not defined";
    }
})();

<commit_msg>Fixed creation of initial prototype during addPlugin. Amended extend function defined as part of readonlyMembers.<commit_after>/*!
 * jQuery Plugin Creator @VERSION
 * https://github.com/OOPMan/jquery-plugin-creator
 *
 * Copyright 2014 Adam Jorgensen
 * Released under the MIT license.
 * http://github.com/OOPMan/jquery-plugin-creator/LICENSE
 *
 */
/**
 * TODO: Add checks to prevent over-writing plugins
 * TODO: Add checks to prevent re-instantating plugins
 * TODO: Add plugin destruction handling
 * TODO: Add ability to control whether extendPlugin calls parent constructor
 * TODO: Add ability to not specify plugin name and have a randomly generated name assigned
 */
"use strict";
(function () {
    /**
     *
     * @param {jQuery} jQuery
     * @returns {{addPlugin: addPlugin}}
     */
    function pluginCreatorFactory(jQuery) {
        var $ = jQuery,
            /**
             *
             * @type {{addPlugin: addPlugin}}
             */
            pluginCreator = {
                /**
                 * Adds a new stateful plugin to jQuery.
                 *
                 * A stateful plugin consists of the following optional components:
                 * - A constructor function to be executed when the plugin is instantiated on a given element.
                 * - An object defining default properties to be associated with a plugin instance via its options member
                 * - An object defining member functions and values to be associated with a plugin instances prototype.
                 * - A prototype function to be used as the plugin instances prototype when the plugin is instantiate on a given element.
                 *
                 * @param {string} name
                 * @param {function} [constructor]
                 * @param {Object} [defaults]
                 * @param {Object} [members]
                 * @param {function} [prototype]
                 * @return {string}
                 */
                addPlugin: function (name, constructor, defaults, members, prototype) {
                    var constructor = constructor || function () {},
                        defaults = $.extend({}, defaults || {}),
                        members = $.extend({}, members || {}),
                        prototype = prototype || function () {},
                        prototypes = [prototype],
                        readonlyMembers = {
                            /**
                             *
                             * @param {Object} options
                             * @returns {Object}
                             */
                            update: function (options) {
                                $.extend(true, this.options, options);
                                return this.options;
                            },
                            /**
                             *
                             * @param {Object} members
                             * @returns {boolean}
                             */
                            extend: function (members, prototype) {
                                var prototype = prototype || function prototype() {};
                                prototype.prototype = new (this.prototype)();
                                $.extend(true, prototype.prototype, members, readonlyMembers);
                                return prototype;
                            }
                        };
                    $.extend(true, prototype.prototype, members, readonlyMembers);

                    /**
                     * This function is used to instantiate an instance of the plugin on a given element.
                     *
                     * @param {Object} element
                     * @param {Object} [options]
                     * @param {Array} [constructorArguments]
                     */
                    function instantiatePlugin(element, options, constructorArguments) {
                        var options = options || {},
                            innerConstructor = function () {
                                this.element = element;
                                this.context = $(element).addClass(name);
                                this.options = $.extend(true, {}, $.fn[name].defaults, options);
                                constructor.apply(this, constructorArguments);
                            };
                        innerConstructor.prototype = new prototypes[0]();
                        $.data(element, "jquery-plugincreator-" + name, new innerConstructor());
                    }

                    // Add Plugin
                    /**
                     *
                     * @param {Object|string} options
                     * @returns {jQuery}
                     */
                    $.fn[name] = function(options) {
                        var args = $.makeArray(arguments);
                        return this.each(function() {
                            var instance = $.data(this, "jquery-plugincreator-" + name);
                            if (instance) {
                                if (typeof options == "string") { // call a method on the instance
                                    instance[options].apply(instance, args.slice(1));
                                } else if (instance.update) { // call update on the instance
                                    instance.update.apply(instance, args);
                                }
                            } else {
                                instantiatePlugin(this, options, args.slice(1));
                            }
                        })
                    };
                    /**
                     *
                     * @type {Object}
                     */
                    $.fn[name].defaults = defaults;
                    /**
                     *
                     * @param {Object} options
                     * @returns {Object}
                     */
                    $.fn[name].updateDefaultsWith = function(options) {
                        $.extend(true, $.fn[name].defaults, options);
                        return $.fn[name].defaults;
                    };
                    /**
                     *
                     * @param {Object} members
                     * @param {function} [prototype]
                     * @returns {function}
                     */
                    $.fn[name].extendMembersWith = function(members, prototype) {
                        var prototype = prototype || function prototype() {};
                        prototype.prototype = new prototypes[0]();
                        $.extend(true, prototype.prototype, members, readonlyMembers);
                        prototypes.unshift(prototype);
                        return prototype;
                    };
                    /**
                     * Clones a plugin added using jQuery PluginCreator.
                     *
                     * While the defaults and members are cloned completely and are independent, the constructor is shared.
                     *
                     * @param {string} name
                     * @param {string} newName
                     * @returns {string}
                     */
                    $.fn[name].cloneTo = function (newName) {
                        return pluginCreator.addPlugin(newName, constructor, defaults, members, prototype);
                    };
                    /**
                     * Extends a plugin added using jQuery PluginCreator.
                     *
                     * Defaults and members are cloned and extended from the original plugin while the extended constructor
                     * functions such that the constructor for the original plugin is called first, then new new
                     * constructor, if present.
                     *
                     * @param {string} name
                     * @param {string} newName
                     * @param {function()} [constructor]
                     * @param {Object} [defaults]
                     * @param {Object} [members]
                     * @return {string}
                     */
                     $.fn[name].extendTo = function (newName, members, prototype) {
                        var prototype = prototype || function () {};
                        $.fn[name].cloneTo(newName);
                        $.fn[newName].extendMembersWith(members, prototype);
                     };
                    return name;
                }
        };
        return pluginCreator;
    }
    // Export jQuery Plugin Creator
    if (typeof module !== "undefined") {
        var jQuery = require("jquery"),
            pluginCreator = pluginCreatorFactory(jQuery);
        jQuery.extend(jQuery, pluginCreator);
        module.exports = pluginCreator;
    } else if (typeof define === "function" && define.amd) {
        define(["jquery"], function(jQuery) {
            var pluginCreator = pluginCreatorFactory(jQuery);
            jQuery.extend(jQuery, pluginCreator);
            return pluginCreator;
        });
    } else if (typeof jQuery !== "undefined")  {
        jQuery.extend(jQuery, pluginCreatorFactory(jQuery));
    } else {
        throw "jQuery not defined";
    }
})();

<|endoftext|>


<commit_before>import cssSelectorExtract from 'css-selector-extract';
import fs from 'fs';
import path from 'path';

export default class SelectorImporter {
  /**
   * Import packages from the `node_modules` directory.
   * @param {Object} options - Configuration options.
   */
  constructor(options = {}) {
    const defaultOptions = {};
    this.options = Object.assign({}, defaultOptions, options);
  }

  /**
   * Clean a node sass import url.
   * @param {string} url - Import url from node-sass.
   * @return {string} Cleaned url.
   */
  cleanUrl(url) {
    // Remove tilde symbol from the beginning
    // of urls (except home "~/" directory).
    const re = new RegExp(`^~(?!${path.sep})`);
    return url.replace(re, '');
  }

  /**
   * Parse a url for selector filters.
   * @param {string} url - Import url from node-sass.
   * @return {Object} Cleaned up url and selector filter object.
   */
  parseUrl(url) {
    // Find selectors in the import url and
    // return a cleaned up url and the selectors.
    let cleanUrl = this.cleanUrl(url);
    let selectorFilters;
    const selectorFiltersMatch = url.match(/{([^}]+)}/);
    if (selectorFiltersMatch) {
      cleanUrl = url.replace(/(\r\n|\n|\r)/gm, ' ').split(' from ')[1].trim();
      // Create an array with selectors and replacement as one value.
      selectorFilters = selectorFiltersMatch[1].split(',')
        // Trim unnecessary whitespace.
        .map(Function.prototype.call, String.prototype.trim)
        // Split selectors and replacement selectors into an array.
        .map((currentValue) => currentValue.split(' as ')
          .map(Function.prototype.call, String.prototype.trim));
    }
    return { url: cleanUrl, selectorFilters };
  }

  /**
   * Synchronously extract selectors from a file with the given url.
   * @param {string} url - Import url from node-sass.
   * @return {string} Contents string or null.
   */
  resolveSync(url) {
    const data = this.parseUrl(url);
    const cleanUrl = data.url;
    const selectorFilters = data.selectorFilters;
    const selectors = [];
    const replacementSelectors = {};
    let contents = null;

    if (!selectorFilters) {
      return contents;
    }

    selectorFilters.forEach((selectorFilter) => {
      const selector = selectorFilter[0];
      const replacementSelector = selectorFilter[1];
      selectors.push(selector);
      if (replacementSelector) {
        replacementSelectors[selector] = replacementSelector;
      }
    });

    this.options.includePaths.some((includePath) => {
      const css = fs.readFileSync(path.join(includePath, cleanUrl), { encoding: 'utf8' });
      if (css) {
        contents = cssSelectorExtract.processSync(css, selectors, replacementSelectors);
        return true;
      }
      return false;
    });

    return contents;
  }

  /**
   * Asynchronously extract selectors from a file with the given url.
   * @param {string} url - Import url from node-sass.
   * @return {Promise} Promise for a contents string.
   */
  resolve(url) {
    return new Promise((promiseResolve) => {
      promiseResolve(this.resolveSync(url));
    });
  }
}
<commit_msg>fix the main docblock description<commit_after>import cssSelectorExtract from 'css-selector-extract';
import fs from 'fs';
import path from 'path';

export default class SelectorImporter {
  /**
   * Import only certain CSS selectors form a file.
   * @param {Object} options - Configuration options.
   */
  constructor(options = {}) {
    const defaultOptions = {};
    this.options = Object.assign({}, defaultOptions, options);
  }

  /**
   * Clean a node sass import url.
   * @param {string} url - Import url from node-sass.
   * @return {string} Cleaned url.
   */
  cleanUrl(url) {
    // Remove tilde symbol from the beginning
    // of urls (except home "~/" directory).
    const re = new RegExp(`^~(?!${path.sep})`);
    return url.replace(re, '');
  }

  /**
   * Parse a url for selector filters.
   * @param {string} url - Import url from node-sass.
   * @return {Object} Cleaned up url and selector filter object.
   */
  parseUrl(url) {
    // Find selectors in the import url and
    // return a cleaned up url and the selectors.
    let cleanUrl = this.cleanUrl(url);
    let selectorFilters;
    const selectorFiltersMatch = url.match(/{([^}]+)}/);
    if (selectorFiltersMatch) {
      cleanUrl = url.replace(/(\r\n|\n|\r)/gm, ' ').split(' from ')[1].trim();
      // Create an array with selectors and replacement as one value.
      selectorFilters = selectorFiltersMatch[1].split(',')
        // Trim unnecessary whitespace.
        .map(Function.prototype.call, String.prototype.trim)
        // Split selectors and replacement selectors into an array.
        .map((currentValue) => currentValue.split(' as ')
          .map(Function.prototype.call, String.prototype.trim));
    }
    return { url: cleanUrl, selectorFilters };
  }

  /**
   * Synchronously extract selectors from a file with the given url.
   * @param {string} url - Import url from node-sass.
   * @return {string} Contents string or null.
   */
  resolveSync(url) {
    const data = this.parseUrl(url);
    const cleanUrl = data.url;
    const selectorFilters = data.selectorFilters;
    const selectors = [];
    const replacementSelectors = {};
    let contents = null;

    if (!selectorFilters) {
      return contents;
    }

    selectorFilters.forEach((selectorFilter) => {
      const selector = selectorFilter[0];
      const replacementSelector = selectorFilter[1];
      selectors.push(selector);
      if (replacementSelector) {
        replacementSelectors[selector] = replacementSelector;
      }
    });

    this.options.includePaths.some((includePath) => {
      const css = fs.readFileSync(path.join(includePath, cleanUrl), { encoding: 'utf8' });
      if (css) {
        contents = cssSelectorExtract.processSync(css, selectors, replacementSelectors);
        return true;
      }
      return false;
    });

    return contents;
  }

  /**
   * Asynchronously extract selectors from a file with the given url.
   * @param {string} url - Import url from node-sass.
   * @return {Promise} Promise for a contents string.
   */
  resolve(url) {
    return new Promise((promiseResolve) => {
      promiseResolve(this.resolveSync(url));
    });
  }
}
<|endoftext|>


<commit_before>(function ($) {

    var themes = $.mobiscroll.themes,
        theme = {
            minWidth: 76,
            height: 76,
            accent: 'none',
            dateOrder: 'mmMMddDDyy',
            headerText: false,
            showLabel: false,
            deleteIcon: 'backspace4',
            icon: { filled: 'star3', empty: 'star' },
            btnWidth: false,
            btnStartClass: 'mbsc-ic mbsc-ic-play3',
            btnStopClass: 'mbsc-ic mbsc-ic-pause2',
            btnResetClass: 'mbsc-ic mbsc-ic-stop2',
            btnLapClass: 'mbsc-ic mbsc-ic-loop2',
            btnHideClass: 'mbsc-ic mbsc-ic-close',
            btnCalPrevClass: 'mbsc-ic mbsc-ic-arrow-left2',
            btnCalNextClass: 'mbsc-ic mbsc-ic-arrow-right2',
            btnPlusClass: 'mbsc-ic mbsc-ic-plus',
            btnMinusClass: 'mbsc-ic mbsc-ic-minus',
            onMarkupInserted: function (elm, inst) {
                var click,
                    touch,
                    active;

                elm.addClass('mbsc-wp');

                $('.dw', elm).addClass('mbsc-wp-' + inst.settings.accent);

                $('.dwb-s .dwb', elm).addClass('mbsc-ic mbsc-ic-checkmark');
                $('.dwb-c .dwb', elm).addClass('mbsc-ic mbsc-ic-close');
                $('.dwb-cl .dwb', elm).addClass('mbsc-ic mbsc-ic-close');
                $('.dwb-n .dwb', elm).addClass('mbsc-ic mbsc-ic-loop2');

                $('.dwwl', elm).on('touchstart mousedown DOMMouseScroll mousewheel', function (e) {
                    if (e.type === 'mousedown' && touch) {
                        return;
                    }
                    touch = e.type === 'touchstart';
                    click = true;
                    active = $(this).hasClass('wpa');
                    $('.dwwl', elm).removeClass('wpa');
                    $(this).addClass('wpa');
                }).on('touchmove mousemove', function () {
                    click = false;
                }).on('touchend mouseup', function (e) {
                    if (click && active && $(e.target).closest('.dw-li').hasClass('dw-sel')) {
                        $(this).removeClass('wpa');
                    }
                    if (e.type === 'mouseup') {
                        touch = false;
                    }
                    click = false;
                });
            },
            onThemeLoad: function (lang, s) {
                if (lang && lang.dateOrder && !s.dateOrder) {
                    var ord = lang.dateOrder;
                    ord = ord.match(/mm/i) ? ord.replace(/mmMM|mm|MM/,  'mmMM') : ord.replace(/mM|m|M/,  'mM');
                    ord = ord.match(/dd/i) ? ord.replace(/ddDD|dd|DD/,  'ddDD') : ord.replace(/dD|d|D/,  'dD');
                    s.dateOrder = ord;
                }
                if (s.theme) {
                    s.theme = s.theme.replace(' light', '-light');
                }
            }
        };

    themes.wp = theme;
    themes['wp-light'] = theme;

    // @deprecated since 2.12.0, backward compatibility code
    themes['wp light'] = theme;

})(jQuery);

<commit_msg>Small improvements and cleanup<commit_after>(function ($) {

    var themes = $.mobiscroll.themes,
        theme = {
            minWidth: 76,
            height: 76,
            accent: 'none',
            dateOrder: 'mmMMddDDyy',
            headerText: false,
            showLabel: false,
            deleteIcon: 'backspace4',
            icon: { filled: 'star3', empty: 'star' },
            btnWidth: false,
            btnStartClass: 'mbsc-ic mbsc-ic-play3',
            btnStopClass: 'mbsc-ic mbsc-ic-pause2',
            btnResetClass: 'mbsc-ic mbsc-ic-stop2',
            btnLapClass: 'mbsc-ic mbsc-ic-loop2',
            btnHideClass: 'mbsc-ic mbsc-ic-close',
            btnCalPrevClass: 'mbsc-ic mbsc-ic-arrow-left2',
            btnCalNextClass: 'mbsc-ic mbsc-ic-arrow-right2',
            btnPlusClass: 'mbsc-ic mbsc-ic-plus',
            btnMinusClass: 'mbsc-ic mbsc-ic-minus',
            onMarkupInserted: function (elm, inst) {
                var click,
                    touch,
                    active;

                elm.addClass('mbsc-wp');

                $('.dw', elm).addClass('mbsc-wp-' + inst.settings.accent);

                $('.dwb-s .dwb', elm).addClass('mbsc-ic mbsc-ic-checkmark');
                $('.dwb-c .dwb', elm).addClass('mbsc-ic mbsc-ic-close');
                $('.dwb-cl .dwb', elm).addClass('mbsc-ic mbsc-ic-close');
                $('.dwb-n .dwb', elm).addClass('mbsc-ic mbsc-ic-loop2');

                $('.dwwl', elm).on('touchstart mousedown DOMMouseScroll mousewheel', function (e) {
                    if (e.type === 'mousedown' && touch) {
                        return;
                    }
                    touch = e.type === 'touchstart';
                    click = true;
                    active = $(this).hasClass('wpa');
                    $('.dwwl', elm).removeClass('wpa');
                    $(this).addClass('wpa');
                }).on('touchmove mousemove', function () {
                    click = false;
                }).on('touchend mouseup', function (e) {
                    if (click && active && $(e.target).closest('.dw-li').hasClass('dw-sel')) {
                        $(this).removeClass('wpa');
                    }
                    if (e.type === 'mouseup') {
                        touch = false;
                    }
                    click = false;
                });
            },
            onThemeLoad: function (lang, s) {
                if (lang && lang.dateOrder && !s.dateOrder) {
                    var ord = lang.dateOrder;
                    ord = ord.match(/mm/i) ? ord.replace(/mmMM|mm|MM/,  'mmMM') : ord.replace(/mM|m|M/,  'mM');
                    ord = ord.match(/dd/i) ? ord.replace(/ddDD|dd|DD/,  'ddDD') : ord.replace(/dD|d|D/,  'dD');
                    s.dateOrder = ord;
                }
                // @deprecated since 2.12.0, backward compatibility code
                // ---
                if (s.theme) {
                    s.theme = s.theme.replace(' light', '-light');
                }
                // ---
            }
        };

    themes.wp = theme;
    themes['wp-light'] = theme;

    // @deprecated since 2.12.0, backward compatibility code
    themes['wp light'] = theme;

})(jQuery);

<|endoftext|>


<commit_before>// Pattern which Plone livesearch functionality on an input
//
// Author: Nathan Van Gheem
// Contact: nathan@vangheem.us
// Version: 1.0
//
// Adapted from queryhelper.js in Plone.
//
// License:
//
// Copyright (C) 2013 Plone Foundation
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

/*jshint bitwise:true, curly:true, eqeqeq:true, immed:true, latedef:true,
  newcap:true, noarg:true, noempty:true, nonew:true, plusplus:true,
  undef:true, strict:true, trailing:true, browser:true, evil:true */
/*global define:false */

define([
  'jquery',
  'js/patterns/base'
], function($, Base) {
  "use strict";

  var QueryHelper = Base.extend({
    name: "queryhelper",
    defaults: {
      ajaxvocabulary: null,
      searchParam: 'SearchableText', // query string param to pass to search url
      attributes: ['UID','Title', 'Description', 'getURL', 'Type'],
      batchSize: 10 // number of results to retrive
    },

    init: function(basePattern) {
      /* if basePattern argument provided, it can implement the interface of:
       *    - browsing: boolean if currently browsing
       *    - currentPath: string of current path to apply to search if browsing
       *    - basePath: default path to provide if no subpath used
       */
      var self = this;
      if(basePattern === undefined){
        basePattern = {
          browsing: false
        };
      }
      self.basePattern = basePattern;
      if(self.options.ajaxvocabulary !== undefined &&
          self.options.ajaxvocabulary !== null){
        self.valid = true;
      }else{
        self.valid = false;
      }
    },

    selectAjax: function(){
      var self = this;
      return {
        url: self.options.ajaxvocabulary,
        dataType: 'JSON',
        quietMillis: 100,
        data: function(term, page) {
          if(term){
            term += '*';
          }
          var criteria = [{
            i: self.options.searchParam,
            o: 'plone.app.querystring.operation.string.contains',
            v: term
          }];
          var pattern = self.basePattern;
          if(pattern.browsing){
            criteria.push({
              i: 'path',
              o: 'plone.app.querystring.operation.string.path',
              v: pattern.currentPath ? pattern.currentPath : pattern.basePath
            });
          }

          var opts = {
            query: JSON.stringify({
              criteria: criteria
            }),
            batch: JSON.stringify({
              page: page, // select2 is 1 based for pages
              size: self.options.batchSize
            }),
            attributes: JSON.stringify(self.options.attributes)
          };
          return opts;
        },
        results: function (data, page) {
          var more = (page * 10) < data.total; // whether or not there are more results available
          // notice we return the value of more so Select2 knows if more results can be loaded
          return {results: data.results, more: more};
        }
      };
    },

    search: function(term, operation, value, callback){
      var self = this;
      var data = {
        query: JSON.stringify({
          criteria: [{
            i: term,
            o: operation,
            v: value
          }]
        }),
        attributes: JSON.stringify(self.options.attributes)
      };
      $.ajax({
        url: self.options.ajaxvocabulary,
        dataType: 'JSON',
        data: data,
        success: callback
      });
    }
  });

  return QueryHelper;

});

<commit_msg>fix use of basePath<commit_after>// Pattern which Plone livesearch functionality on an input
//
// Author: Nathan Van Gheem
// Contact: nathan@vangheem.us
// Version: 1.0
//
// Adapted from queryhelper.js in Plone.
//
// License:
//
// Copyright (C) 2013 Plone Foundation
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 2 of the License.
//
// This program is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
// FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
// more details.
//
// You should have received a copy of the GNU General Public License along with
// this program; if not, write to the Free Software Foundation, Inc., 51
// Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
//

/*jshint bitwise:true, curly:true, eqeqeq:true, immed:true, latedef:true,
  newcap:true, noarg:true, noempty:true, nonew:true, plusplus:true,
  undef:true, strict:true, trailing:true, browser:true, evil:true */
/*global define:false */

define([
  'jquery',
  'js/patterns/base'
], function($, Base) {
  "use strict";

  var QueryHelper = Base.extend({
    name: "queryhelper",
    defaults: {
      ajaxvocabulary: null,
      searchParam: 'SearchableText', // query string param to pass to search url
      attributes: ['UID','Title', 'Description', 'getURL', 'Type'],
      batchSize: 10 // number of results to retrive
    },

    init: function(basePattern) {
      /* if basePattern argument provided, it can implement the interface of:
       *    - browsing: boolean if currently browsing
       *    - currentPath: string of current path to apply to search if browsing
       *    - basePath: default path to provide if no subpath used
       */
      var self = this;
      if(basePattern === undefined){
        basePattern = {
          browsing: false
        };
      }
      self.basePattern = basePattern;
      if(self.options.ajaxvocabulary !== undefined &&
          self.options.ajaxvocabulary !== null){
        self.valid = true;
      }else{
        self.valid = false;
      }
    },

    selectAjax: function(){
      var self = this;
      return {
        url: self.options.ajaxvocabulary,
        dataType: 'JSON',
        quietMillis: 100,
        data: function(term, page) {
          if(term){
            term += '*';
          }
          var criteria = [{
            i: self.options.searchParam,
            o: 'plone.app.querystring.operation.string.contains',
            v: term
          }];
          var pattern = self.basePattern;
          if(pattern.browsing){
            criteria.push({
              i: 'path',
              o: 'plone.app.querystring.operation.string.path',
              v: pattern.currentPath ? pattern.currentPath : pattern.options.basePath
            });
          }

          var opts = {
            query: JSON.stringify({
              criteria: criteria
            }),
            batch: JSON.stringify({
              page: page, // select2 is 1 based for pages
              size: self.options.batchSize
            }),
            attributes: JSON.stringify(self.options.attributes)
          };
          return opts;
        },
        results: function (data, page) {
          var more = (page * 10) < data.total; // whether or not there are more results available
          // notice we return the value of more so Select2 knows if more results can be loaded
          return {results: data.results, more: more};
        }
      };
    },

    search: function(term, operation, value, callback){
      var self = this;
      var data = {
        query: JSON.stringify({
          criteria: [{
            i: term,
            o: operation,
            v: value
          }]
        }),
        attributes: JSON.stringify(self.options.attributes)
      };
      $.ajax({
        url: self.options.ajaxvocabulary,
        dataType: 'JSON',
        data: data,
        success: callback
      });
    }
  });

  return QueryHelper;

});

<|endoftext|>


<commit_before>'use strict';

formsAngular.provider('formRoutes', ['$routeProvider', function ($routeProvider) {

  var _fngRoutes = [
    {route: '/analyse/:model/:reportSchemaName',  options: {templateUrl: 'partials/base-analysis.html'}},
    {route: '/analyse/:model',                    options: {templateUrl: 'partials/base-analysis.html'}},
    {route: '/:model/:id/edit',                   options: {templateUrl: 'partials/base-edit.html'}},
    {route: '/:model/new',                        options: {templateUrl: 'partials/base-edit.html'}},
    {route: '/:model',                            options: {templateUrl: 'partials/base-list.html'}},
    {route: '/:model/:form/:id/edit',             options: {templateUrl: 'partials/base-edit.html'}},       // non default form (different fields etc)
    {route: '/:model/:form/new',                  options: {templateUrl: 'partials/base-edit.html'}},       // non default form (different fields etc)
    {route: '/:model/:form',                      options: {templateUrl: 'partials/base-list.html'}}        // list page with links to non default form
  ];

  var _setRoutes = function (appRoutes) {
    if (appRoutes === null || appRoutes === undefined) {
      throw new Error('invalid app routes being added to forms-angular');
    }
    for (var i = 0, end = appRoutes.length; i < end; i++) {
      $routeProvider.when(appRoutes[i].route, appRoutes[i].options);
    }
  };

  var _setDefaultRoute = function (defaultRoute) {
    if (defaultRoute !== null) {
      $routeProvider.otherwise({redirectTo: defaultRoute});
    }
  };

  return {
    setRoutes: function (appRoutes, defaultRoute) {
      _setRoutes(appRoutes);
      _setRoutes(_fngRoutes);
      _setDefaultRoute(defaultRoute);
    },
    $get: function () {
      return null;
    }
  };
}]);
<commit_msg>Give other modules chance to set up their routes before out general ones<commit_after>'use strict';

formsAngular.provider('formRoutes', ['$routeProvider', function ($routeProvider) {

  var _fngRoutes = [
    {route: '/analyse/:model/:reportSchemaName',  options: {templateUrl: 'partials/base-analysis.html'}},
    {route: '/analyse/:model',                    options: {templateUrl: 'partials/base-analysis.html'}},
    {route: '/:model/:id/edit',                   options: {templateUrl: 'partials/base-edit.html'}},
    {route: '/:model/new',                        options: {templateUrl: 'partials/base-edit.html'}},
    {route: '/:model',                            options: {templateUrl: 'partials/base-list.html'}},
    {route: '/:model/:form/:id/edit',             options: {templateUrl: 'partials/base-edit.html'}},       // non default form (different fields etc)
    {route: '/:model/:form/new',                  options: {templateUrl: 'partials/base-edit.html'}},       // non default form (different fields etc)
    {route: '/:model/:form',                      options: {templateUrl: 'partials/base-list.html'}}        // list page with links to non default form
  ];

  var _setRoutes = function (appRoutes) {
    if (appRoutes === null || appRoutes === undefined) {
      throw new Error('invalid app routes being added to forms-angular');
    }
    for (var i = 0, end = appRoutes.length; i < end; i++) {
      $routeProvider.when(appRoutes[i].route, appRoutes[i].options);
    }
  };

  var _setDefaultRoute = function (defaultRoute) {
    if (defaultRoute !== null) {
      $routeProvider.otherwise({redirectTo: defaultRoute});
    }
  };

  return {
    setRoutes: function (appRoutes, defaultRoute) {
      _setRoutes(appRoutes);
      setTimeout(function() {_setRoutes(_fngRoutes)});   // add our routes when all other modules have had a chance to get theirs in
      _setDefaultRoute(defaultRoute);
    },
    $get: function () {
      return null;
    }
  };
}]);
<|endoftext|>