;;; dom5.el --- Add HTML5's DOM methods to dom.el
;; Copyright (C) 2007 Edward O'Connor
;; Author: Edward O'Connor
;; Keywords: xml
;; URL: http://edward.oconnor.cx/elisp/dom5.el
;; This file is not part of GNU Emacs.
;; This file is free software; you can redistribute it and/or modify it
;; under the terms of the GNU General Public License as published by the
;; Free Software Foundation; either version 2, or (at your option) any
;; later version.
;; This file is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with GNU Emacs; see the file COPYING. If not, write to
;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
;; Boston, MA 02110-1301, USA.
;;; Commentary:
;; An implementation of the various new DOM methods defined in the HTML5
;; draft specification.
;; N.B. Functions prefixed by `dom-' are public-facing, and augment the
;; API provided by dom.el. Functions prefixed with `dom5-' are internal
;; and should not be called.
;;; History:
;; 2007-08-10: Initial version.
;;; Code:
(require 'dom)
;; interface HTMLDocument
;; ...
;; NodeList getElementsByName(in DOMString elementName);
;; NodeList getElementsByClassName(in DOMString[] classNames);
;; ...
;; The getElementsByName(name) method a string name, and must return a
;; live NodeList containing all the a, applet, button, form, iframe,
;; img, input, map, meta, object, select, and textarea elements in that
;; document that have a name attribute whose value is equal to the name
;; argument.
(defun dom-document-get-elements-by-name (document name)
"Return all of the nodes in DOCUMENT whose name= is NAME."
(error "Not implemented yet"))
;; The getElementsByClassName(classNames) method takes an array of
;; strings representing classes. When called, the method must return a
;; live NodeList object containing all the elements in the document that
;; have all the classes specified in that array. If the array is empty,
;; then the method must return an empty NodeList.
(defun dom-document-get-elements-by-class-name (document &rest class-names)
"Return all nodes in DOCUMENT thathave all classes named in CLASS-NAMES."
(dom5-element-get-elements-by-class-name-1
(dom-document-element document)
class-names))
;; interface HTMLElement : Element {
;; ...
;; NodeList getElementsByClassName(in DOMString[] classNames);
(defun dom-element-get-elements-by-class-name (element &rest class-names)
"Return all nodes under ELEMENT thathave all classes named in CLASS-NAMES."
(dom5-element-get-elements-by-class-name-1
(dom-element-first-child element)
class-names))
(defun dom5-element-has-class (element class)
"Non-nil if ELEMENT has CLASS."
(and (eq (dom-node-type element) dom-element-node)
(catch 'found
(let ((attrs (dom-node-attributes element)))
(dolist (attr attrs)
(when (eq (dom-node-name attr) 'class)
(dolist (class-name (split-string (dom-node-value attr)))
(when (equal class-name class)
(throw 'found t))))))
nil)))
(defun dom5-element-get-elements-by-class-name-1 (element class-names)
"Return a list of nodes under ELEMENT with all classes in CLASS-NAMES.
CLASS-NAMES is a list of strings. The elements are ELEMENT, its
siblings, and their descendants. This is used by
`dom-element-get-elements-by-class-name' and
`dom-document-get-elements-by-class-name'."
;; We don't want to call this recursively because of performance.
(let (stack result)
(while element
;; when `element' has all class names in `class-names'
(when (and (eq (dom-node-type element) dom-element-node)
(reduce (lambda (a b) (and a b))
(mapcar (lambda (class-name)
(dom5-element-has-class element class-name))
class-names)))
(setq result (cons element result)))
(setq element
(cond ((dom-node-first-child element)
(when (dom-node-next-sibling element)
(push (dom-node-next-sibling element) stack))
(dom-node-first-child element))
((dom-node-next-sibling element))
(t (pop stack)))))
(nreverse result)))
(provide 'dom5)
;;; dom5.el ends here