分享

Overview of the Prototype Javascript Library

 yeqiwei 2006-01-10

Overview of the Prototype Javascript Library

The following is a brief overview of what functionality is provided by the Prototype Javascript Library. It contains a number of useful functions, fixes for browser bugs, and I think it is also a good model for how a javascript library should be written. The homepage for the Prototype Library is http://prototype./, and the latest version of the Prototype Library can be found at http://dev./repos/prototype/dist/prototype.js. Unfortunately the documentation on the site for this library is completely non-existant, and therefore this document is necessary in avoiding having to read through the source code to figure out what is available. The licensing of the Prototype library allows free, unrestricted use of the code as far as I can tell, but I‘m not a lawyer so...

The claim is that the Protoype Library supports the following browsers:

  • Microsoft Internet Explorer for Windows, version 6.0 and higher
  • Mozilla Firefox 1.0/Mozilla 1.7 and higher
  • Apple Safari 1.2 and higher

The Prototype Library is broken up into 10 seperate subcomponents, we will look at each one individually.

Base

The base subcomponent contains a few useful objects and methods for using JavaScript in a more Object-Oriented manner, as well as a few helper functions.

  • Class: The class object is used to create classes. So, when defining a new class, we‘d use the following form.
        var PeriodicalExecuter = Class.create();
  • Abstract: Used to create an abstract class. Really this is just an empty Object.
  • Try: A helper object for iterating through a list of functions that may or may not throw exceptions, and returning the result from the first function that runs successfully. Useful for things like
        var transport = Try.these(
          function() {return new ActiveXObject(‘Msxml2.XMLHTTP‘)},
          function() {return new ActiveXObject(‘Microsoft.XMLHTTP‘)},
          function() {return new XMLHttpRequest()}
        );
  • Object.extend(destination, source): Useful for creating inherited classes. All this does is copy all of the properties, fields, and methods from the source class (the one we‘re inheriting from) to the destination class. A simple example use of this function is as follows.
      setOptions: function(options) {
        this.options = {
          method:       ‘post‘,
          asynchronous: true,
          parameters:   ‘‘
        }
        Object.extend(this.options, options || {});
      }
    This setOptions function creates a default set of options, this.options, and then uses the extend function to add any other options that were passed to the function. This is a really simple example, but should show how this function can make code much more readable.
  • Function.prototype.bind(object): Used to bind a function to an object.
  • Function.prototype.bindAsEventListener(object): Used to bind a function to an object as an event listener.
  • Number.prototype.toColorPart(): Converts a number into its two digit hexadecimal equivalent (ie. 255 => FF, 10 => 0A, etc.).
  • PeriodicalExecuter: Used to call a specific function at regular intervals.
  • $(): This is a helper function. It ensures that we are always dealing with references to elements, and not their names. It can be passed a single object, or an array of objects, and it will return the proper element references. The parameters can be either strings, specifying the id‘s of the elements, in which case the result will be that of document.getElementById(), or the actual elements themselves, in which case the result will just be the same element that was passed in.

Compat

The Compat subcomponent contains a few methods to help with cross-browser compatibility. At the moment it contains only the two functions.

  • Array.prototype.push : Allows the push method on arrays, which simply append an element, or an array of elements, to the end of the array.
  • Function.prototype.apply(object, parameters): Allows a function to be called on an object. Binds the function to the object, so that ‘this‘ references in the function will resolve correctly.

String

The String subcomponent adds the following methods to the String object

  • stripTags(): Strips all HTML tags. Does not handle encoded tags, and just calls the following regular expression:
    this.replace(/<\/?[^>]+>/gi, ‘‘);
  • escapeHTML() and unescapeHTML(): These two functions should be obvious. It performs these functions in a rather clever, interesting way, and the code for these functions is as follows:
      escapeHTML: function() {
        var div = document.createElement(‘div‘);
        var text = document.createTextNode(this);
        div.appendChild(text);
        return div.innerHTML;
      }
    
      unescapeHTML: function() {
        var div = document.createElement(‘div‘);
        div.innerHTML = this.stripTags();
        return div.childNodes[0].nodeValue;
      }
  • parseQuery(): Simply returns an associative array of the parameters and values in string that it is called on. The source string must be of the form name1=value1&name2=value2.

Enumerable

The Enumerable subcomponent contains the definition for the Enumerable object, which is an extremely useful object for working with collections. It is also an excellent example of how the Object.extend method should be used, and also contains a really interesting use of the exception handling ability of JavaScript, with the _break and _continue objects. Therefore, I‘m just including the entire source code of this subcomponent.

var _break    = new Object();
var _continue = new Object();

var Enumerable = {
  each: function(iterator) {
    var index = 0;
    try {
      this._each(function(value) {
        try {
          iterator(value, index++);
        } catch (e) {
          if (e != _continue) throw e;
        }
      });
    } catch (e) {
      if (e != _break) throw e;
    }
  },
  
  all: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      if (!(result &= (iterator || Prototype.K)(value, index))) 
        throw _break;
    });
    return result;
  },
  
  any: function(iterator) {
    var result = true;
    this.each(function(value, index) {
      if (result &= (iterator || Prototype.K)(value, index)) 
        throw _break;
    });
    return result;
  },
  
  collect: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      results.push(iterator(value, index));
    });
    return results;
  },
  
  detect: function (iterator) {
    var result;
    this.each(function(value, index) {
      if (iterator(value, index)) {
        result = value;
        throw _break;
      }
    });
    return result;
  },
  
  findAll: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (iterator(value, index))
        results.push(value);
    });
    return results;
  },
  
  grep: function(pattern, iterator) {
    var results = [];
    this.each(function(value, index) {
      var stringValue = value.toString();
      if (stringValue.match(pattern))
        results.push((iterator || Prototype.K)(value, index));
    })
    return results;
  },
  
  include: function(object) {
    var found = false;
    this.each(function(value) {
      if (value == object) {
        found = true;
        throw _break;
      }
    });
    return found;
  },
  
  inject: function(memo, iterator) {
    this.each(function(value, index) {
      memo = iterator(memo, value, index);
    });
    return memo;
  },
  
  invoke: function(method) {
    var args = $A(arguments).slice(1);
    return this.collect(function(value) {
      return value[method].apply(value, args);
    });
  },
  
  max: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (value >= (result || value))
        result = value;
    });
    return result;
  },
  
  min: function(iterator) {
    var result;
    this.each(function(value, index) {
      value = (iterator || Prototype.K)(value, index);
      if (value <= (result || value))
        result = value;
    });
    return result;
  },
  
  partition: function(iterator) {
    var trues = [], falses = [];
    this.each(function(value, index) {
      ((iterator || Prototype.K)(value, index) ? 
        trues : falses).push(value);
    });
    return [trues, falses];
  },
  
  pluck: function(property) {
    var results = [];
    this.each(function(value, index) {
      results.push(value[property]);
    });
    return results;
  },
  
  reject: function(iterator) {
    var results = [];
    this.each(function(value, index) {
      if (!iterator(value, index))
        results.push(value);
    });
    return results;
  },
  
  sortBy: function(iterator) {
    return this.collect(function(value, index) {
      return {value: value, criteria: iterator(value, index)};
    }).sort(function(left, right) {
      var a = left.criteria, b = right.criteria;
      return a < b ? -1 : a > b ? 1 : 0;
    }).pluck(‘value‘);
  },
  
  toArray: function() {
    return this.collect(Prototype.K);
  },
  
  zip: function() {
    var iterator = Prototype.K, args = $A(arguments);
    if (typeof args.last() == ‘function‘)
      iterator = args.pop();

    var collections = [this].concat(args).map($A);
    return this.map(function(value, index) {
      iterator(value = collections.pluck(index));
      return value;
    });
  }
}

Object.extend(Enumerable, {
  map:     Enumerable.collect,
  find:    Enumerable.detect,
  select:  Enumerable.findAll,
  member:  Enumerable.include,
  entries: Enumerable.toArray
});

Array

The Array subcomponent contains the $A() function which converts a regular Javascript Array into an Enumerable object (as defined in the Enumerable subcomponent). It also adds the functions _each(iterator), first(), and last() to the standard Array object.

Ajax

The Ajax subcomponent contains a simple object, called Ajax, which essentially provides a cross-browser solution for using the XMLHttpRequest object. There are a number of Ajax objects:

  • Ajax.Base: A basic Ajax from which the other Ajax objects are extended from. The following methods are supported:
    • setOptions(options): Used to set the values for the options, method which is either ‘get‘ or ‘post‘, asynchronous which is either true or false, and parameters which is a string of name=value pairs to be sent with the request. The options are just an associative array.
    • responseIsSuccess() and responseIsFailure(): For determining whether the previous request was successful.
  • Ajax.Request: Inherits from Ajax.Base. Adds more functionality required for making basic requests. Includes the following methods:
    • initialize(url, options): Peforms a request on the given url, using the options as specified.
    • request(url): Performs a request on the given url. Assumes that the options have been previously set.
    • setRequestHeaders(): Sets the request headers to match those found in the options.requestHeaders array, which is of the form [‘name1‘, ‘value1‘, ‘name2‘, ‘value2‘, ...].
    • onStateChange(): Used internally to handle the stateChange events, calls the respondToReadyState function if the readyState is 1.
    • evalJSON(): If there is a response header named X-JSON, then this method eval‘s the value of that header and returns the result.
    • respondToReadyState(readyState): calls evalJSON, then calls any events that have been set in the options. The way to specify a handler in the options would be to have an entry like {‘onSuccess‘ : myFunction } in the options, which is just an associative array.
  • Ajax.Updater: Inherits from AjaxRequest. Includes additional functionality so that two containers can be set, a success container and a failure container. The containers are HTML elements, and then when the response is received from the server, the element‘s innerHTML is set to be the reponse, or if the options.insertion function is set to be a function of the Insertion type defined in the DOM subcomponent, then the response is inserted into the container using that type of Insertion. Optionally, if the options.evalScripts property is set to true, then any <script> tags that are included in the response will be evaluated.
  • Ajax.PeriodicalUpdater: Inherits from AjaxBase. Allows for an Ajax.Updater object to be called at regular intervals, as specified by the options.frequency property. Also has start() and stop() methods that do what you‘d guess.

DOM

The DOM subcomponent provides a number of methods and objects for making it easier to work with the DOM. They are as follows:

  • document.getElementsByClassName(className): Just like getElementsByTagName, but this method returns all of the elements in the document which have the specified name defined in their className property (which is the value of the class attribute for the element).
  • Element: The element class extends the Object object to add a few more very useful helper methods, which are as follows:
    • toggle(): This function toggles the value of the style.display attribute for an element, or an array of elements (or element id‘s, as the $() function is applied to the arguments.
    • hide(): This function sets the value of the style.display attribute for an element, or an array of elements, to ‘none‘.
    • show():  This function sets the value of the style.display attribute for an element, or an array of elements, to ‘‘.
    • remove(element): Removes the element, by calling removeChild on the elements‘ parentNode.
    • getHeight(element): Returns the offsetHeight for the element.
    • hasClassName(element, className): Returns whether the element has that name in its className property.
    • addClassName(element, className): Adds a class name to the className property of the element.
    • removeClassName(element, className): Removes a class name from the className property of the element.
    • cleanWhitespace(element): Removes all whitespace-only text node children.
  • Insertion: Allows for insertion of Content into an Element at a certain point. Insertion points are ‘beforeBegin‘, ‘afterBegin‘, ‘beforeEnd‘, and ‘afterEnd‘. It defines the Insertion.Before, Insertion.Top, Insertion.Bottom, and Insertion.After objects to handle each of these Insertion points respectively.

Form

The Form subcomponent provides a useful wrapper for HTML Forms, and their fields. It defines the following objects:

  • Field: A field represents any form element. The following methods are defined:
    • clear(): Sets the value of the field to be ‘‘. Can also take an array of fields, in which case it will clear each field in the array.
    • focus(element): Sets the focus to the element.
    • present(): Pass this an array of form elements, and it‘ll determine whether all of their values are anything other than an empty string.
    • select(element): Calls select on the form element.
    • activate(element): Calls focus, and then select on the form element.
  • Form: A JavaScript object defined to provide additional functionality for working with HTML Forms. The following methods are defined:
    • serialize(form): Serializes the form to a string, in the form name1=value1&name2=value2&...
    • getElements(form): Returns all of the Form.Element objects for a form.
    • getInputs(form, typeName, name): Returns all of the input elements from a form, optionally specifying a typeName and name to filter by.
    • disable(form): Calls blur on each element in the form and sets their disabled property to true.
    • enable(form): Sets the disabled property on every element in the form to be ‘‘.
    • focusFirstElement(form): Sets the focus to the first element in the form.
    • reset(form): Calls reset on the form.
  • Form.Element: Represents an element in an HTML Form. Seems to be used for serializing form elements. The methods supported are serialize(element), and getValue(element). Also, the function $F() is defined as a shortcut to the getValue.
  • Form.Element.Serializers: Four serializers are defined. input is used for basic input types, which are submit, hidden, password, text, checkbox, and radio. inputSelector is used for checkboxes and radio inputs. textarea is used for text areas. select is used for select boxes.
  • Abstract.TimedObserver: An abstract class, used for attaching a function to an element, where the function will be called at regular intervals.
  • Form.Element.Observer and Form.Observer: Inherit from the Abstract.TimedObserver class. Used to bind a function to a form element or a form, such that the function will be called at regular intervals.
  • Abstract.EventObserver: An abstract class used to attach a callback function to an element such that the callback function will be called on an event. The events that will trigger the callback are the onclick event for checkboxes or radio inputs, and the onchange event for password boxes, text boxes, textareas, and select boxes.
  • Form.Element.EventObserver and Form.EventObserver: Inherits from the Abstract.EventObserver class. Used to bind callback functions to form elements or forms.

Event

The Event subcomponent extends the standard Event object with much more functionality. Constants for various keystrokes are defined, such as KEY_BACKSPACE, KEY_TAB, KEY_RETURN, KEY_ESC, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN, and KEY_DELETE. The following methods are added to the Event object.

  • element(event): Returns the source of the event, using either event.target, or event.srcElement.
  • isLeftClick(event): Returns whether the event was triggered by a left click.
  • pointerX(event) and pointerY(event): Return the X or Y coordinates of the mouse pointer.
  • stop(event): Stops the event from bubbling.
  • findElement(event, tagName): Finds the first node with the given tagName, starting from the node the event was triggered on and moving up the DOM.
  • _observeAndCache(element, name, observer, useCapture): "Private" method, used to add an event listener to an element. Keeps track of the observers so that they can later be deleted in order to clean up for memory leaks in IE.
  • unloadCache: Clears all of the observers.
  • observe(element, name, observer, useCapture): Used to attach an event handler (or observer) to an element.
  • stopObserving(element, name, observer, useCapture): Disconnects an event handler (or observer) from an element.

To prevent memory leaks in IE, this subcomponent does the following:

Event.observe(window, ‘unload‘, Event.unloadCache, false);

Position

The Position subcomponent defines the Position class which provides the following methods to assist with the positioning of elements.

  • prepare(): This method must be called before calling withinIncludingScrolloffset if the page has been scrolled since the last time it was called.
  • realOffset(element): Returns an array [left, top] where left and top are the sum of the scrollLeft and scrollTop values between the element and its parentNode, and the parentNode and its parentNode, all the way up the DOM tree.
  • cumulativeOffset(element): Returns an array [left, top] where left and top are the sum of the offsetLeft and offsetTop values between the element and its offsetParent, and the offsetParent and its offsetParent, all the way up the DOM tree.
  • within(element, x, y): Determines whether the point (x, y) lies within the element.
  • withinIncludingScrolloffsets(element, x, y): Same as above, but seems to be required when draggable elements are contained within a scrollable element. Causes major Firefox performance problems.
  • overlap(mode, element): Mode is either ‘horizontal‘ or ‘vertical‘. Must call within directly before this function. Determines the amount that the point passed to within overlaps the element, either horizontally or vertically, as set by the mode.
  • clone(source, target): Sets the top, left, width, and height for the source element to be identical to that of the target element. Uses absolute positioning to place the source target.

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多