aboutsummaryrefslogtreecommitdiff
path: root/src/js/fiveui/injected/prelude.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/js/fiveui/injected/prelude.js')
-rw-r--r--src/js/fiveui/injected/prelude.js428
1 files changed, 428 insertions, 0 deletions
diff --git a/src/js/fiveui/injected/prelude.js b/src/js/fiveui/injected/prelude.js
new file mode 100644
index 0000000..a77a1de
--- /dev/null
+++ b/src/js/fiveui/injected/prelude.js
@@ -0,0 +1,428 @@
+/*
+ * Module : injected/prelude.js
+ * Copyright : (c) 2011-2012, Galois, Inc.
+ *
+ * Maintainer :
+ * Stability : Provisional
+ * Portability: Portable
+ *
+ * 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.
+ */
+
+/**
+ * The FiveUI Prelude.
+ *
+ * @description
+ * The prelude provides a collection of utilities to ease the
+ * conversion from human-readable guideline documents (such as the Web
+ * Accessibilty Guidelines, or Apple Human Interface Guidelines) to
+ * executable Rules.
+ *
+ * @namespace
+ */
+var fiveui = fiveui || {};
+
+/**
+ * A global namespace for statistics collection.
+ *
+ * @namespace
+ */
+fiveui.stats = fiveui.stats || {};
+/** @global */
+fiveui.stats.numElts = 0;
+/** @const */
+fiveui.stats.zero = { numRules: 0, start: 0, end: 0, numElts: 0 };
+
+/** DOM Traversal ************************************************************/
+
+/**
+ * fiveui.query is a wrapper around the jQuery $() function.
+ *
+ * @description
+ * fiveui.query recurses into iframes and frames, whereas $(...) stops
+ * when it encounters internal frames.
+ *
+ * Generally, rules written for FiveUI will want to cover the entire
+ * visible page, and as such, should use fiveui.query; however, $(...)
+ * is available if recursing into frames is not necessary.
+ *
+ * @param {String} sel The jQuery selector string.
+ * @param {Object} [context] The context to run the query within. This is often a DOM object/tree.
+ * @returns {Object} A jQuery object, suitable for chaining.
+ */
+fiveui.query = function (sel, context) {
+ var ctx = context || document;
+ var $results = jQuery(sel, ctx);
+
+ jQuery('iframe, frame', ctx).each(
+ function(idx, elt) {
+ var $tempResults;
+ if (elt.contentDocument) {
+ try {
+ $tempResults = fiveui.query(sel, elt.contentDocument);
+ } catch (e) {
+ console.log("encoutered a non-cooperative iframe/frame at " + $(elt).attr("src"));
+ console.log(e.toString());
+ $tempResults = [];
+ }
+
+ $results = $results.add($tempResults);
+ }
+ }
+ );
+
+ $filteredResults = $results.not('#uic-top *')
+ .not('#uic-top')
+ .filter(':visible');
+
+ // update global stats
+ fiveui.stats.numElts += $filteredResults.length;
+
+ return $filteredResults;
+};
+
+/**
+ * Provide a short alias for fiveui.query along the lines of the jQuery $ alias.
+ *
+ * @example $5("p").hasText("foo") -> jQuery object containing paragraph elements
+ * containing the text "foo"
+ * </pre></p>
+ *
+ * @const
+ *
+ */
+var $5 = fiveui.query;
+
+/** Utilities ****************************************************************/
+
+/**
+ * Determine if a given value is a string or not.
+ *
+ * @param {*} [o] A value of some type that may or may not be defined.
+ * @returns {!boolean} true if the object is a defined, non-null string, false
+ * otherwise.
+ */
+fiveui.isString = function(o) {
+ return typeof o == 'string';
+};
+
+
+/**
+ * String-specific utilities.
+ *
+ * @namespace
+ */
+fiveui.string = {};
+
+/**
+ * Non-destructively removes whitespace from the start and end of a
+ * string.
+ *
+ * @param {String} [s] The string to trim of whitespace.
+ * @returns {String} The input string, without leading or trailing
+ * whitespace. Returns null if you gave it null.
+ */
+fiveui.string.trim = function(s) {
+ if (s) {
+ return s.replace(/^\s+|\s+$/g,"");
+ }
+ return s;
+};
+
+/**
+ * Tokenize a string on whitespace.
+ *
+ * @param {!String} s The string to tokenize.
+ * @returns {String[]>} An array of substrings.
+ */
+fiveui.string.tokens = function (s) {
+ var posLength = function(ar) {
+ return 1 <= ar.length;
+ };
+
+ return s.split(/\s/).filter(posLength);
+};
+
+
+/**
+ * A simple heuristic check to see if a string is in Title Case.
+ *
+ * @description
+ * This does not perform an exhaustive gramatical analysis, and as
+ * such, it is prone to generating false-positives in some cases. In
+ * particular, it only has a short 'white list' of articles,
+ * conjections, and prepositions that are allowed to be in lower case.
+ *
+ * @param {!String} str The string to check.
+ * @returns {!boolean} true if the string is in title case, false if
+ * it is not.
+ */
+fiveui.string.isTitleCase = function(str) {
+ var exception = function(str) {
+ var exceptions = [ 'a', 'an', 'the' // articles
+ , 'and', 'but', 'for', 'not', 'or' // conjuctions
+ , 'in', 'on' // short prepositions
+ , 'to' ];
+ return exceptions.indexOf(str.toLowerCase()) != -1;
+ };
+
+ if ( !fiveui.word.capitalized(str[0]) ) {
+ return false;
+ }
+
+ var tokens = fiveui.string.tokens(str);
+ for (var i=1; i < tokens.length; ++i) {
+ if (!exception(tokens[i]) && !fiveui.word.capitalized(tokens[i])) {
+ return false;
+ }
+ }
+ return true;
+};
+
+/**
+ * Utilities for word-specific processing.
+ *
+ * @description The fiveui.word namespace focuses on tools for working directly
+ * with words in the sense of natural languages, rather than general
+ * strings (as is the case for the fiveui.string namespace).
+ *
+ * @namespace
+ */
+fiveui.word = {};
+
+/**
+ * Check to see if a sting begins with a capital letter.
+ *
+ * @param {!String} word The string to check for capitalization.
+ * @returns {!boolean}
+ */
+fiveui.word.capitalized = function(word) {
+ return fiveui.isString(word) && word.search(/^[A-Z]/, word) >= 0;
+};
+
+/**
+ * Check to see if a sting consists entirely of capital letters.
+ *
+ * @param {!String} word The string to check for capitalization.
+ * @returns {!boolean}
+ */
+fiveui.word.allCaps = function(word) {
+ return fiveui.isString(word)
+ && word.search(/^\w/, word) >= 0
+ && (word == word.toUpperCase());
+};
+
+
+/**
+ * Utilities for dealing with color.
+ *
+ * @namespace
+ */
+fiveui.color = {};
+
+/**
+ * Color check compiler. It is recommended to use the jQuery plugin
+ * fiveui.jquery.cssIsNot instead.
+ *
+ * @param {!String} selector The HTML element selector to check.
+ * @param {String[]} colorSet An array of strings containing the HEX values of
+ * colors in the desired color set.
+ * @returns {!function()} A function which checks the rule
+ * @see fiveui.jquery.cssIsNot
+ */
+fiveui.color.colorCheck = function (selector, colorSet) {
+ var allowable, i, fnStr, forEachFuncStr;
+ allowable = {};
+ for (i = 0; i < colorSet.length; i += 1) { allowable[colorSet[i]] = true; }
+ forEachFuncStr = 'function (j, elt) {\n'
+ + ' var allowable = ' + JSON.stringify(allowable) + ';\n'
+ + ' var color = fiveui.color.colorToHex($(elt).css("color"));\n'
+ + ' if (!(color in allowable)) {\n'
+ + ' report("Disallowed color " + color + " in element matching " + ' + JSON.stringify(selector) + ', $(elt));\n'
+ + ' }\n'
+ + '}\n';
+ fnStr = 'function () { fiveui.query("' + selector + '").each(' + forEachFuncStr + '); }';
+ return eval('false||'+fnStr); // the `false||` trick is required for eval to parse a
+ // function expression ?!?
+};
+
+/**
+ * Covert rgb colors to hex and abreviated hex colors to their full 3 byte
+ * form.
+ *
+ * In case there are parse errors during the conversion, i.e. color values
+ * that are not understood, the input is returned unchanged.
+ *
+ * @param {!String} color The color string to convert. This should be either of the form rgb(...) or #...
+ * @returns {!String} The color string in #XXXXXX form
+ * @throws {ParseError} if the rgb color string cannot be parsed
+ */
+fiveui.color.colorToHex = function(color) {
+ var have, need;
+ if (color.substr(0, 1) === '#') {
+ if (color.length === 7) {
+ return color;
+ }
+ else { // deal with #0 or #F7 cases
+ var have = color.length - 1;
+ var haveDigits = color.substr(1, color.length);
+ var need = 6 - have;
+ var reps = Math.ceil(need / have);
+ var i, strColor;
+ for (i = 0, stdColor = color; i < reps; i += 1) { stdColor += haveDigits; }
+ return stdColor.substr(0, 7);
+ }
+ }
+
+ var digits = /rgba?\((\d+), (\d+), (\d+)/.exec(color);
+ if (!digits) {
+ return color; // in case there is a parse error, we just
+ // return the input unchanged
+ }
+
+ var red = parseInt(digits[1]);
+ var green = parseInt(digits[2]);
+ var blue = parseInt(digits[3]);
+
+ var rgb = blue | (green << 8) | (red << 16);
+ if (rgb === 0) {
+ return '#000000'; // normalized form
+ }
+ else {
+ return '#' + rgb.toString(16).toUpperCase();
+ }
+};
+
+
+/**
+ * Utilities for dealing with fonts.
+ *
+ * @namespace
+ */
+fiveui.font = {};
+
+/**
+ * Extracts the font-family, font-size (in px, as an int), and font-weight
+ * from a jQuery object.
+ *
+ * @param {!Object} jElt A jQuery object to extract font info from
+ * @returns {!Object} An object with properties: 'family', 'size', and 'weight'
+ * @throws {ParseError} if the font size cannot be parsed
+ */
+fiveui.font.getFont = function (jElt) {
+ var res = {};
+ var size = jElt.css('font-size');
+ if(size.length > 0) {
+ var psize = /(\d+)/.exec(size);
+ if(!psize) {
+ throw {
+ name: 'ParseError',
+ message: 'Could not parse font size: ' + jElt.css('font-size')
+ };
+ }
+ else {
+ res.size = psize
+ }
+ } else {
+ res.size = '';
+ }
+ res.family = jElt.css('font-family');
+ res.weight = jElt.css('font-weight').toString();
+ // normalize reporting of the following two synonyms
+ if (res.weight === '400') { res.weight = 'normal'; }
+ if (res.weight === '700') { res.weight = 'bold'; }
+ return res;
+};
+
+/**
+ * Validate a font property object extracted using fiveui.font.getFont().
+ *
+ * @description The `allow` parameter should be an object whose top level properties are
+ * (partial) font family names (e.g. 'Verdana'). For each font family name
+ * there should be an object whose properties are font weights (e.g. 'bold'),
+ * and for each font weight there should be an array of allowable sizes
+ * (e.g. [10, 11, 12]).
+ *
+ * The `font` parameter should be an object containing 'family', 'weight', and
+ * 'size' properties. These are returned by @see fiveui.font.getFont().
+ *
+ * @example > allow = { 'Verdana': { 'bold': [10, 12], 'normal': [10, 12]}};
+ * > font = { family: 'Verdana Arial sans-serif', size: "10", weight: "normal" };
+ * > fiveui.font.validate(allow, font) -> true
+ *
+ * @param {!Object} allow Object containing allowable font sets (see description and examples)
+ * @param {!Object} font object to check
+ * @param font.family A partial font family name (e.g. 'Verdana')
+ * @param font.weight A font weight (e.g. 'bold')
+ * @param font.size A font size string (e.g. "10")
+ * @returns {!boolean}
+ */
+fiveui.font.validate = function (allow, font) {
+ var x;
+ for (x in allow) { // loop over allowed font family keywords
+ if (font.family.indexOf(x) !== -1) { break; }
+ else { return false; }
+ }
+ return (font.weight in allow[x] && allow[x][font.weight].indexOf(parseInt(font.size)) != -1);
+};
+
+/**
+ * Functions outside the fiveui namespace that can be called during rule
+ * evaluation.
+ */
+
+/**
+ * <p>Report a problem to FiveUI.</p>
+ *
+ * @description
+ * <p>report is used to indicate that a guideline has been violated.
+ * Invocations should provide a short (1-line) string description of
+ * the problem, as well as a reference to the element of the DOM that
+ * violated the guideline.</p>
+ *
+ * <p>The second parameter is not strictly required, but we strongly
+ * suggest providing a node if at all possible, as that is used to
+ * visually highlight the problematic areas of the DOM at runtime.
+ * Debugging a guideline violation becomes much more difficult without
+ * the visual indicator.</p>
+ *
+ * @function
+ * @param {!String} desc The description of the problem to report.
+ * @param {?Node} node The node in the DOM that caused the problem.
+ * @name report
+ */
+
+/**
+ * JSON.stringify is included here for extension and ruleset debugging
+ * purposes. It is used by the jQuery pluggin jQuery.fn.log.
+ */
+var JSON = JSON || {};
+JSON.stringify = JSON.stringify || function (obj) {
+ var t = typeof (obj);
+ if (t != "object" || obj === null) {
+ // simple data type
+ if (t == "string") obj = '"'+obj+'"';
+ return String(obj);
+ }
+ else {
+ // recurse array or object
+ var n, v, json = [], arr = (obj && obj.constructor == Array);
+ for (n in obj) {
+ v = obj[n]; t = typeof(v);
+ if (t == "string") v = '"'+v+'"';
+ else if (t == "object" && v !== null) v = JSON.stringify(v);
+ json.push((arr ? "" : '"' + n + '":') + String(v));
+ }
+ return (arr ? "[" : "{") + String(json) + (arr ? "]" : "}");
+ }
+};