widgetsBasic.js

Summary

No overview generated for 'widgetsBasic.js'


// This file implements some basic, but usable widgets, with an eye
// towards filling in the holes that HTML has w.r.t. XUL
// support.

/**
  LabelWidget - simple demo widget showing constant text, surprisingly
  useful

  @summary The LabelWidget is primarily the simplest possible usable
  widget. (This is also why methods I'd normally leave undocumented
  are documented here, for educational purposes.) It is simply a text
  span on the screen; due to the way HTML works and how simple this
  Widget is the text inside can not even be styled; the label widget
  is simply a <span> with a text node.) However, due to how
  hard/annoying the DOM makes it to have this sort of "label", I find
  myself using this in real code all the time, since it integrates so
  well with the rest of XBLinJS; trivial, yes, useless, no.

  <p>The widget does assume you aren't going to muck around with the
  insides directly; if you fragment the internal text node or do any
  other crazy DOM things, the value you retrieve from it will be
  wrong.</p> 

  <p><b>Relevant Parameters</b>:</p>

  <ul>
    <li><b>value</b> (get/set): The value of the text in the
        Label. (Note the use of <tt>.get_value</tt> and
        <tt>.set_value</tt> to implement this.)</li>
    </ul>

  <p><b>Inheritances</b>:</p>

  <p>The LabelWidget is a &lt;span&gt; that inherits everything
  ("*").</p> 

*/
deriveNewWidget("LabelWidget", Widget);

/**
  Defines the content of the LabelWidget, a &lt;span&gt; tag.
*/
LabelWidget.prototype.content = {
  tagName: "span", name: "span", appendTarget: "default",
  inherits: "*"
}

/**
  Retrieves the current text of the LabelWidget and returns
  it. 

  <p>Note how it actually uses DOM functions to retrieve the text;
  this means no duplication of that value in memory. Normally I'd
  consider this silly, but this is good technique to show.</p>

  <p>Note you <i>should not</i> call this directly; call
  <tt>widget.get("value")</tt>. This is documented for educational
  purposes, not use.</p>
*/
LabelWidget.prototype.get_value = function () {
  if (this.span.childNodes.length) {
    return this.span.childNodes[0].data;
  } 
  return "";
}

/**
  Sets the current value of the widget to the given text, removing
  any text that may currently be there.

  <p>Note you <i>should not</i> call this directly; call
  <tt>widget.set("value", "your new text");</tt>. This is documented
  for educational purposes only, not use.</p>
*/
LabelWidget.prototype.set_value = function (val) {
  while (this.span.childNodes.length) {
    this.span.removeChild(this.span.childNodes[0]);
  }
  this.appendChild(textNode(val));
}

/**
  Widget wrapping a button
*/

/**
  Widget for submitting values to an HTTP form, automatically creating
  fields as needed.

  @summary FormSubmitWidget encapsulates submitting a form. If you
  really go to town with dynamic Javascript interfaces, it is nice
  not to have to worry about creating literal form elements for 
  your submission. 

  <p>This simple widget creates a form with nothing in it, so there is
  no user-visible node on the screen. When <tt>.submit(argObj)</tt>,
  the form will be submitted as normal in HTTP forms.</p>

  <p><b>Inheritances</b>:</p>

  <p>The <tt>&lt;form&gt;</tt> element of the FormSubmitWidget
  inherits all attributes ("*"), so set the form up with .setAttribute()
  as you would in HTML.</p>

*/
deriveNewWidget("FormSubmitWidget", Widget);

FormSubmitWidget.prototype.content = {
  tagName: "form", inherits: "*",
  appendTarget: "default", name: "form"
}

/**
  Do the form submission.

  @param argObj A Javascript object containing the key: value pairs
  you wish to submit to the <tt>action</tt> via the Widget's
  <tt>method</tt>. If the value is a list of strings, multiple values
  will be submitted with that same key. (This shows up in
  a querystring as <tt>a=1&a=2</tt>.)
*/
FormSubmitWidget.prototype.submit = function (argObj) {
  for (var key in argObj) {
    var value = argObj[key];
    var formElement;
    if (value instanceof Array) {
      for (var idx in value) {
        var thisValue = value[idx];
        formElement = create("input", {type: "hidden", name: key,
                                           value: thisValue});
        this.appendChild(formElement);
      }
    } else {
      formElement = create("input", {type: "hidden", name: key,
                                         value: argObj[key]});
      this.appendChild(formElement);
    }
  }
  this.form.submit();
}

/**
  SelectWidget - a wrap around &lt;select&gt;

  @summary SelectWidget is a wrapper around the &lt;select&gt; widget,
  because it is a pain to deal with in <tt>.content</tt>
  specifications.

  <p>Terminology note: I refer to what the user sees on the screen as
  the <b>human choice</b>, and what the widget returns as the value
  as the <b>computer choice</b>. For example, with
  <tt>&lt;option value='#FF0000'&gt;red&lt;/option&gt;</tt>,
  the human value is "red", but the computer value is "#FF0000".</p>

  <p><b>Relevant Parameters</b>:</p>

  <ul>
    <li><b>values</b>: An array of possible &lt;options&gt;. Each option
        should be in the order it will appear on the screen, and may
        be one of two things:
        <ol><li>A string which is both the human value, and the 
            computer value if that is the current choice.</li>
            <li>A Javascript array, where the first value is the 
            computer value, and the second is the human value.
            For instance, if I was offering the user a
            choice of "Michigan" which I wanted to have the postal
            abbrevation of "MI" for, I'd put <tt>["MI",
            "Michigan"]</tt> as the value.</li>
          </ol>
        This may be reset but if it is, it will blow away any other
        options that used to be available.
        </li>
      <li><b>value</b>: Read/write the current computer value of the widget.
          (The select widget <tt>inherits</tt> this, so behavior if
          the written value is not in the select widget will be
          browser-defined.)</li>
    </ul>

  <p><b>Inheritances</b>:</p>

  <p>The &lt;select&gt; DOM node inherits everything ("*").</p>

*/
deriveNewWidget("SelectWidget", Widget);

// Must set "values" before we can set the "value" during
// initialization
/** 
  We have to set .values before we can set .value during
  initialization, for a reason that should be clear upon reflection.

  @private
*/
SelectWidget.prototype.initOrder = [
  "values", "value"
]

/**
  @private
*/
SelectWidget.prototype.defaults = {index: 0};

/** 
  @private
*/
SelectWidget.prototype.content = {
  tagName: "select", name: "select", inherits: "*"
}

/**
  @private
*/
SelectWidget.prototype.Variables = [
  ["value", ValueVar, undefined, "select"]
];

/** 
  @private
*/
SelectWidget.prototype.set_values = function (values) {
  this.empty();

  for (var idx in values) {
    var value = values[idx];
    if (value instanceof Array) {
      this.addOption.apply(this, value);
    } else {
      this.addOption(value);
    }
  }
}

/**
  Adds a single option to the end of the widget.

  @param computerValue The value that will be used as the computer
         value for the choice.
  @param humanValue The value the human will see. If not given, 
         the computer value will be used instead.
*/
SelectWidget.prototype.addOption = function (computerValue, humanValue) {
  if (humanValue == undefined) {
    humanValue = computerValue;
  }

  var option = create("option", {value: computerValue}, humanValue);
  this.select.appendChild(option);
}

/**
  empty - remove all choices from the widget
*/
SelectWidget.prototype.empty = function () {
  emptyNode(this.select);
}

/**
  Wraps any DOM node

  @summary This widget wraps any DOM node and provides the Widget
  functionality. Use this when you have something that doesn't really
  need to be a fully-fledged custom widget, but where you'd still like 
  to tap into Widget capabilities, such as the cascading lookup
  support.

  <p>This is probably one of those things you can't think of a use
  for, until one day you suddenly need it. (I use it to dynamically
  create buttons that, when clicked, want to fire an event into
  another Widget, which the Widget event system handles by design.)</p>

  <p><b>Relevant Parameters</b>:</p>

  <ul>
    <li><b>domNode</b>: The DOM node to wrap, either as a pre-existing
        DOM node (possibly even one that already exists on the
        screen), or as an object specfication that
        <tt>createObject</tt> can consume. Will be turned into a 
        DOM node, of course, and this widget will then work as normal.
        </li>
    </ul>

  <p><b>Inheritances</b>:</p>

  <p>As a wrapper, the root .domNode will inherit everything ("*"), so
  you can use setAttribute and .getAttribute just as you would on the
  widget. (For methods, you have to go to DOM(widget); sorry, if
  Javascript had a __getattr__ like Python or something, I'd finish
  the transparent delegation, but it doesn't...</p>

*/
deriveNewWidget("DOMWrap", Widget);

/**
  Do not every create a default; if the user doesn't supply something, 
  game over.
*/
DOMWrap.prototype.content = false;

DOMWrap.prototype.set_domNode = function (nodeSpec) {
  if (nodeSpec.nodeType) {
    this.domNode = nodeSpec;
    return;
  }
  if (typeof nodeSpec == OBJECT_TYPE) {
    this.domNode = this.createObject(nodeSpec);
    return;
  }
  throw ("Illegal nodeSpec passed to set('domNode'). nodeSpec was: " +
         nodeSpec);
}

DOMWrap.prototype.initDOM = function (atts) {
  this.processAtt(atts, "domNode");

  // register the inherits: "*" to the domNode
  this.inherits.register("*", this.domNode);

  Widget.prototype.initDOM.apply(this, arguments);
}

DOMWrap.prototype.setAttribute = function (key, value) {
  if (key != "domNode") {
    DOM(this)[key] = value;
  } else {
    Widget.prototype.setAttribute.apply(this, arguments);
  }
}
DOMWrap.prototype.getAttribute = function (key) {
  return DOM(this)[key];
}



Documentation generated by JSDoc on Tue May 3 17:16:26 2005