~caneypuggies/reformedchurcheslocator/couchapp-backbone

« back to all changes in this revision

Viewing changes to _attachments/js/vendor/modernizr/test/js/lib/jsonselect.js

  • Committer: Tim Black
  • Date: 2013-09-16 22:50:16 UTC
  • Revision ID: tim@alwaysreformed.com-20130916225016-zk8jiba25z33ew7h
Versioned Bower vendor directory

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*! Copyright (c) 2011, Lloyd Hilaiel, ISC License */
 
2
/*
 
3
 * This is the JSONSelect reference implementation, in javascript.
 
4
 */
 
5
(function(exports) {
 
6
 
 
7
    var // localize references
 
8
    toString = Object.prototype.toString;
 
9
 
 
10
    function jsonParse(str) {
 
11
      try {
 
12
          if(JSON && JSON.parse){
 
13
              return JSON.parse(str);
 
14
          }
 
15
          return (new Function("return " + str))();
 
16
      } catch(e) {
 
17
        te("ijs");
 
18
      }
 
19
    }
 
20
 
 
21
    // emitted error codes.
 
22
    var errorCodes = {
 
23
        "ijs": "invalid json string",
 
24
        "mpc": "multiple pseudo classes (:xxx) not allowed",
 
25
        "mepf": "malformed expression in pseudo-function",
 
26
        "nmi": "multiple ids not allowed",
 
27
        "se": "selector expected",
 
28
        "sra": "string required after '.'",
 
29
        "uc": "unrecognized char",
 
30
        "ujs": "unclosed json string",
 
31
        "upc": "unrecognized pseudo class"
 
32
    };
 
33
 
 
34
    // throw an error message
 
35
    function te(ec) {
 
36
        throw new Error(errorCodes[ec]);
 
37
    }
 
38
 
 
39
    // THE LEXER
 
40
    var toks = {
 
41
        psc: 1, // pseudo class
 
42
        psf: 2, // pseudo class function
 
43
        typ: 3, // type
 
44
        str: 4 // string
 
45
    };
 
46
 
 
47
    var pat = /^(?:([\r\n\t\ ]+)|([*.,>])|(string|boolean|null|array|object|number)|(:(?:root|first-child|last-child|only-child))|(:(?:nth-child|nth-last-child))|(:\w+)|(\"(?:[^\\]|\\[^\"])*\")|(\")|((?:[_a-zA-Z]|[^\0-\0177]|\\[^\r\n\f0-9a-fA-F])(?:[_a-zA-Z0-9\-]|[^\u0000-\u0177]|(?:\\[^\r\n\f0-9a-fA-F]))*))/;
 
48
    var exprPat = /^\s*\(\s*(?:([+\-]?)([0-9]*)n\s*(?:([+\-])\s*([0-9]))?|(odd|even)|([+\-]?[0-9]+))\s*\)/;
 
49
    var lex = function (str, off) {
 
50
        if (!off) off = 0;
 
51
        var m = pat.exec(str.substr(off));
 
52
        if (!m) return undefined;
 
53
        off+=m[0].length;
 
54
        var a;
 
55
        if (m[1]) a = [off, " "];
 
56
        else if (m[2]) a = [off, m[0]];
 
57
        else if (m[3]) a = [off, toks.typ, m[0]];
 
58
        else if (m[4]) a = [off, toks.psc, m[0]];
 
59
        else if (m[5]) a = [off, toks.psf, m[0]];
 
60
        else if (m[6]) te("upc");
 
61
        else if (m[7]) a = [off, toks.str, jsonParse(m[0])];
 
62
        else if (m[8]) te("ujs");
 
63
        else if (m[9]) a = [off, toks.str, m[0].replace(/\\([^\r\n\f0-9a-fA-F])/g,"$1")];
 
64
        return a;
 
65
    };
 
66
 
 
67
    // THE PARSER
 
68
 
 
69
    var parse = function (str) {
 
70
        var a = [], off = 0, am;
 
71
 
 
72
        while (true) {
 
73
            var s = parse_selector(str, off);
 
74
            a.push(s[1]);
 
75
            s = lex(str, off = s[0]);
 
76
            if (s && s[1] === " ") s = lex(str, off = s[0]);
 
77
            if (!s) break;
 
78
            // now we've parsed a selector, and have something else...
 
79
            if (s[1] === ">") {
 
80
                a.push(">");
 
81
                off = s[0];
 
82
            } else if (s[1] === ",") {
 
83
                if (am === undefined) am = [ ",", a ];
 
84
                else am.push(a);
 
85
                a = [];
 
86
                off = s[0];
 
87
            }
 
88
        }
 
89
        if (am) am.push(a);
 
90
        return am ? am : a;
 
91
    };
 
92
 
 
93
    var parse_selector = function(str, off) {
 
94
        var soff = off;
 
95
        var s = { };
 
96
        var l = lex(str, off);
 
97
        // skip space
 
98
        if (l && l[1] === " ") { soff = off = l[0]; l = lex(str, off); }
 
99
        if (l && l[1] === toks.typ) {
 
100
            s.type = l[2];
 
101
            l = lex(str, (off = l[0]));
 
102
        } else if (l && l[1] === "*") {
 
103
            // don't bother representing the universal sel, '*' in the
 
104
            // parse tree, cause it's the default
 
105
            l = lex(str, (off = l[0]));
 
106
        }
 
107
 
 
108
        // now support either an id or a pc
 
109
        while (true) {
 
110
            if (l === undefined) {
 
111
                break;
 
112
            } else if (l[1] === ".") {
 
113
                l = lex(str, (off = l[0]));
 
114
                if (!l || l[1] !== toks.str) te("sra");
 
115
                if (s.id) te("nmi");
 
116
                s.id = l[2];
 
117
            } else if (l[1] === toks.psc) {
 
118
                if (s.pc || s.pf) te("mpc");
 
119
                // collapse first-child and last-child into nth-child expressions
 
120
                if (l[2] === ":first-child") {
 
121
                    s.pf = ":nth-child";
 
122
                    s.a = 0;
 
123
                    s.b = 1;
 
124
                } else if (l[2] === ":last-child") {
 
125
                    s.pf = ":nth-last-child";
 
126
                    s.a = 0;
 
127
                    s.b = 1;
 
128
                } else {
 
129
                    s.pc = l[2];
 
130
                }
 
131
            } else if (l[1] === toks.psf) {
 
132
                if (s.pc || s.pf ) te("mpc");
 
133
                s.pf = l[2];
 
134
                var m = exprPat.exec(str.substr(l[0]));
 
135
                if (!m) te("mepf");
 
136
                if (m[5]) {
 
137
                    s.a = 2;
 
138
                    s.b = (m[5] === "odd") ? 1 : 0;
 
139
                } else if (m[6]) {
 
140
                    s.a = 0;
 
141
                    s.b = parseInt(m[6], 10);
 
142
                } else {
 
143
                    s.a = parseInt((m[1] ? m[1] : "+") + (m[2] ? m[2] : "1"),10);
 
144
                    s.b = m[3] ? parseInt(m[3] + m[4],10) : 0;
 
145
                }
 
146
                l[0] += m[0].length;
 
147
            } else {
 
148
                break;
 
149
            }
 
150
            l = lex(str, (off = l[0]));
 
151
        }
 
152
 
 
153
        // now if we didn't actually parse anything it's an error
 
154
        if (soff === off) te("se");
 
155
 
 
156
        return [off, s];
 
157
    };
 
158
 
 
159
    // THE EVALUATOR
 
160
 
 
161
    function isArray(o) {
 
162
        return Array.isArray ? Array.isArray(o) : 
 
163
          toString.call(o) === "[object Array]";
 
164
    }
 
165
 
 
166
    function mytypeof(o) {
 
167
        if (o === null) return "null";
 
168
        var to = typeof o;
 
169
        if (to === "object" && isArray(o)) to = "array";
 
170
        return to;
 
171
    }
 
172
 
 
173
    function mn(node, sel, id, num, tot) {
 
174
        var sels = [];
 
175
        var cs = (sel[0] === ">") ? sel[1] : sel[0];
 
176
        var m = true, mod;
 
177
        if (cs.type) m = m && (cs.type === mytypeof(node));
 
178
        if (cs.id)   m = m && (cs.id === id);
 
179
        if (m && cs.pf) {
 
180
            if (cs.pf === ":nth-last-child") num = tot - num;
 
181
            else num++;
 
182
            if (cs.a === 0) {
 
183
                m = cs.b === num;
 
184
            } else {
 
185
                mod = ((num - cs.b) % cs.a);
 
186
 
 
187
                m = (!mod && ((num*cs.a + cs.b) >= 0));
 
188
            }
 
189
        }
 
190
 
 
191
        // should we repeat this selector for descendants?
 
192
        if (sel[0] !== ">" && sel[0].pc !== ":root") sels.push(sel);
 
193
 
 
194
        if (m) {
 
195
            // is there a fragment that we should pass down?
 
196
            if (sel[0] === ">") { if (sel.length > 2) { m = false; sels.push(sel.slice(2)); } }
 
197
            else if (sel.length > 1) { m = false; sels.push(sel.slice(1)); }
 
198
        }
 
199
 
 
200
        return [m, sels];
 
201
    }
 
202
 
 
203
    function forEach(sel, obj, fun, id, num, tot) {
 
204
        var a = (sel[0] === ",") ? sel.slice(1) : [sel],
 
205
        a0 = [],
 
206
        call = false,
 
207
        i = 0, j = 0, l = 0, k, x;
 
208
        for (i = 0; i < a.length; i++) {
 
209
            x = mn(obj, a[i], id, num, tot);
 
210
            if (x[0]) {
 
211
                call = true;
 
212
            }
 
213
            for (j = 0; j < x[1].length; j++) {
 
214
                a0.push(x[1][j]);
 
215
            }
 
216
        }
 
217
        if (a0.length && typeof obj === "object") {
 
218
            if (a0.length >= 1) {
 
219
                a0.unshift(",");
 
220
            }
 
221
            if (isArray(obj)) {
 
222
                for (i = 0; i < obj.length; i++) {
 
223
                    forEach(a0, obj[i], fun, undefined, i, obj.length);
 
224
                }
 
225
            } else {
 
226
                // it's a shame to do this for :last-child and other
 
227
                // properties which count from the end when we don't
 
228
                // even know if they're present.  Also, the stream
 
229
                // parser is going to be pissed.
 
230
                l = 0;
 
231
                for (k in obj) {
 
232
                    if (obj.hasOwnProperty(k)) {
 
233
                        l++;
 
234
                    }
 
235
                }
 
236
                i = 0;
 
237
                for (k in obj) {
 
238
                    if (obj.hasOwnProperty(k)) {
 
239
                        forEach(a0, obj[k], fun, k, i++, l);
 
240
                    }
 
241
                }
 
242
            }
 
243
        }
 
244
        if (call && fun) {
 
245
            fun(obj);
 
246
        }
 
247
    }
 
248
 
 
249
    function match(sel, obj) {
 
250
        var a = [];
 
251
        forEach(sel, obj, function(x) {
 
252
            a.push(x);
 
253
        });
 
254
        return a;
 
255
    }
 
256
 
 
257
    function compile(sel) {
 
258
        return {
 
259
            sel: parse(sel),
 
260
            match: function(obj){
 
261
                return match(this.sel, obj);
 
262
            },
 
263
            forEach: function(obj, fun) {
 
264
                return forEach(this.sel, obj, fun);
 
265
            }
 
266
        };
 
267
    }
 
268
 
 
269
    exports._lex = lex;
 
270
    exports._parse = parse;
 
271
    exports.match = function (sel, obj) {
 
272
        return compile(sel).match(obj);
 
273
    };
 
274
    exports.forEach = function(sel, obj, fun) {
 
275
        return compile(sel).forEach(obj, fun);
 
276
    };
 
277
    exports.compile = compile;
 
278
})(typeof exports === "undefined" ? (window.JSONSelect = {}) : exports);
 
279