Alien-GvaScript

 view release on metacpan or  search on metacpan

src/choiceList.js  view on Meta::CPAN


//----------------------------------------------------------------------
// CONSTRUCTOR
//----------------------------------------------------------------------

GvaScript.ChoiceList = function(choices, options) {
  if (! (choices instanceof Array) )
    throw new Error("invalid choices argument : " + choices);
  this.choices = choices;

  var defaultOptions = {
    labelField       : "label",
    classes          : {},        // see below for default classes
    idForChoices     : "CL_choice",
    keymap           : null,
    grabfocus        : false,
    mouseovernavi    : true,
    scrollCount      : 5,
    choiceItemTagName: "div",
    htmlWrapper      : function(html) {return html;},
    paginator        : null
  };


  this.options = Class.checkOptions(defaultOptions, options);

  var defaultClasses = {
    choiceItem      : "CL_choiceItem",
    choiceHighlight : "CL_highlight"
  };
  this.classes = Class.checkOptions(defaultClasses, this.options.classes);

  // handy vars
  this.hasPaginator = this.options.paginator != null;
  this.pageSize = (
                    // the step size of the paginator if any
                    (this.hasPaginator && this.options.paginator.options.step)
                    ||
                    // scroll count
                    this.options.scrollCount
                  );

  // prepare some stuff to be reused when binding to inputElements
  this.reuse = {
    onmouseover : this._listOverHandler.bindAsEventListener(this),
    onclick     : this._clickHandler.bindAsEventListener(this),
    ondblclick  : this._dblclickHandler.bindAsEventListener(this),
    navigationRules: {
      DOWN:      this._highlightDelta.bindAsEventListener(this, 1),
      UP:        this._highlightDelta.bindAsEventListener(this, -1),

      PAGE_DOWN: this._highlightDelta.bindAsEventListener(this, this.pageSize),
      PAGE_UP:   this._highlightDelta.bindAsEventListener(this, -this.pageSize),

      HOME:      this._jumpToIndex.bindAsEventListener(this, 0),
      END:       this._jumpToIndex.bindAsEventListener(this, 99999),

      RETURN:    this._returnHandler .bindAsEventListener(this),
      ESCAPE:    this._escapeHandler .bindAsEventListener(this)
    }
  };

  if(this.hasPaginator) {
    // next/prev page
    this.reuse.navigationRules.RIGHT
        = this._highlightDelta.bindAsEventListener(this, this.pageSize)
    this.reuse.navigationRules.LEFT
        = this._highlightDelta.bindAsEventListener(this, -this.pageSize);

    // first/last page
    this.reuse.navigationRules.C_HOME
        = this._jumpToPage.bindAsEventListener(this, 0);
    this.reuse.navigationRules.C_END
        = this._jumpToPage.bindAsEventListener(this, 99999);
  }
};


GvaScript.ChoiceList.prototype = {

//----------------------------------------------------------------------
// PUBLIC METHODS
//----------------------------------------------------------------------
  destroy: function() {
    // test that element still in DOM
    if(this.container) Event.stopObserving(this.container);
  },

  fillContainer: function(containerElem) {

    this.container = containerElem;
    this.container.choiceList = this;

    Element.update(this.container, this.htmlForChoices());

    // mouse events on choice items will bubble up to the container
    if(this.options.mouseovernavi) {
        Event.observe(this.container, "mouseover", this.reuse.onmouseover);
    }
    Event.observe(this.container, "click"    , this.reuse.onclick);
    Event.observe(this.container, "dblclick" , this.reuse.ondblclick);

    if (this.options.keymap) {
      this.keymap = this.options.keymap;
      this.keymap.rules.push(this.reuse.navigationRules);
    }
    else {
      this.keymap = new GvaScript.KeyMap(this.reuse.navigationRules);
      var target = this.container.tabIndex == undefined
                     ? document
                     : this.container;
      this.keymap.observe("keydown", target);
    }
    // POTENTIAL PROBLEM HERE : the keymap may stay active
    // even after the choiceList is deleted (may yield memory leaks and
    // inconsistent behaviour). But we have no "destructor", so how
    // can we unregister the keymap ?


src/choiceList.js  view on Meta::CPAN

  //----------------------------------------------------------------------

  _findChoiceItem: function(event) { // walk up DOM to find mouse target
    var stop_condition = function(elem){return elem === this.container};
    return Element.navigateDom(Event.element(event), "parentNode",
                               this.classes.choiceItem,
                               stop_condition);
  },

  _listOverHandler: function(event) {
    var elem = this._findChoiceItem(event);
    if (elem) {
      this._highlightChoiceNum(this._choiceIndex(elem), false);
      if (this.options.grabfocus)
        this.container.focus();
      Event.stop(event);
    }
  },

  // no _listOutHandler needed

  _dblclickHandler: function(event) {
    var elem = this._findChoiceItem(event);
    if (elem) {
      var newIndex = this._choiceIndex(elem);
      this._highlightChoiceNum(newIndex, false);
      this._clickHandler(event);
    }
  },

  _clickHandler: function(event) {
    var elem = this._findChoiceItem(event);
    if (elem) {
      var newIndex = this._choiceIndex(elem);
      // check if choice is selected
      if (this.currentHighlightedIndex == newIndex) {
        // selected -> fire ping event
        var toStop = this.fireEvent({type : "Ping",
                                    index: this._choiceIndex(elem)},
                                    elem,
                                    this.container);
        Event.detailedStop(event, toStop || Event.stopAll);
      }
      else {
        // not selected -> select
        this._highlightChoiceNum(newIndex, false);
      }
    }
  },

  _returnHandler: function(event) {
    var index = this.currentHighlightedIndex;
    if (index != undefined) {
      var elem = this._choiceElem(index);
      var toStop = this.fireEvent({type : "Ping",
                                   index: index}, elem, this.container);
      Event.detailedStop(event, toStop || Event.stopAll);
    }
  },

  _escapeHandler: function(event) {
    var toStop = this.fireEvent("Cancel", this.container);
    Event.detailedStop(event, toStop || Event.stopAll);
  }

};



( run in 1.250 second using v1.01-cache-2.11-cpan-f5b5a18a01a )