Path: blob/trunk/third_party/closure/goog/dom/classlist.js
2868 views
// Copyright 2012 The Closure Library Authors. All Rights Reserved.1//2// Licensed under the Apache License, Version 2.0 (the "License");3// you may not use this file except in compliance with the License.4// You may obtain a copy of the License at5//6// http://www.apache.org/licenses/LICENSE-2.07//8// Unless required by applicable law or agreed to in writing, software9// distributed under the License is distributed on an "AS-IS" BASIS,10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.11// See the License for the specific language governing permissions and12// limitations under the License.1314/**15* @fileoverview Utilities for detecting, adding and removing classes. Prefer16* this over goog.dom.classes for new code since it attempts to use classList17* (DOMTokenList: http://dom.spec.whatwg.org/#domtokenlist) which is faster18* and requires less code.19*20* Note: these utilities are meant to operate on HTMLElements21* and may have unexpected behavior on elements with differing interfaces22* (such as SVGElements).23*/242526goog.provide('goog.dom.classlist');2728goog.require('goog.array');293031/**32* Override this define at build-time if you know your target supports it.33* @define {boolean} Whether to use the classList property (DOMTokenList).34*/35goog.define('goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST', false);363738/**39* Gets an array-like object of class names on an element.40* @param {Element} element DOM node to get the classes of.41* @return {!IArrayLike<?>} Class names on {@code element}.42*/43goog.dom.classlist.get = function(element) {44if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {45return element.classList;46}4748var className = element.className;49// Some types of elements don't have a className in IE (e.g. iframes).50// Furthermore, in Firefox, className is not a string when the element is51// an SVG element.52return goog.isString(className) && className.match(/\S+/g) || [];53};545556/**57* Sets the entire class name of an element.58* @param {Element} element DOM node to set class of.59* @param {string} className Class name(s) to apply to element.60*/61goog.dom.classlist.set = function(element, className) {62element.className = className;63};646566/**67* Returns true if an element has a class. This method may throw a DOM68* exception for an invalid or empty class name if DOMTokenList is used.69* @param {Element} element DOM node to test.70* @param {string} className Class name to test for.71* @return {boolean} Whether element has the class.72*/73goog.dom.classlist.contains = function(element, className) {74if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {75return element.classList.contains(className);76}77return goog.array.contains(goog.dom.classlist.get(element), className);78};798081/**82* Adds a class to an element. Does not add multiples of class names. This83* method may throw a DOM exception for an invalid or empty class name if84* DOMTokenList is used.85* @param {Element} element DOM node to add class to.86* @param {string} className Class name to add.87*/88goog.dom.classlist.add = function(element, className) {89if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {90element.classList.add(className);91return;92}9394if (!goog.dom.classlist.contains(element, className)) {95// Ensure we add a space if this is not the first class name added.96element.className +=97element.className.length > 0 ? (' ' + className) : className;98}99};100101102/**103* Convenience method to add a number of class names at once.104* @param {Element} element The element to which to add classes.105* @param {IArrayLike<string>} classesToAdd An array-like object106* containing a collection of class names to add to the element.107* This method may throw a DOM exception if classesToAdd contains invalid108* or empty class names.109*/110goog.dom.classlist.addAll = function(element, classesToAdd) {111if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {112goog.array.forEach(classesToAdd, function(className) {113goog.dom.classlist.add(element, className);114});115return;116}117118var classMap = {};119120// Get all current class names into a map.121goog.array.forEach(goog.dom.classlist.get(element), function(className) {122classMap[className] = true;123});124125// Add new class names to the map.126goog.array.forEach(127classesToAdd, function(className) { classMap[className] = true; });128129// Flatten the keys of the map into the className.130element.className = '';131for (var className in classMap) {132element.className +=133element.className.length > 0 ? (' ' + className) : className;134}135};136137138/**139* Removes a class from an element. This method may throw a DOM exception140* for an invalid or empty class name if DOMTokenList is used.141* @param {Element} element DOM node to remove class from.142* @param {string} className Class name to remove.143*/144goog.dom.classlist.remove = function(element, className) {145if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {146element.classList.remove(className);147return;148}149150if (goog.dom.classlist.contains(element, className)) {151// Filter out the class name.152element.className = goog.array153.filter(154goog.dom.classlist.get(element),155function(c) { return c != className; })156.join(' ');157}158};159160161/**162* Removes a set of classes from an element. Prefer this call to163* repeatedly calling {@code goog.dom.classlist.remove} if you want to remove164* a large set of class names at once.165* @param {Element} element The element from which to remove classes.166* @param {IArrayLike<string>} classesToRemove An array-like object167* containing a collection of class names to remove from the element.168* This method may throw a DOM exception if classesToRemove contains invalid169* or empty class names.170*/171goog.dom.classlist.removeAll = function(element, classesToRemove) {172if (goog.dom.classlist.ALWAYS_USE_DOM_TOKEN_LIST || element.classList) {173goog.array.forEach(classesToRemove, function(className) {174goog.dom.classlist.remove(element, className);175});176return;177}178// Filter out those classes in classesToRemove.179element.className =180goog.array181.filter(182goog.dom.classlist.get(element),183function(className) {184// If this class is not one we are trying to remove,185// add it to the array of new class names.186return !goog.array.contains(classesToRemove, className);187})188.join(' ');189};190191192/**193* Adds or removes a class depending on the enabled argument. This method194* may throw a DOM exception for an invalid or empty class name if DOMTokenList195* is used.196* @param {Element} element DOM node to add or remove the class on.197* @param {string} className Class name to add or remove.198* @param {boolean} enabled Whether to add or remove the class (true adds,199* false removes).200*/201goog.dom.classlist.enable = function(element, className, enabled) {202if (enabled) {203goog.dom.classlist.add(element, className);204} else {205goog.dom.classlist.remove(element, className);206}207};208209210/**211* Adds or removes a set of classes depending on the enabled argument. This212* method may throw a DOM exception for an invalid or empty class name if213* DOMTokenList is used.214* @param {!Element} element DOM node to add or remove the class on.215* @param {?IArrayLike<string>} classesToEnable An array-like object216* containing a collection of class names to add or remove from the element.217* @param {boolean} enabled Whether to add or remove the classes (true adds,218* false removes).219*/220goog.dom.classlist.enableAll = function(element, classesToEnable, enabled) {221var f = enabled ? goog.dom.classlist.addAll : goog.dom.classlist.removeAll;222f(element, classesToEnable);223};224225226/**227* Switches a class on an element from one to another without disturbing other228* classes. If the fromClass isn't removed, the toClass won't be added. This229* method may throw a DOM exception if the class names are empty or invalid.230* @param {Element} element DOM node to swap classes on.231* @param {string} fromClass Class to remove.232* @param {string} toClass Class to add.233* @return {boolean} Whether classes were switched.234*/235goog.dom.classlist.swap = function(element, fromClass, toClass) {236if (goog.dom.classlist.contains(element, fromClass)) {237goog.dom.classlist.remove(element, fromClass);238goog.dom.classlist.add(element, toClass);239return true;240}241return false;242};243244245/**246* Removes a class if an element has it, and adds it the element doesn't have247* it. Won't affect other classes on the node. This method may throw a DOM248* exception if the class name is empty or invalid.249* @param {Element} element DOM node to toggle class on.250* @param {string} className Class to toggle.251* @return {boolean} True if class was added, false if it was removed252* (in other words, whether element has the class after this function has253* been called).254*/255goog.dom.classlist.toggle = function(element, className) {256var add = !goog.dom.classlist.contains(element, className);257goog.dom.classlist.enable(element, className, add);258return add;259};260261262/**263* Adds and removes a class of an element. Unlike264* {@link goog.dom.classlist.swap}, this method adds the classToAdd regardless265* of whether the classToRemove was present and had been removed. This method266* may throw a DOM exception if the class names are empty or invalid.267*268* @param {Element} element DOM node to swap classes on.269* @param {string} classToRemove Class to remove.270* @param {string} classToAdd Class to add.271*/272goog.dom.classlist.addRemove = function(element, classToRemove, classToAdd) {273goog.dom.classlist.remove(element, classToRemove);274goog.dom.classlist.add(element, classToAdd);275};276277278