如何仅在一个下拉列表中应用脚本?

时间:2014-02-13 08:11:28

标签: javascript jquery

我在这里粘贴我的剧本 jquerymultiselect.js

(function($, undefined) {

    var multiselectID = 0;
    var $doc = $(document);

   $.widget("ech.multiselect", {

// default options
options: {
  header: true,
  height: 175,
  minWidth: 225,
  classes: '',
  checkAllText: 'Check all',
  uncheckAllText: 'Uncheck all',
  noneSelectedText: 'Select options',
  selectedText: '# selected',
  selectedList: 0,
  show: null,
  hide: null,
  autoOpen: false,
  multiple: true,
  position: {},
  appendTo: "body"
},

_create: function() {
  var el = this.element.hide();
  var o = this.options;

  this.speed = $.fx.speeds._default; // default speed for effects
  this._isOpen = false; // assume no

  // create a unique namespace for events that the widget
  // factory cannot unbind automatically. Use eventNamespace if on
  // jQuery UI 1.9+, and otherwise fallback to a custom string.
  this._namespaceID = this.eventNamespace || ('multiselect' + multiselectID);

  var button = (this.button = $('<button type="button"><span class="ui-icon ui-icon-triangle-1-s"></span></button>'))
    .addClass('ui-multiselect ui-widget ui-state-default ui-corner-all')
    .addClass(o.classes)
    .attr({ 'title':el.attr('title'), 'aria-haspopup':true, 'tabIndex':el.attr('tabIndex') })
    .insertAfter(el),

    buttonlabel = (this.buttonlabel = $('<span />'))
      .html(o.noneSelectedText)
      .appendTo(button),

    menu = (this.menu = $('<div />'))
      .addClass('ui-multiselect-menu ui-widget ui-widget-content ui-corner-all')
      .addClass(o.classes)
      .appendTo($(o.appendTo)),

    header = (this.header = $('<div />'))
      .addClass('ui-widget-header ui-corner-all ui-multiselect-header ui-helper-clearfix')
      .appendTo(menu),

    headerLinkContainer = (this.headerLinkContainer = $('<ul />'))
      .addClass('ui-helper-reset')
      .html(function() {
        if(o.header === true) {
          return '<li><a class="ui-multiselect-all" href="#"><span class="ui-icon ui-icon-check"></span><span>' + o.checkAllText + '</span></a></li><li><a class="ui-multiselect-none" href="#"><span class="ui-icon ui-icon-closethick"></span><span>' + o.uncheckAllText + '</span></a></li>';
        } else if(typeof o.header === "string") {
          return '<li>' + o.header + '</li>';
        } else {
          return '';
        }
      })
      .append('<li class="ui-multiselect-close"><a href="#" class="ui-multiselect-close"><span class="ui-icon ui-icon-circle-close"></span></a></li>')
      .appendTo(header),

    checkboxContainer = (this.checkboxContainer = $('<ul />'))
      .addClass('ui-multiselect-checkboxes ui-helper-reset')
      .appendTo(menu);

    // perform event bindings
    this._bindEvents();

    // build menu
    this.refresh(true);

    // some addl. logic for single selects
    if(!o.multiple) {
      menu.addClass('ui-multiselect-single');
    }

    // bump unique ID
    multiselectID++;
},

_init: function() {
  if(this.options.header === false) {
    this.header.hide();
  }
  if(!this.options.multiple) {
    this.headerLinkContainer.find('.ui-multiselect-all, .ui-multiselect-none').hide();
  }
  if(this.options.autoOpen) {
    this.open();
  }
  if(this.element.is(':disabled')) {
    this.disable();
  }
},

refresh: function(init) {
  var el = this.element;
  var o = this.options;
  var menu = this.menu;
  var checkboxContainer = this.checkboxContainer;
  var optgroups = [];
  var html = "";
  var id = el.attr('id') || multiselectID++; // unique ID for the label & option tags

  // build items
  el.find('option').each(function(i) {
    var $this = $(this);
    var parent = this.parentNode;
    var description = this.innerHTML;
    var title = this.title;
    var value = this.value;
    var inputID = 'ui-multiselect-' + (this.id || id + '-option-' + i);
    var isDisabled = this.disabled;
    var isSelected = this.selected;
    var labelClasses = [ 'ui-corner-all' ];
    var liClasses = (isDisabled ? 'ui-multiselect-disabled ' : ' ') + this.className;
    var optLabel;

    // is this an optgroup?
    if(parent.tagName === 'OPTGROUP') {
      optLabel = parent.getAttribute('label');

      // has this optgroup been added already?
      if($.inArray(optLabel, optgroups) === -1) {
        html += '<li class="ui-multiselect-optgroup-label ' + parent.className + '"><a href="#">' + optLabel + '</a></li>';
        optgroups.push(optLabel);
      }
    }

    if(isDisabled) {
      labelClasses.push('ui-state-disabled');
    }

    // browsers automatically select the first option
    // by default with single selects
    if(isSelected && !o.multiple) {
      labelClasses.push('ui-state-active');
    }

    html += '<li class="' + liClasses + '">';

    // create the label
    html += '<label for="' + inputID + '" title="' + title + '" class="' + labelClasses.join(' ') + '">';
    html += '<input id="' + inputID + '" name="multiselect_' + id + '" type="' + (o.multiple ? "checkbox" : "radio") + '" value="' + value + '" title="' + title + '"';

    // pre-selected?
    if(isSelected) {
      html += ' checked="checked"';
      html += ' aria-selected="true"';
    }

    // disabled?
    if(isDisabled) {
      html += ' disabled="disabled"';
      html += ' aria-disabled="true"';
    }

    // add the title and close everything off
    html += ' /><span>' + description + '</span></label></li>';
  });

  // insert into the DOM
  checkboxContainer.html(html);

  // cache some moar useful elements
  this.labels = menu.find('label');
  this.inputs = this.labels.children('input');

  // set widths
  this._setButtonWidth();
  this._setMenuWidth();

  // remember default value
  this.button[0].defaultValue = this.update();

  // broadcast refresh event; useful for widgets
  if(!init) {
    this._trigger('refresh');
  }
},

// updates the button text. call refresh() to rebuild
update: function() {
  var o = this.options;
  var $inputs = this.inputs;
  var $checked = $inputs.filter(':checked');
  var numChecked = $checked.length;
  var value;

  if(numChecked === 0) {
    value = o.noneSelectedText;
  } else {
    if($.isFunction(o.selectedText)) {
      value = o.selectedText.call(this, numChecked, $inputs.length, $checked.get());
    } else if(/\d/.test(o.selectedList) && o.selectedList > 0 && numChecked <= o.selectedList) {
      value = $checked.map(function() { return $(this).next().html(); }).get().join(', ');
    } else {
      value = o.selectedText.replace('#', numChecked).replace('#', $inputs.length);
    }
  }

  this._setButtonValue(value);

  return value;
},

// this exists as a separate method so that the developer 
// can easily override it.
_setButtonValue: function(value) {
  this.buttonlabel.text(value);
},

// binds events
_bindEvents: function() {
  var self = this;
  var button = this.button;

  function clickHandler() {
    self[ self._isOpen ? 'close' : 'open' ]();
    return false;
  }

  // webkit doesn't like it when you click on the span :(
  button
    .find('span')
    .bind('click.multiselect', clickHandler);

  // button events
  button.bind({
    click: clickHandler,
    keypress: function(e) {
      switch(e.which) {
        case 27: // esc
          case 38: // up
          case 37: // left
          self.close();
        break;
        case 39: // right
          case 40: // down
          self.open();
        break;
      }
    },
    mouseenter: function() {
      if(!button.hasClass('ui-state-disabled')) {
        $(this).addClass('ui-state-hover');
      }
    },
    mouseleave: function() {
      $(this).removeClass('ui-state-hover');
    },
    focus: function() {
      if(!button.hasClass('ui-state-disabled')) {
        $(this).addClass('ui-state-focus');
      }
    },
    blur: function() {
      $(this).removeClass('ui-state-focus');
    }
  });

  // header links
  this.header.delegate('a', 'click.multiselect', function(e) {
    // close link
    if($(this).hasClass('ui-multiselect-close')) {
      self.close();

      // check all / uncheck all
    } else {
      self[$(this).hasClass('ui-multiselect-all') ? 'checkAll' : 'uncheckAll']();
    }

    e.preventDefault();
  });

  // optgroup label toggle support
  this.menu.delegate('li.ui-multiselect-optgroup-label a', 'click.multiselect', function(e) {
    e.preventDefault();

    var $this = $(this);
    var $inputs = $this.parent().nextUntil('li.ui-multiselect-optgroup-label').find('input:visible:not(:disabled)');
    var nodes = $inputs.get();
    var label = $this.parent().text();

    // trigger event and bail if the return is false
    if(self._trigger('beforeoptgrouptoggle', e, { inputs:nodes, label:label }) === false) {
      return;
    }

    // toggle inputs
    self._toggleChecked(
      $inputs.filter(':checked').length !== $inputs.length,
      $inputs
    );

    self._trigger('optgrouptoggle', e, {
      inputs: nodes,
      label: label,
      checked: nodes[0].checked
    });
  })
  .delegate('label', 'mouseenter.multiselect', function() {
    if(!$(this).hasClass('ui-state-disabled')) {
      self.labels.removeClass('ui-state-hover');
      $(this).addClass('ui-state-hover').find('input').focus();
    }
  })
  .delegate('label', 'keydown.multiselect', function(e) {
    e.preventDefault();

    switch(e.which) {
      case 9: // tab
        case 27: // esc
        self.close();
      break;
      case 38: // up
        case 40: // down
        case 37: // left
        case 39: // right
        self._traverse(e.which, this);
      break;
      case 13: // enter
        $(this).find('input')[0].click();
      break;
    }
  })
  .delegate('input[type="checkbox"], input[type="radio"]', 'click.multiselect', function(e) {
    var $this = $(this);
    var val = this.value;
    var checked = this.checked;
    var tags = self.element.find('option');

    // bail if this input is disabled or the event is cancelled
    if(this.disabled || self._trigger('click', e, { value: val, text: this.title, checked: checked }) === false) {
      e.preventDefault();
      return;
    }

    // make sure the input has focus. otherwise, the esc key
    // won't close the menu after clicking an item.
    $this.focus();

    // toggle aria state
    $this.attr('aria-selected', checked);

    // change state on the original option tags
    tags.each(function() {
      if(this.value === val) {
        this.selected = checked;
      } else if(!self.options.multiple) {
        this.selected = false;
      }
    });

    // some additional single select-specific logic
    if(!self.options.multiple) {
      self.labels.removeClass('ui-state-active');
      $this.closest('label').toggleClass('ui-state-active', checked);

      // close menu
      self.close();
    }

    // fire change on the select box
    self.element.trigger("change");

    // setTimeout is to fix multiselect issue #14 and #47. caused by jQuery issue #3827
    // http://bugs.jquery.com/ticket/3827
    setTimeout($.proxy(self.update, self), 10);
  });

  // close each widget when clicking on any other element/anywhere else on the page
  $doc.bind('mousedown.' + this._namespaceID, function(event) {
    var target = event.target;

    if(self._isOpen
        && target !== self.button[0]
        && target !== self.menu[0]
        && !$.contains(self.menu[0], target)
        && !$.contains(self.button[0], target)
      ) {
      self.close();
    }
  });

  // deal with form resets.  the problem here is that buttons aren't
  // restored to their defaultValue prop on form reset, and the reset
  // handler fires before the form is actually reset.  delaying it a bit
  // gives the form inputs time to clear.
  $(this.element[0].form).bind('reset.multiselect', function() {
    setTimeout($.proxy(self.refresh, self), 10);
  });
},

// set button width
_setButtonWidth: function() {
  var width = this.element.outerWidth();
  var o = this.options;

  if(/\d/.test(o.minWidth) && width < o.minWidth) {
    width = o.minWidth;
  }

  // set widths
  this.button.outerWidth(width);
},

// set menu width
_setMenuWidth: function() {
  var m = this.menu;
  m.outerWidth(this.button.outerWidth());
},

// move up or down within the menu
_traverse: function(which, start) {
  var $start = $(start);
  var moveToLast = which === 38 || which === 37;

  // select the first li that isn't an optgroup label / disabled
  var $next = $start.parent()[moveToLast ? 'prevAll' : 'nextAll']('li:not(.ui-multiselect-disabled, .ui-multiselect-optgroup-label)').first();

  // if at the first/last element
  if(!$next.length) {
    var $container = this.menu.find('ul').last();

    // move to the first/last
    this.menu.find('label')[ moveToLast ? 'last' : 'first' ]().trigger('mouseover');

    // set scroll position
    $container.scrollTop(moveToLast ? $container.height() : 0);

  } else {
    $next.find('label').trigger('mouseover');
  }
},

// This is an internal function to toggle the checked property and
// other related attributes of a checkbox.
//
// The context of this function should be a checkbox; do not proxy it.
_toggleState: function(prop, flag) {
  return function() {
    if(!this.disabled) {
      this[ prop ] = flag;
    }

    if(flag) {
      this.setAttribute('aria-selected', true);
    } else {
      this.removeAttribute('aria-selected');
    }
  };
},

_toggleChecked: function(flag, group) {
  var $inputs = (group && group.length) ?  group : this.inputs;
  var self = this;

  // toggle state on inputs
  $inputs.each(this._toggleState('checked', flag));

  // give the first input focus
  $inputs.eq(0).focus();

  // update button text
  this.update();

  // gather an array of the values that actually changed
  var values = $inputs.map(function() {
    return this.value;
  }).get();

  // toggle state on original option tags
  this.element
    .find('option')
    .each(function() {
      if(!this.disabled && $.inArray(this.value, values) > -1) {
        self._toggleState('selected', flag).call(this);
      }
    });

  // trigger the change event on the select
  if($inputs.length) {
    this.element.trigger("change");
  }
},

_toggleDisabled: function(flag) {
  this.button.attr({ 'disabled':flag, 'aria-disabled':flag })[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled');

  var inputs = this.menu.find('input');
  var key = "ech-multiselect-disabled";

  if(flag) {
    // remember which elements this widget disabled (not pre-disabled)
    // elements, so that they can be restored if the widget is re-enabled.
    inputs = inputs.filter(':enabled').data(key, true)
  } else {
    inputs = inputs.filter(function() {
      return $.data(this, key) === true;
    }).removeData(key);
  }

  inputs
    .attr({ 'disabled':flag, 'arial-disabled':flag })
    .parent()[ flag ? 'addClass' : 'removeClass' ]('ui-state-disabled');

  this.element.attr({
    'disabled':flag,
    'aria-disabled':flag
  });
},

// open the menu
open: function(e) {
  var self = this;
  var button = this.button;
  var menu = this.menu;
  var speed = this.speed;
  var o = this.options;
  var args = [];

  // bail if the multiselectopen event returns false, this widget is disabled, or is already open
  if(this._trigger('beforeopen') === false || button.hasClass('ui-state-disabled') || this._isOpen) {
    return;
  }

  var $container = menu.find('ul').last();
  var effect = o.show;

  // figure out opening effects/speeds
  if($.isArray(o.show)) {
    effect = o.show[0];
    speed = o.show[1] || self.speed;
  }

  // if there's an effect, assume jQuery UI is in use
  // build the arguments to pass to show()
  if(effect) {
    args = [ effect, speed ];
  }

  // set the scroll of the checkbox container
  $container.scrollTop(0).height(o.height);

  // positon
  this.position();

  // show the menu, maybe with a speed/effect combo
  $.fn.show.apply(menu, args);

  // select the first not disabled option
  // triggering both mouseover and mouseover because 1.4.2+ has a bug where triggering mouseover
  // will actually trigger mouseenter.  the mouseenter trigger is there for when it's eventually fixed
  this.labels.filter(':not(.ui-state-disabled)').eq(0).trigger('mouseover').trigger('mouseenter').find('input').trigger('focus');

  button.addClass('ui-state-active');
  this._isOpen = true;
  this._trigger('open');
},

// close the menu
close: function() {
if(this._trigger('beforeclose') === false) {
    return;
  }

  var o = this.options;
  var effect = o.hide;
  var speed = this.speed;
  var args = [];

  // figure out opening effects/speeds
  if($.isArray(o.hide)) {
    effect = o.hide[0];
    speed = o.hide[1] || this.speed;
  }

  if(effect) {
    args = [ effect, speed ];
  }

  $.fn.hide.apply(this.menu, args);
  this.button.removeClass('ui-state-active').trigger('blur').trigger('mouseleave');
  this._isOpen = false;
  this._trigger('close');
},

enable: function() {
  this._toggleDisabled(false);
},

disable: function() {
  this._toggleDisabled(true);
},

checkAll: function(e) {
  this._toggleChecked(true);
  this._trigger('checkAll');
},

uncheckAll: function() {
  this._toggleChecked(false);
  this._trigger('uncheckAll');
},

getChecked: function() {
  return this.menu.find('input').filter(':checked');
},

destroy: function() {
  // remove classes + data
  $.Widget.prototype.destroy.call(this);

  // unbind events
  $doc.unbind(this._namespaceID);

  this.button.remove();
  this.menu.remove();
  this.element.show();

  return this;
},

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

widget: function() {
  return this.menu;
},

getButton: function() {
  return this.button;
},
position: function () {
  var o = this.options;

  // use the position utility if it exists and options are specifified
  if ($.ui.position && !$.isEmptyObject(o.position)) {
      o.position.of = o.position.of || this.button;

      this.menu
      .show()
      .position(o.position)
      .hide();

      // otherwise fallback to custom positioning
  } else {
      var pos = this.button.offset();

      this.menu.css({
          top: pos.top + this.button.outerHeight(),
          left: pos.left
      });
  }
},

// react to option changes after initialization
_setOption: function (key, value) {
  var menu = this.menu;

  switch (key) {
      case 'header':
          menu.find('div.ui-multiselect-header')[value ? 'show' : 'hide']();
          break;
      case 'checkAllText':
          menu.find('a.ui-multiselect-all span').eq(-1).text(value);
          break;
      case 'uncheckAllText':
          menu.find('a.ui-multiselect-none span').eq(-1).text(value);
          break;
      case 'height':
          menu.find('ul').last().height(parseInt(value, 10));
          break;
      case 'minWidth':
          this.options[key] = parseInt(value, 10);
          this._setButtonWidth();
          this._setMenuWidth();
          break;
      case 'selectedText':
      case 'selectedList':
      case 'noneSelectedText':
          this.options[key] = value; // these all needs to update immediately for the update() call
          this.update();
          break;
      case 'classes':
          menu.add(this.button).removeClass(this.options.classes).addClass(value);
          break;
      case 'multiple':
          menu.toggleClass('ui-multiselect-single', !value);
          this.options.multiple = value;
          this.element[0].multiple = value;
          this.refresh();
          break;
      case 'position':
          this.position();
  }

  $.Widget.prototype._setOption.apply(this, arguments);
}
});

})(jQuery);

当我在下拉列表中应用此脚本时,它将影响我的网页中的所有下拉列表。如何限制?

1 个答案:

答案 0 :(得分:1)

提供您希望定位唯一ID的下拉列表,并在初始化插件时使用它。

e.g。

$("#myUniqueId").multiSelect();