#-- # Copyright (c) 2007 by Michael Neumann (mneumann@ntecs.de) # # Copyright 2007 Google Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may not # use this file except in compliance with the License. You may obtain a copy of # the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations under # the License. #++ class DOM #------------------------------------------------------------------- # Element creation #------------------------------------------------------------------- # # Creates an HTML element. # # tagName:: the HTML tag of the element to be created # return:: the newly-created element # def self.createElement(tagName) `return document.createElement(#)` end # # Creates an HTML A element. # # return:: the newly-created element # def self.createAnchor createElement("A") end # # Creates an HTML BUTTON element. # # return:: the newly-created element # def self.createButton() createElement("button") end # # Creates an HTML CAPTION element. # # return:: the newly-created element # def self.createCaption createElement("caption") end # # Creates an HTML COL element. # # return:: the newly-created element # def self.createCol createElement("col") end # # Creates an HTML COLGROUP element. # # return:: the newly-created element # def self.createColGroup createElement("colgroup") end # # Creates an HTML DIV element. # # return:: the newly-created element # def self.createDiv createElement("div") end # # Creates an HTML FIELDSET element. # # return:: the newly-created element # def self.createFieldSet createElement("fieldset") end # # Creates an HTML FORM element. # # return:: the newly-created element # def self.createForm createElement("form") end # # Creates an HTML IFRAME element. # # return:: the newly-created element # def self.createIFrame createElement("iframe") end # # Creates an HTML IMG element. # # return:: the newly-created element # def self.createImg createElement("img") end # # Creates an HTML LABEL element. # # return:: the newly-created element # def self.createLabel createElement("label") end # # Creates an HTML LEGEND element. # # return:: the newly-created element # def self.createLegend createElement("legend") end # # Creates an HTML OPTIONS element. # # return:: the newly-created element # def self.createOptions createElement("options") end # # Creates an HTML SELECT element. # # multiple:: +true+ if multiple selection of options is allowed # (default +false+) # return:: the newly-created element # def self.createSelect(multiple=false) select = createElement("select") setProperty(select, "multiple", true) if multiple return select end # # Creates an HTML SPAN element. # # return:: the newly-created element # def self.createSpan createElement("span") end # # Creates an HTML TABLE element. # # return:: the newly-created element # def self.createTable createElement("table") end # # Creates an HTML TBODY element. # # return:: the newly-created element # def self.createTBody createElement("tbody") end # # Creates an HTML TD element. # # return:: the newly-created element # def self.createTD createElement("td") end # # Creates an HTML TEXTAREA element. # # return:: the newly-created element # def self.createTextArea createElement("textarea") end # # Creates an HTML TFOOT element. # # return:: the newly-created element # def self.createTFoot createElement("tfoot") end # # Creates an HTML TH element. # # return:: the newly-created element # def self.createTH createElement("th") end # # Creates an HTML THEAD element. # # return:: the newly-created element # def self.createTHead createElement("thead") end # # Creates an HTML TR element. # # return:: the newly-created element # def self.createTR createElement("tr") end # # Creates an HTML INPUT element. # # type:: the value of the type attribute # return:: the newly-created element # def self.createInput(type) ` var e = document.createElement("INPUT"); e.type = #; return e` end # # Creates an HTML INPUT type='CHECK' element. # # return:: the newly-created element # def self.createInputCheck createInput("checkbox") end # # Creates an HTML INPUT type='PASSWORD' element. # # return:: the newly-created element # def self.createInputPassword createInput("password") end # # Creates an HTML INPUT type='TEXT' element. # # return:: the newly-created element # def self.createInputText createInput("text") end # # Creates an HTML INPUT type='RADIO' element. # # name:: the name of the group with which this radio button will be # associated # return:: the newly-created element # def self.createInputRadio(name) ` var e = document.createElement("INPUT"); e.type = 'radio'; e.name = #; return e` end #------------------------------------------------------------------- # DOM manipulation #------------------------------------------------------------------- # # Appends one element to another's list of children. # # parent:: the parent element # child:: its new child # def self.appendChild(parent, child) `#.appendChild(#); return #` end # # Inserts an element as a child of the given parent element. # # parent:: the parent element # child:: the child element to add to +parent+ # index:: the index before which the child will be inserted (any value # greater than the number of existing children will cause the child # to be appended) # def self.insertChild(parent, child, index) ` var count = 0, child = #.firstChild, before = null; while (child) { if (child.nodeType == 1) { if (count == #) { before = child; break; } ++count; } child = child.nextSibling; } #.insertBefore(#, before); return #` end # # Inserts an element as a child of the given parent element, before another # child of that parent. # # parent:: the parent element # child:: the child element to add to +parent+ # before:: an existing child element of +parent+ before # which +child+ will be inserted # def self.insertBefore(parent, child, before) `#.insertBefore(#, #); return #` end # # Removes a child element from the given parent element. # # parent:: the parent element # child:: the child element to be removed # def self.removeChild(parent, child) `#.removeChild(#); return #` end # # Replaces +elem+ in the DOM tree with element +newElem+. # # elem:: the element to be replaced # newElem:: the element that is used to replace +elem+ with. # def self.replace(elem, newElem) ` var p = #.parentNode; if (!p) return; p.insertBefore(#, #); p.removeChild(#); return #` end #------------------------------------------------------------------- # DOM navigation #------------------------------------------------------------------- # # Gets the element associated with the given unique id within the entire # document. # # id:: the id whose associated element is to be retrieved # return:: the associated element, or +nil+ if none is found # def self.getElementById(id) `return document.getElementById(#) || #` end # # Gets an element's n-th child element. # # parent:: the element whose child is to be retrieved # index:: the index of the child element # return:: the n-th child element # def self.getChild(parent, index) ` var count = 0, child = #.firstChild; while (child) { var next = child.nextSibling; if (child.nodeType == 1) { if (# == count) return child; ++count; } child = next; } return #` end # # Gets the number of child elements present in a given parent element. # # parent:: the element whose children are to be counted # return:: the number of children # def self.getChildCount(parent) ` var count = 0, child = #.firstChild; while (child) { if (child.nodeType == 1) ++count; child = child.nextSibling; } return count` end # # Gets the index of a given child element within its parent. # # parent:: the parent element # child:: the child element # return:: the child's index within its parent, or +nil+ if it is # not a child of the given parent # def self.getChildIndex(parent, child) ` var count = 0, child = #.firstChild; while (child) { if (child == #) return count; if (child.nodeType == 1) ++count; child = child.nextSibling; } return #` end # # Gets the first child element of the given element. # # elem:: the element whose child is to be retrieved # return:: the child element # def self.getFirstChild(elem) ` var child = #.firstChild; while (child && child.nodeType != 1) child = child.nextSibling; return child || #` end # # Gets an element's next sibling element. # # elem:: the element whose sibling is to be retrieved # return:: the sibling element # def self.getNextSibling(elem) ` var sib = #.nextSibling; while (sib && sib.nodeType != 1) sib = sib.nextSibling; return sib || #` end # # Gets an element's parent element. # # elem:: the element whose parent is to be retrieved # return:: the parent element # def self.getParent(elem) ` var parent = #.parentNode; if(parent == null) { return #; } if (parent.nodeType != 1) parent = null; return parent || #` end #------------------------------------------------------------------- # Event related #------------------------------------------------------------------- # # Sets the +EventListener+ to receive events for the given element. # Only one such listener may exist for a single element. # # elem:: the element whose listener is to be set # listener:: the listener to receive events # def self.setEventListener(elem, listener) `#.# = (# === #) ? null : #; return #` end def self.removeEventListener(elem) `#.# = null; return #` end # # Gets the current set of events sunk by a given element. # # elem:: the element whose events are to be retrieved # return:: a bitfield describing the events sunk on this element (its possible # values are described in +Event+) # def self.getEventsSunk(elem) `return #.# || 0` end # # Sets the current set of events sunk by a given element. These events will # be fired to the nearest +EventListener+ specified on any of the # element's parents. # # elem:: the element whose events are to be retrieved # eventBits:: a bitfield describing the events sunk on this element (its # possible values are described in +Event+) # def self.sinkEvents(elem, eventBits) ` #.# = #; #.onclick = (# & 0x00001) ? window.# : null; #.ondblclick = (# & 0x00002) ? window.# : null; #.onmousedown = (# & 0x00004) ? window.# : null; #.onmouseup = (# & 0x00008) ? window.# : null; #.onmouseover = (# & 0x00010) ? window.# : null; #.onmouseout = (# & 0x00020) ? window.# : null; #.onmousemove = (# & 0x00040) ? window.# : null; #.onkeydown = (# & 0x00080) ? window.# : null; #.onkeypress = (# & 0x00100) ? window.# : null; #.onkeyup = (# & 0x00200) ? window.# : null; #.onchange = (# & 0x00400) ? window.# : null; #.onfocus = (# & 0x00800) ? window.# : null; #.onblur = (# & 0x01000) ? window.# : null; #.onlosecapture = (# & 0x02000) ? window.# : null; #.onscroll = (# & 0x04000) ? window.# : null; #.onload = (# & 0x08000) ? window.# : null; #.onerror = (# & 0x10000) ? window.# : null; #.onmousewheel = (# & 0x20000) ? window.# : null; return #` end #------------------------------------------------------------------- # Attribute related #------------------------------------------------------------------- # # Gets the named attribute from the element. # # elem:: the element whose property is to be retrieved # attr:: the name of the attribute # return:: the value of the attribute # def self.getAttribute(elem, attr) ` var ret = #.getAttribute(#); return (ret == null) ? # : ret` end # # Sets an attribute on a given element. # # elem:: element whose attribute is to be set # attr:: the name of the attribute # value:: the value to which the attribute should be set # def self.setAttribute(elem, attr, value) `#.setAttribute(#, #); return #` end # # Removes the named attribute from the given element. # # elem:: the element whose attribute is to be removed # attr:: the name of the element to remove # def self.removeAttribute(elem, attr) `#.removeAttribute(#); return #` end #------------------------------------------------------------------- # Style Attribute related #------------------------------------------------------------------- # # Gets an attribute of the given element's style. # # elem:: the element whose style attribute is to be retrieved # attr:: the name of the style attribute to be retrieved # return:: the style attribute's value # def self.getStyleAttribute(elem, attr) ` var ret = #.style[#]; return (ret == null) ? # : ret` end # # Gets an integer attribute on a given element's style. # # elem:: the element whose style attribute is to be retrieved # attr:: the name of the attribute to be retrieved # return:: the style attribute's value as an integer # def self.getStyleAttributeInt(elem, attr) ` var i = parseInt(#.style[#]); return ((!i) ? 0 : i)` end # # Gets a boolean attribute on a given element's style. # # elem:: the element whose style attribute is to be retrieved # attr:: the name of the attribute to be retrieved # return:: the style attribute's value as a boolean # def self.getStyleAttributeBoolean(elem, attr) `return !!#.style[#]` end # # Sets an attribute on the given element's style. # # elem:: the element whose style attribute is to be set # attr:: the name of the style attribute to be set # value:: the style attribute's new value # def self.setStyleAttribute(elem, attr, value) `#.style[#] = #; return #` end #------------------------------------------------------------------- # Property related #------------------------------------------------------------------- # # Gets any named property from an element, as a string. # # elem:: the element whose property is to be retrieved # prop:: the name of the property # return:: the property's value # def self.getProperty(elem, prop) ` var ret = #[#]; return (ret == null) ? # : String(ret)` end # # Gets any named property from an element, as a boolean. # # param:: elem the element whose property is to be retrieved # param:: prop the name of the property # return:: the property's value as a boolean # def self.getPropertyBoolean(elem, prop) `return !!#[#]` end # # Gets any named property from an element, as an int. # # elem:: the element whose property is to be retrieved # prop:: the name of the property # return:: the property's value as an int # def self.getPropertyInt(elem, prop) ` var i = parseInt(#[#]); return ((!i) ? 0 : i)` end # # Sets a property on the given element. # # elem:: the element whose property is to be set # prop:: the name of the property to be set # value:: the new property value # def self.setProperty(elem, prop, value) `#[#] = #; return #` end #------------------------------------------------------------------- # Misc #------------------------------------------------------------------- # # Compares two elements for equality (note that reference equality is not # sufficient to determine equality among elements on most browsers). # # elem1:: the first element to be compared # elem2:: the second element to be compared # return:: +true+ if they are in fact the same element # # See #isOrHasChild. # def self.compare(elem1, elem2) `return (# == #)` end # # Determine whether one element is equal to, or the child of, another. # # parent:: the potential parent element # child:: the potential child element # return:: +true+ if the relationship holds # # See #compare. # def self.isOrHasChild(parent, child) ` while (#) { if (# == #) { return true; } # = #.parentNode; if (# && (#.nodeType != 1)) { # = null; } } return false` end # # Gets an element's absolute left coordinate in the document's coordinate # system. # # elem:: the element to be measured # return:: the element's absolute left coordinate # def self.getAbsoluteLeft(elem) ` var left = 0; var curr = #; // This intentionally excludes body which has a null offsetParent. while (curr.offsetParent) { left -= curr.scrollLeft; curr = curr.parentNode; } while (#) { left += #.offsetLeft; # = #.offsetParent; } return left` end # # Gets an element's absolute top coordinate in the document's coordinate # system. # # elem:: the element to be measured # return:: the element's absolute top coordinate # def self.getAbsoluteTop(elem) ` var top = 0; var curr = #; // This intentionally excludes body which has a null offsetParent. while (curr.offsetParent) { top -= curr.scrollTop; curr = curr.parentNode; } while (#) { top += #.offsetTop; # = #.offsetParent; } return top` end # # Gets the element that currently has mouse capture. # # return:: a handle to the capture element, or +nil+ if none exists # def self.getCapture return @sCaptureElem end # # Releases mouse capture on the given element. Calling this method has no # effect if the element does not currently have mouse capture. # # elem:: the element to release capture # # See #setCapture. # def self.releaseCapture(elem) @sCaptureElem = nil if @sCaptureElem and compare(elem, @sCaptureElem) `if (# == window.#) window.# = null;` return nil end # # Sets mouse-capture on the given element. This element will directly receive # all mouse events until {@link #releaseCapture(Element)} is called on it. # # elem:: the element on which to set mouse capture # def self.setCapture(elem) @sCaptureElem = elem `window.# = #;` return nil end # # Gets the src attribute of an img element. This method is paired with # #setImgSrc so that it always returns the correct url. # # img:: a non-nil img whose src attribute is to be read. # return:: the src url of the img # def self.getImgSrc(img) ` var ret = #.src; return (ret == null) ? # : ret` end # # Sets the src attribute of an img element. This method ensures that imgs # only ever have their contents requested one single time from the server. # # img:: a non-nil img whose src attribute will be set. # src:: a non-nil url for the img # def self.setImgSrc(img, src) `#.src = #; return #` end # # Gets an HTML representation (as String) of an element's children. # # elem:: the element whose HTML is to be retrieved # return:: the HTML representation of the element's children # def self.getInnerHTML(elem) ` var ret = #.innerHTML; return (ret == null) ? # : ret` end # # Sets the HTML contained within an element. # # elem:: the element whose inner HTML is to be set # html:: the new html # def self.setInnerHTML(elem, html='') ` #.innerHTML = #; return #` end # # Gets the text contained within an element. If the element has child # elements, only the text between them will be retrieved. # # elem:: the element whose inner text is to be retrieved # return:: the text inside this element # def self.getInnerText(elem) ` // To mimic IEs +innerText+ property in the W3C DOM, we need to recursively // concatenate all child text nodes (depth first). var text = '', child = #.firstChild; while (child) { // 1 == Element node if (child.nodeType == 1) { text += this.#(#, child); } else if (child.nodeValue) { text += child.nodeValue; } child = child.nextSibling; } return text` end # # Sets the text contained within an element. If the element already has # children, they will be destroyed. # # elem:: the element whose inner text is to be set # text:: the new text # def self.setInnerText(elem, text) ` // Remove all children first. while (#.firstChild) { #.removeChild(#.firstChild); } // Add a new text node. if (# !== #) { #.appendChild(document.createTextNode(#)); } return #` end # # Sets the option text of the given select object. # # select:: the select object whose option text is being set # text:: the text to set # index:: the index of the option whose text should be set # def self.setOptionText(select, text, index) # IE doesnt properly update the screen when you use # setAttribute('option', text), so we instead directly assign to the # 'option' property, which works correctly on all browsers. `var option = #