1 /* 2 * Module : injected/jquery-plugins.js 3 * Copyright : (c) 2011-2012, Galois, Inc. 4 * 5 * Maintainer : 6 * Stability : Provisional 7 * Portability: Portable 8 * 9 * Licensed under the Apache License, Version 2.0 (the "License"); 10 * you may not use this file except in compliance with the License. 11 * You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, software 16 * distributed under the License is distributed on an "AS IS" BASIS, 17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 * See the License for the specific language governing permissions and 19 * limitations under the License. 20 */ 21 22 var fiveui = fiveui || {}; 23 24 /** 25 * <p>This module provides several useful jQuery plugins related to checking and reporting 26 * UI consistency issues.</p> 27 * 28 * @namespace 29 */ 30 fiveui.jquery = fiveui.jquery || {}; 31 32 33 /** 34 * <p>Wrapper for the :contains('text') selector</p> 35 * 36 * @example 37 * $('div').hasText('to remove').remove(); 38 * 39 * @param {!string} text Text to select for 40 * @returns {!Object} A modified jQuery object 41 */ 42 fiveui.jquery.hasText = function (text) { 43 return this.filter(":contains('" + text + "')"); 44 }; 45 46 /** 47 * <p>Filter for elements which lack of the given attribute. (see also 48 * fiveui.jquery.attrFilter)</p> 49 * 50 * @example 51 * $('<table></table>').noAttr('summary').each(function(idx, table) { 52 * // `table` is a table element that does not have a "summary" 53 * // attribute or that has a "summary" attribute that is empty. 54 * }); 55 * 56 * @param {!string} attribute name 57 * @returns {!Object} a filtered jQuery object 58 */ 59 fiveui.jquery.noAttr = function (name) { 60 return this.filter(function () { 61 $attr = $.trim($(this).attr(name)); 62 return $attr == undefined || $attr == ''; 63 }); 64 }; 65 66 67 /** 68 * <p>Filter for elements having no sub-elements matching the given selector.</p> 69 * 70 * Example: the following should contain no elements 71 * 72 * @example 73 * // Returns an empty result because the <div> contains a <p> element. 74 * $('<div><p>hello</p></div>').noSubElt('p') 75 * 76 * @param {!string} sel a jQuery selector 77 * @param {!Object} A filtered jQuery object 78 */ 79 fiveui.jquery.noSubElt = function (sel) { 80 return this.filter(function () { 81 return $(this).find(sel).length == 0; 82 }); 83 }; 84 85 /** 86 * <p>Color checker plugin: filters for elements whose CSS color property is 87 * not in the given set.</p> 88 * 89 * @description 90 * <p>Note: This is a special case of fiveui.jquery.cssIsNot, i.e. 91 * $(..).notColorSet(set) == $(..).cssIsNot("color", set, fiveui.color.colorToHex) 92 * @see {fiveui.color.colorToHex}</p> 93 * 94 * @param {string[]} cset An array of allowable color strings 95 * @returns {!Object} A modified jQuery object 96 */ 97 fiveui.jquery.notColorSet = function (cset) { 98 var allowable = {}; 99 // input array -> object 100 for (var i = 0; i < cset.length; i += 1) { 101 allowable[fiveui.color.colorToHex(cset[i])] = true; 102 } 103 return this.filter(function (index) { 104 var color = fiveui.color.colorToHexWithDefault($(this).css("color")); // .css("color") returns rgb(...) 105 return !(color in allowable); 106 }); 107 }; 108 109 110 fiveui.jquery._makeCss = function (pos) { 111 return function (prop, set, fn) { 112 var allowable = {}; 113 fn = fn || function (x) { return x; }; // default is Id 114 if (typeof set === "string") { 115 allowable[fn(set)] = true; 116 } 117 else { // assume `set` is an array of strings 118 // array -> object 119 for (var i = 0; i < set.length; i += 1) { 120 allowable[fn(set[i])] = true; 121 } 122 } 123 return this.filter(function (index) { 124 var cssProp = fn($(this).css(prop)); 125 return pos ? (cssProp in allowable) : !(cssProp in allowable); 126 }); 127 }; 128 }; 129 130 /** 131 * <p>General CSS property checker plugin</p> 132 * 133 * @description 134 * <p>This plugin filters elements, keeping only elements whose CSS 135 * property `prop` is a member of the given array `cset`. The names in 136 * `cset` and the CSS values that are checked are transformed using the 137 * optional given function `fn`. This may be used to normalize values 138 * that the browser returns so they can be compared to values in 139 * `cset`.</p> 140 * 141 * @example 142 * var div = $('<div style="visibility:hidden"></div>') 143 * div.cssIs('visibility', ['hidden', 'visible']) // returns the same div 144 * 145 * @function 146 * 147 * @param {string} prop CSS property selector 148 * @param {string|string[]} set allowable values (either a string or an array 149 * of strings) 150 * @param {function(string):string} [fn] Function to apply to return values 151 * of $(this).css(prop), fn defaults to 152 * the identity function. 153 * @returns {Object} jQuery object 154 */ 155 fiveui.jquery.cssIs = fiveui.jquery._makeCss(true); 156 157 /** 158 * <p>Negated version of fiveui.jquery.cssIs</p> 159 * 160 * @description 161 * <p>Behaves exactly like fiveui.jquery.cssIs - except that this 162 * version excludes elements that have CSS properties and values that 163 * match.</p> 164 * 165 * @example 166 * var div = $('<div style="visibility:hidden"></div>') 167 * div.cssIsNot('visibility', ['hidden', 'visible']) // returns empty result 168 * 169 * @function 170 * 171 * @param {string} prop CSS property selector 172 * @param {string|string[]} set allowable values (either a string or an array 173 * of strings) 174 * @param {function(string):string} [fn] Function to apply to return values 175 * of $(this).css(prop), fn defaults to 176 * the identity function. 177 * @returns {Object} jQuery object 178 */ 179 fiveui.jquery.cssIsNot = fiveui.jquery._makeCss(false); 180 181 /** 182 * <p>General attribute filter</p> 183 * 184 * @description 185 * <p>This plugin filters for elements whose attribute `a` pass the 186 * predicate `fn`, which should take a string and return true or false. 187 * Elements that don't have the attribute are automatically filtered 188 * out.</p> 189 * 190 * @example 191 * $('input').attrFilter('type', function(t) { return t === 'checkbox'; }); 192 * 193 * @param {string} a element attribute name 194 * @param {Function} fn a predicate to run on the element attribute 195 * @returns {Object} jQuery object 196 */ 197 fiveui.jquery.attrFilter = function (a, fn) { 198 return this.filter(function () { 199 var x = $(this).attr(a); 200 return x != undefined && fn(x); 201 }); 202 } 203 204 /** 205 * <p>Filter out elements that do not contain the attribute 206 * href=`href`.</p> 207 * 208 * @param {string} href the href to look for 209 * @returns {Object} jQuery object 210 */ 211 fiveui.jquery.linksTo = function (href) { 212 return this.filter('[href=' + href + ']'); 213 } 214 215 /** 216 * <p>Visually highlight elements in the jQuery object.</p> 217 * 218 * @description 219 * <p>This plugin is useful mostly in the process of writing 220 * guidelines, for example the guideline developer can load a page, 221 * click the "Break" button on the FiveUI window, enter the browser's 222 * Javascript console, and run:</p> 223 * 224 * @example > $5("p").hasText("foo").highlight(); 225 * 226 * @param {string} [hint] Highlighted border color, defaults to "red" 227 * @returns {!Object} A modified jQuery object 228 */ 229 fiveui.jquery.highlight = function (hint) { 230 hint = hint || "red"; // Default is "red" 231 return this.css("background-color", "rgba(255, 0, 0, 0.3)") 232 .css("border-style", "solid") 233 .css("border-color", hint); 234 } 235 236 /** 237 * <p>Returns a list of css properties that element in the jQuery 238 * object have.</p> 239 * 240 * @description 241 * <p>This plugin is useful for analysis of a given page when 242 * writing guielines. For example if the guideline developer wants to 243 * know what font sizes are used on a loaded page, they can run from the 244 * Javascript console:</p> 245 * 246 * @example > $5("*").propDist("font-size", true); 247 * 248 * @param {string} prop CSS property to be inspected 249 * @param {boolean} [log] Boolean which enables console logging of the result; default is `false`. 250 * @returns {Object} A frequence map { "property": frequency } 251 */ 252 fiveui.jquery.propDist = function (prop, log) { 253 var res = {}; 254 log = log || false; 255 this.each(function (i, elt) { 256 var p = $(elt).css(prop); 257 if (p in res) { 258 res[p] += 1; 259 } 260 else { 261 res[p] = 1; 262 } 263 }); 264 if (log) { 265 console.log("Property distribution:"); 266 for (var p in res) { 267 console.log(" " + p + ": " + res[p]); 268 } 269 } 270 return res; 271 } 272 273 /** 274 * Register the plugins. This adds methods to the jQuery.fn namespace. 275 * 276 * @private 277 */ 278 fiveui.jquery.init = function () { 279 for (fn in fiveui.jquery) { 280 f = fiveui.jquery[fn]; 281 if (jQuery.isFunction(f) && fn != "init") { 282 jQuery.fn[fn] = fiveui.jquery[fn]; 283 } 284 } 285 } 286 fiveui.jquery.init(); 287