TEST
JavaScript for HTML Browsers: CSS Selectors and Media Queries
最終更新:
eriax
-
view
制限
- DOM-HTML 限定。名前空間を認識しない。大文字・小文字の区別はテキトー。長さは px しか認識しない。
- 構文エラーからの回復はしない(構文エラー回復を含めた CSS パーサは別所を参照)。
- 1000 行以内を目指したが現状 1050 行。パックして 20kb ぐらい。
- マッチング主体なので、ノードをかき集める速度は期待できない。
使用例
セレクタテスト
var sapi = CSS_Selectors_and_MediaQueries_for_HTML_Browsers._selectors_group; // セレクタテストの生成。 var selector = sapi('body:lang(ja) p#HOGE:nth-child(2n+1)'); // テストしたい要素。 var target = document.getElementById('HOGE'); // テストを実行。this として all 配列を渡すと :scope にマッチする。 var result = selector.call({ all: [document.body] }, target);
戻り値は [[p, null], [body, null]] のように単純セレクタにマッチした要素の配列(または null)。セレクタとは逆順に入っており、0 番がセレクタ全体にマッチした要素。この例で null になっている部分は疑似要素を表すレンジ。例えば p::before なら、p の最初の子の直前に位置するレンジになる。
セレクタを使って要素をかき集める簡便メソッド
var applySelectors = CSS_Selectors_and_MediaQueries_for_HTML_Browsers.applySelectors; // body 以下で非表示の要素をかき集める。戻り値は配列。 var result = applySelectors('*[aria-hidden="true"]', document.body);
メディアクエリテスト
var mql = CSS_Selectors_and_MediaQueries_for_HTML_Browsers._media_query_list; // メディアクエリテストの生成。 var mediump = mql('only screen and (min-width: 800px), screen and (min-color: 16)'); // window をメディアグループ 'visual' としてクエリテスト。戻り値は真偽値。 if (mediump.call({ ondefault: function (e) { return true; } }, window, 'visual')) alert('OK');
this 値として ondefault ハンドラを渡すと、未知の特徴を処理できる。
メディアグループ 'interactive' としてテストする簡便メソッド
var matchesWindow = CSS_Selectors_and_MediaQueries_for_HTML_Browsers.matchesWindow; if (matchesWindow('(orientation: portrait)', window)) alert('OK');
ソースコード
var CSS_Selectors_and_MediaQueries_for_HTML_Browsers = new function () { /*@cc_on@*/ var h = '[0-9a-f]'; var nonascii = '[^\\u0000-\\u007F]'; var unicode = '\\\\' + h + '{1,6}(?:\\r\\n|[\x20\\n\\r\\t\\f])?'; var num = '(?:[0-9]+|[0-9]*\\.[0-9]+)'; var nl = '(?:\\n|\\r\\n|\\r|\\f)'; var w = '[\x20\\t\\r\\n\\f]*'; var s = '[\x20\\t\\r\\n\\f]+'; var comment = '\\/\\*[^\*]*\\*+(?:[^\/\*][^\*]*\\*+)*\\/'; var escape = unicode + '|\\\\[^\\n\\r\\f0-9A-Fa-f]'; var nmchar = '(?:[_0-9a-z-]|' + nonascii + '|' + escape + ')'; var name = nmchar + '+'; var nmstart = '(?:[_a-z]|' + nonascii + '|' + escape + ')'; var ident = '-?' + nmstart + nmchar + '*'; var string1 = '\"(?:[^\\n\\r\\f\\\\\"]|\\\\' + nl + '|' + nonascii + '|' + escape + ')*\"'; var string2 = '\'(?:[^\\n\\r\\f\\\\\']|\\\\' + nl + '|' + nonascii + '|' + escape + ')*\''; var string = '(?:' + string1 + '|' + string2 + ')'; var invalid1 = '\"(?:[^\\n\\r\\f\\\\\"]|\\\\' + nl + '|' + nonascii + '|' + escape + ')*'; var invalid2 = '\'(?:[^\\n\\r\\f\\\\\']|\\\\' + nl + '|' + nonascii + '|' + escape + ')*'; var invalid = '(?:' + invalid1 + '|' + invalid2 + ')'; var url = '(?:[!#$%&*-~]|' + nonascii + '|' + escape + ')*'; // var A = '(?:a|\\\\0{0,4}[46]1(?:\\r\\n|[ \\t\\r\\n\\f])?)'; var D = '(?:d|\\\\0{0,4}[46]4(?:\\r\\n|[ \\t\\r\\n\\f])?)'; var E = '(?:e|\\\\0{0,4}[46]5(?:\\r\\n|[ \\t\\r\\n\\f])?)'; var L = '(?:l|\\\\0{0,4}[46]c(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\l)'; var N = '(?:n|\\\\0{0,4}[46]e(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\n)'; var O = '(?:o|\\\\0{0,4}[46]f(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\o)'; var P = '(?:p|\\\\0{0,4}[57]0(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\p)'; var R = '(?:r|\\\\0{0,4}[57]2(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\r)'; var T = '(?:t|\\\\0{0,4}[57]4(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\t)'; var U = '(?:u|\\\\0{0,4}[57]5(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\u)'; var V = '(?:v|\\\\0{0,4}[57]6(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\v)'; var X = '(?:x|\\\\0{0,4}[57]8(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\x)'; var Y = '(?:y|\\\\0{0,4}[57]9(?:\\r\\n|[ \\t\\r\\n\\f])?|\\\\y)'; // var S0 = w; var S1 = s; var INCLUDES = '~='; var DASHMATCH = '\\|='; var PREFIXMATCH = '\\^='; var SUFFIXMATCH = '\\$='; var SUBSTRINGMATCH = '\\*='; var PLUS = w + '\\+'; var GREATER = w + '>'; var COMMA = w + ','; var TILDE = w + '~(?!=)'; var NOT = ':not\\('; var STRING = string; var IDENT = ident; var HASH = '#' + name; var DIMENSION = num + ident; var PERCENTAGE = num + '%'; var NUMBER = num; var URI = U + R + L + '\\(' + w + string + w + '\\)|' + U + R + L + '\\(' + w + url + w + '\\)'; var FUNCTION = ident + '\\('; var s_unary_operator = PLUS + '|-'; var s_hexcolor = HASH + S0; // var p_Sh = new RegExp('^' + S1); var p_St = new RegExp(S1 + '$'); var f_trim = function (stringData) { return stringData.replace(p_Sh, '').replace(p_St, ''); }; var p_escaped = /\\([0-9a-f]{1,6})(?:\r\n|[\x20\n\r\t\f])?|\\([^\n\r\f0-9a-f])/gi; var f_unescape_replace = function (str, x, c) { if (x) { return String.fromCharCode(parseInt(x, 16)); // not accurate } return c; }; var f_unescape = function (stringData) { return stringData.replace(p_escaped, f_unescape_replace); }; // // css3-selectors var p_selector_type = new RegExp('^(?:(' + IDENT + '(?=\\|)|\\*(?=\\|))?\\|)?(' + IDENT + '|\\*)', 'i'); var p_selector_subject = new RegExp; p_selector_subject.exec = function (stringData) { var src = stringData; var cmp; if ((cmp = p_selector_type.exec(src))) { // subject var res1 = []; var res2 = []; var code; var ns = cmp[1]; var ln = cmp[2]; if (!ns || ns === '*') { if (ln === '*') { code = 'return\x20n;'; } else { code = f_unescape(ln).replace(/\W/g, '\\$&'); code = 'return\x20/^' + code + '$/i.test(n.nodeName)?n:null;'; } res2[res2.length] = code; cmp = cmp[0]; res1[res1.length] = cmp; } else { throw new Error('Namespace is not supported'); } return [].concat(res1.join(''), res2); } return null; }; // var p_selector_ID = new RegExp('^#(' + name + ')', 'i'); var p_selector_class = new RegExp('^\\.(' + IDENT + ')', 'i'); var p_selector_attrib = new RegExp('\\[' + S0 + '((' + IDENT + '(?=\\|)|\\*(?=\\|))?\\|)?(' + IDENT + ')' + S0 + '(?:(' + PREFIXMATCH + '|' + SUFFIXMATCH + '|' + SUBSTRINGMATCH + '|' + INCLUDES + '|' + DASHMATCH + '|=)' + S0 + '(?:(' + STRING + ')|(' + IDENT + '))' + S0 + ')?' + '\\]', 'i'); var p_selector_negation_begin = new RegExp('^' + NOT, 'i'); var p_selector_negation_end = new RegExp('^' + S0 + '\\)'); var p_selector_pseudo_class = new RegExp('^(::?)(?:(' + FUNCTION + ')' + S0 + '(' + '(?:(?:' + DIMENSION + '|' + STRING + '|' + IDENT + '|' + NUMBER + '|' + PLUS + '|-)' + S0 + ')+' + ')' + '\\)' + '|(' + IDENT + '))', 'i'); var p_selector_predicate_common = new RegExp; p_selector_predicate_common.exec = function (stringData) { var src = stringData; var cmp; var res1 = []; var res2 = []; var code; switch (src.charAt(0)) { case '#': if ((cmp = p_selector_ID.exec(src))) { code = f_unescape(cmp[1]).replace(/[\"\\]/g, '\\$&'); code = 'return\x20(n.id==="' + code + '")?n:null;'; break; } return null; case '.': if ((cmp = p_selector_class.exec(src))) { code = f_unescape(cmp[1]).replace(/\W/g, '\\$&'); code = 'return\x20/(?:^|' + S1 + ')' + code + '(?:' + S0 + '|$)/.test(n.className)?n:null;'; break; } return null; case '[': if ((cmp = p_selector_attrib.exec(src))) { var ns = cmp[2]; if (ns && ns !== '*') { throw new Error('Namespace is not supported'); } var ln = f_unescape(cmp[3]).replace(/[\"\\]/g, '\\$&'); var opr = cmp[4]; var val; code = 'var\x20a=n.getAttributeNode("' + ln + '"); '; if (opr) { val = ((val = cmp[5])) ? val.slice(1, -1) : cmp[6]; val = f_unescape(val).replace(/\W/g, '\\$&'); } switch (opr) { case '=': val = '/^' + val + '$/.test(a.value)'; break; case '^=': val = '/^' + val + '/.test(a.value)'; break; case '$=': val = '/' + val + '$/.test(a.value)'; break; case '*=': val = '/' + val + '/.test(a.value)'; break; case '~=': val = '/(?:^|' + S1 + ')' + val + '(?:' + S1 + '|$)/.test(a.value)'; break; case '|=': val = '/^' + val + '(?=-|$)/.test(a.value)'; break; default: val = 'a.specified'; break; } code += 'return\x20(a&&' + val + ')?n:null;'; break; } return null; case ':': if ((cmp = p_selector_pseudo_class.exec(src))) { var type = cmp[1]; var name; var args, a, b; if ((name = cmp[2])) { name = name.slice(0, -1); args = cmp[3]; } else { name = cmp[4]; args = ''; } switch (type + name) { case ':root': code = 'return\x20(n===n.ownerDocument.documentElement)?n:null;'; break; case ':nth-child': args = f_parse_nth(args), a = args[0], b = args[1]; code = 'var\x20m,i;for(m=n,i=1;m=m.previousSibling;)if(m.nodeType===1)i++;'; code += (a === 0) ? 'return\x20(i===' + b + ')?n:null;' : 'var\x20j=i-' + b + ';return((j%' + a + '===0) && (j / ' + a + '>=0))?n:null;'; break; case ':nth-last-child': args = f_parse_nth(args), a = args[0], b = args[1]; code = 'var\x20m,i;for(m=n,i=1;m=m.nextSibling;)if(m.nodeType===1)i++;'; code += (a === 0) ? 'return\x20(i===' + b + ')?n:null;' : 'var\x20j=i-' + b + ';return((j%' + a + '===0) && (j / ' + a + '>=0))?n:null;'; break; case ':nth-of-type': args = f_parse_nth(args), a = args[0], b = args[1]; code = 'var\x20s=n.tagName,m,i;for(m=n,i=1;m=m.previousSibling;)if(m.nodeType===1&&m.tagName===s)i++;'; code += (a === 0) ? 'return\x20(i===' + b + ')?n:null;' : 'var\x20j=i-' + b + ';return((j%' + a + '===0)&&(j/' + a + '>=0))?n:null;'; break; case ':nth-last-of-type': args = f_parse_nth(args), a = args[0], b = args[1]; code = 'var\x20s=n.tagName,m,i;for(m=n,i=1;m=m.nextSibling;)if(m.nodeType===1&&m.tagName===s)i++;'; code += (a === 0) ? 'return\x20(i===' + b + ')?n:null;' : 'var\x20j=i-' + b + ';return((j%' + a + '===0)&&(j/' + a + '>=0))?n:null;'; break; case ':first-child': code = 'var\x20m;for(m=n;m=m.previousSibling;)if(m.nodeType===1)return\x20null;return\x20n;'; break; case ':last-child': code = 'var\x20m;for(m=n;m=m.nextSibling;)if(m.nodeType===1)return\x20null;return\x20n;'; break; case ':first-of-type': code = 'var\x20s=n.tagName,m;for(m=n;m=m.previousSibling;)if(m.nodeType===1&&m.tagName===s)return\x20null;return\x20n;'; break; case ':last-of-type': code = 'var\x20s=n.tagName,m;for(m=n;m=m.nextSibling;)if(m.nodeType===1&&m.tagName===s)return\x20null;return\x20n;'; break; case ':only-child': code = 'var\x20m;for(m=n;m=m.previousSibling;)if(m.nodeType===1)return\x20null;for(m=n;m=m.nextSibling;)if(m.nodeType===1)return\x20null;return\x20n;'; break; case ':only-of-type': code = 'var\x20s=n.tagName,m;for(m=n;m=m.previousSibling;)if(m.nodeType===1&&m.tagName===s)return\x20null;for(m=n;m=m.nextSibling;)if(m.nodeType===1&&m.tagName===s)return\x20null;return\x20n;'; break; case ':empty': code = 'var\x20m;for(m=n.firstChild;m;m=m.nextSibling)switch(m.nodeType){case\x201:return\x20null;case\x203:case\x204:if(m.length>0)return\x20null;default:continue;}return\x20n;'; break; case ':link': case ':visited': case ':active': case ':hover': throw new Error(name + ' is not supported'); case ':focus': code = 'var\x20d;return((d=n.ownerDocument)&&(n===d.activeElement))?n:null;'; break; case ':target': code = 'var\x20d,s,w;return((d=n.ownerDocument)&&(w=d.defaultView)&&(s=w.location.hash)&&(s=s.slice(1))&&(n.id===s))?n:null;'; break; case ':lang': args = f_trim(args).replace(/\W/g, '\\$&'); code = 'for(var\x20m=n,v;m;m=m.parentNode)if(m.nodeType===1)if((v=m.lang))return\x20/^' + args + '(?:-|$)/i.test(v)?n:null;return\x20null;'; break; case ':enabled': code = 'return\x20(n.disabled===false)?n:null;'; break; case ':disabled': code = 'return\x20(n.disabled===true)?n:null;'; break; case ':checked': code = 'return\x20(n.checked===true)?n:null;'; break; case ':scope': code = 'var\x20c=this.all;if(!c)return\x20null;var\x20I=c.length,i;for(i=0;i<I;i++)if(n===c[i])return\x20n;return\x20null;'; break; case '::first-line': case ':first-line': throw new Error(name + ' is not supported'); case '::first-letter': case ':first-letter': code = 'var\x20d,r;if((d=n.ownerDocument)){r=d.createRange();while(n.hasChildNodes())n=n.firstChild;if(n.nodeType===3)if(n.length>0){r.setStart(n,0);r.setEnd(n,1);return\x20r;}}return\x20null;'; break; case '::selection': case ':selection': code = 'var\x20d,w,s;if((d=n.ownerDocument)&&(w=d.defaultView))return\x20w.getSelection().getRangeAt(0);return\x20null'; break; case '::before': case ':before': code = 'var\x20d,r;if((d=n.ownerDocument)){r=d.createRange();r.setStart(n,0);return\x20r;}return\x20null;'; break; case '::after': case ':after': code = 'var\x20d,r;if((d=n.ownerDocument)){r=d.createRange();switch(n.nodeType){case\x203:case\x204:case\x207:case\x208:r.setStart(n,n.data.length);break;default:r.setStart(n,n.childNodes.length);break;}return\x20r;}return\x20null;'; break; default: throw new Error(name + ' is not supported'); } break; } return null; default: return null; } res2[res2.length] = code; cmp = cmp[0]; res1[res1.length] = cmp; return [].concat(res1.join(''), res2); }; // var p_selector_negation_arg = new RegExp; p_selector_negation_arg.exec = function (stringData) { var src = stringData; var cmp; var res1 = []; var res2 = []; var code; switch (src.charAt(0)) { case '#': case '.': case '[': case ':': if ((cmp = p_selector_predicate_common.exec(src))) { code = cmp.slice(1); break; } return null; default: if ((cmp = p_selector_subject.exec(src))) { code = cmp.slice(1); break; } return null; } res2[res2.length] = 'return\x20!(function(n){' + code.join('') + '})(n)?n:null;'; cmp = cmp[0]; res1[res1.length] = cmp; return [].concat(res1.join(''), res2); }; // var p_simple_selector_sequence = new RegExp; p_simple_selector_sequence.exec = function (stringData) { var src = stringData; var cmp; var res1 = []; var res2 = []; var code; var subj = false; if ((cmp = p_selector_subject.exec(src))) { // subject subj = true; res2 = res2.concat(cmp.slice(1)); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); } A: while (src.length > 0) { // predicates switch (src.charAt(0)) { case '#': case '.': case '[': if ((cmp = p_selector_predicate_common.exec(src))) { code = cmp.slice(1); break; } return null; case ':': if ((cmp = p_selector_negation_begin.exec(src))) { cmp = cmp[0]; var zrc = src.slice(cmp.length); var kmp; var rez1 = [cmp]; var rez2 = []; if ((kmp = p_selector_negation_arg.exec(zrc))) { rez2 = rez2.concat(kmp.slice(1)); kmp = kmp[0]; rez1[rez1.length] = kmp; zrc = zrc.slice(kmp.length); if ((kmp = p_selector_negation_end.exec(zrc))) { kmp = kmp[0]; rez1[rez1.length] = kmp; zrc = zrc.slice(kmp.length); // src = zrc; res1.push.apply(res1, rez1); res2.push.apply(res2, rez2); continue; } } break A; } if ((cmp = p_selector_predicate_common.exec(src))) { code = cmp.slice(1); break; } break A; default: break A; } res2 = res2.concat(code); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); } if (res1.length > 0) { if (!subj) { cmp = p_selector_subject.exec('*'); res2 = [].concat(cmp.slice(1), res2); } return [].concat(res1.join(''), res2); } return null; }; // var p_combinator = new RegExp('^(?:(' + PLUS + ')' + S0 + '|(' + GREATER + ')' + S0 + '|(' + TILDE + ')' + S0 + '|(' + S1 + '))', 'i'); var o_combinator_table = { '': function (node, patterns) { A: if (node.nodeType === 1) { var count = patterns.length; var i, n; for (i = 0; i < count; i++) { n = patterns[i].call(this, node); if (!n) { break A; } } return [node, (node !== n) ? n : null]; } return null; }, '\x20': function (node, patterns) { var count = patterns.length; var i, n; A: while ((node = node.parentNode)) { if (node.nodeType === 1) { for (i = 0; i < count; i++) { n = patterns[i].call(this, node); if (!n) { continue A; } } return [node, (node !== n) ? n : null]; } } return null; }, '>': function (node, patterns) { var count = patterns.length; var i, n; A: if ((node = node.parentNode)) { if (node.nodeType === 1) { for (i = 0; i < count; i++) { n = patterns[i].call(this, node); if (!n) { break A; } } return [node, (node !== n) ? n : null]; } } return null; }, '~': function (node, patterns) { var count = patterns.length; var i, n; A: while ((node = node.previousSibling)) { if (node.nodeType === 1) { for (i = 0; i < count; i++) { n = patterns[i].call(this, node); if (!n) { continue A; } } return [node, (node !== n) ? n : null]; } } return null; }, '+': function (node, patterns) { var count = patterns.length; var i, n; A: while ((node = node.previousSibling)) { if (node.nodeType === 1) { for (i = 0; i < count; i++) { n = patterns[i].call(this, node); if (!n) { break A; } } return [node, (node !== n) ? n : null]; } } return null; } }; // var p_selector = new RegExp; p_selector.exec = function (stringData) { var src = stringData; var cmp; if ((cmp = p_simple_selector_sequence.exec(src))) { var res1 = []; var res2 = []; var sel; var cmb; sel = cmp.slice(1); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); while ((cmp = p_combinator.exec(src))) { cmb = cmp[1] ? '+' : cmp[2] ? '>' : cmp[3] ? '~' : '\x20'; res2[res2.length] = [sel, cmb]; sel = null; cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); if ((cmp = p_simple_selector_sequence.exec(src))) { sel = cmp.slice(1); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); continue; } break; } if (sel) { res2[res2.length] = [sel, '']; } else { var lst = res2[res2.length - 1]; var lsn = lst.length - 1; if (lst[lsn] === '\x20') { lst[lsn] = ''; } else { return null; } } for (var simple, patterns, i = 0, I = res2.length; i < I; i++) { simple = res2[i], patterns = simple[0]; res2[i] = { patterns: patterns, relation: o_combinator_table[simple[1]] }; for (var j = 0, J = patterns.length; j < J; j++) { patterns[j] = new Function('n', patterns[j]); } } res2.reverse(); return [].concat(res1.join(''), res2); } return null; }; // var p_selector_separator = new RegExp('^' + COMMA + w); var p_selectors_group = new RegExp; p_selectors_group.exec = function (stringData) { var src = stringData; var cmp; if ((cmp = p_selector.exec(src))) { var res1 = []; var res2 = []; res2[res2.length] = cmp.slice(1); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); while ((cmp = p_selector_separator.exec(src))) { cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); if ((cmp = p_selector.exec(src))) { res2[res2.length] = cmp.slice(1); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); continue; } break; } return [].concat(res1.join(''), res2); } return null; }; // var s_integer = '[0-9]+'; var p_nth = new RegExp(w + '(?:([-+]?(?:' + s_integer + ')?)' + N + '(?:' + w + '([-+])' + w + '(' + s_integer + '))?|([-+]?(?:' + s_integer + '))|(' + O + D + D + ')|(' + E + V + E + N + '))' + w, 'i'); var f_parse_nth = function (stringData) { var cmp = p_nth.exec(stringData); if (cmp) { var i, a, b; for (i = 0; !cmp[++i];); switch (i) { case 1: // '2n+1' a = cmp[i]; b = cmp[i + 1] + cmp[i + 2]; return [a === '+' ? 1 : a === '-' ? -1 : parseInt(a, 10), parseInt(b, 10) || 0]; case 4: // '1' return [0, parseInt(cmp[i], 10) || 0]; case 5: // 'odd' return [2, 1]; case 6: // 'even' return [2, 0]; } } return null; }; // var o_selectors_group_cache = { }; var f_create_selectors_group = function (stringData) { var selectors = p_selectors_group.exec(stringData); if (!selectors || stringData.length !== selectors[0].length) { throw new Error('malformed CSS selectors'); } var fn = o_selectors_group_cache[stringData]; if ('function' === typeof fn) { return fn; } return o_selectors_group_cache[stringData] = function (node) { var selectorCount = selectors.length; var i; A: for (i = 1; i < selectorCount; i++) { var n = node; var result = []; var simples = selectors[i]; var simpleCount = simples.length; var j; for (j = 0; j < simpleCount; j++) { var simple = simples[j]; var patterns = simple.patterns; var relation = simple.relation; if ((n = relation.call(this, n, patterns))) { result[result.length] = n; n = n[0]; continue; } continue A; } return result; } return null; }; }; this._selectors_group = f_create_selectors_group; // // css3-values var p_exprs = new RegExp('^(?:' + '(' + FUNCTION + ')' + '|(\\))' + '|(' + '(?:' + s_unary_operator + ')?' + '(?:' + PERCENTAGE + '|' + DIMENSION + '|' + NUMBER + ')' + '|' + URI + '|' + STRING + '|' + IDENT + '(?!\\()' + '|' + s_hexcolor + ')|(' + COMMA + S0 + '|' + S0 + '/' + S0 + '|' + S1 + ')' + ')', 'i'); var p_expr = new RegExp; p_expr.exec = function (stringData) { var src = stringData; var cmp; var tmp; var res1 = []; var res2 = []; var depth = 0; for (; cmp = p_exprs.exec(src); src = src.slice(tmp.length)) { if ((tmp = cmp[1])) { // 'f(' depth++, res1[res1.length] = tmp; res2[res2.length] = f_unescape(tmp); continue; } if ((tmp = cmp[2])) { // ')' if (depth > 0) { depth--, res1[res1.length] = tmp; res2[res2.length] = tmp; continue; } break; } if ((tmp = cmp[3])) { res1[res1.length] = tmp; res2[res2.length] = f_unescape(tmp); continue; } if ((tmp = cmp[4])) { // operator res1[res1.length] = tmp; res2[res2.length] = f_trim(tmp) || '\x20'; continue; } } if (depth === 0) { if (res2[res2.length - 1] === '\x20') { res2.pop(); } return [].concat(res1.join(''), res2); } return null; }; // // css3-mediaqueries var p_media_expression_prefix = new RegExp('^\\(' + S0 + '(' + IDENT + ')' + S0, 'i'); var p_media_expression_infix = new RegExp('^:' + S0); var p_media_expression_suffix = new RegExp('^\\)' + S0); var p_val_px = new RegExp('^' + w + '(' + NUMBER + ')' + P + X + w + '$', 'i'); var p_val_ratio = new RegExp('^' + w + '(' + NUMBER + ')' + w + '/' + w + '(' + NUMBER + ')' + w + '$', 'i'); var p_val_num = new RegExp('^' + S0 + '(' + NUMBER + ')' + S0 + '$', 'i'); var p_val_pattern = new RegExp('^' + S0 + '(' + STRING + ')' + S0 + ',' + S0 + '(' + STRING + ')' + S0 + '$'); var c_media_width = 'w.innerWidth'; var c_media_height = 'w.innerHeight'; var c_media_width_div_height = 'w.innerWidth/w.innerHeight'; var c_media_device_width = 'w.screen.availWidth'; var c_media_device_height = 'w.screen.availHeight'; var c_media_device_width_div_device_height = 'w.screen.availWidth/w.screen.availHeight'; var c_media_color = 'w.screen.colorDepth'; var p_media_expression = new RegExp; p_media_expression.exec = function (stringData) { var src = stringData; var cmp; if ((cmp = p_media_expression_prefix.exec(src))) { var res1 = []; var res2 = []; res2 = res2.concat(cmp.slice(1)); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); if ((cmp = p_media_expression_infix.exec(src))) { cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); if ((cmp = p_expr.exec(src))) { res2 = res2.concat(cmp.slice(1)); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); } } if ((cmp = p_media_expression_suffix.exec(src))) { cmp = cmp[0]; res1[res1.length] = cmp; var feature = res2[0].toLowerCase(); var value = res2.slice(1).join(''); var accessor; var operator; var code; /*@{ c_media_width = '(function(d){d=(d.compatMode==="CSS1Compat")?d.documentElement:d.body;return\x20d.clientWidth;})(w.document)'; c_media_height = '(function(d){d=(d.compatMode==="CSS1Compat")?d.documentElement:d.body;return\x20d.clientHeight;})(w.document)'; c_media_width_div_height = '(function(d){d=(d.compatMode==="CSS1Compat")?d.documentElement:d.body;return\x20d.clientWidth/d.clientHeight;})(w.document)'; }@*/ if (/(?:^|-)(?:width|height)$/i.test(feature)) { switch (feature) { case 'width': accessor = c_media_width, operator = '==='; break; case 'height': accessor = c_media_height, operator = '==='; break; case 'max-width': accessor = c_media_width, operator = '<='; break; case 'min-width': accessor = c_media_width, operator = '>='; break; case 'max-height': accessor = c_media_height, operator = '<='; break; case 'min-height': accessor = c_media_height, operator = '>='; break; case 'device-width': accessor = c_media_device_width, operator = '==='; break; case 'device-height': accessor = c_media_device_height, operator = '==='; break; case 'max-device-width': accessor = c_media_device_width, operator = '<='; break; case 'min-device-width': accessor = c_media_device_width, operator = '>='; break; case 'max-device-height': accessor = c_media_device_height, operator = '<='; break; case 'min-device-height': accessor = c_media_device_height, operator = '>='; break; default: accessor = 'false'; } code = 'return\x20' + accessor; if (value && (value = p_val_px.exec(value))) { code += operator + value[1] + ';'; } else if (/^[<>]/.test(operator)) { code += ';'; } else { code += '!==0;'; } } else if (/(?:^|-)aspect-ratio$/i.test(feature)) { switch (feature) { case 'aspect-ratio': accessor = c_media_width_div_height, operator = '=='; break; case 'max-aspect-ratio': accessor = c_media_width_div_height, operator = '<='; break; case 'min-aspect-ratio': accessor = c_media_width_div_height, operator = '>='; break; case 'device-aspect-ratio': accessor = c_media_device_width_div_device_height, operator = '=='; break; case 'max-device-aspect-ratio': accessor = c_media_device_width_div_device_height, operator = '<='; break; case 'min-device-aspect-ratio': accessor = c_media_device_width_div_device_height, operator = '>='; break; default: accessor = 'false'; } code = 'return\x20' + accessor; if (value && (value = p_val_ratio.exec(value))) { code += operator + value[1] + ';'; } else if (/^[<>]/.test(operator)) { code += ';'; } else { code += '!==0;'; } } else if (/(?:^|-)color$/i.test(feature)) { switch (feature) { case 'color': accessor = c_media_color, operator = '==='; break; case 'max-color': accessor = c_media_color, operator = '<='; break; case 'min-color': accessor = c_media_color, operator = '>='; break; default: accessor = 'false'; } code = 'return\x20' + accessor; if (value && (value = p_val_num.exec(value))) { code += operator + value[1] + ';'; } else if (/^[<>]/.test(operator)) { code += ';'; } else { code += '!==0;'; } } else { switch (feature) { case 'orientation': if (value) { value = f_trim(value).toLowerCase(); switch (value) { case 'portrait': code = 'return\x20' + c_media_width + '<=' + c_media_height + ';'; break; case 'landscape': code = 'return\x20' + c_media_width + '>' + c_media_height + ';'; break; default: code = 'return\x20false;'; break; } } else { code = 'return\x20false;'; } break; case '-x-domain-pattern': value = p_val_pattern.exec(value); if (value) { var psrc = value[1].slice(1, -1).replace(/[\/\\]/g, '\\$&'); var flag = value[2].slice(1, -1).replace(/\\/g, '\\$&'); code = /\W/.test(flag) ? 'return\x20false;' : 'return\x20/' + psrc + '/' + flag + '.test(w.location);'; } else { code = 'return\x20false;'; } break; default: code = 'var\x20h=this.ondefault;if(h){return\x20h.call(this,{target:w,feature:"' + feature + '",value:"' + value.replace(/[\"\\]/g, '\\$&') + '"});}return\x20false;'; break; } } res2 = code; return [].concat(res1.join(''), res2); } } return null; }; // var o_media_groups = { 'continuous': /\s*(?:^|,)\s*(?:braille|handheld|screen|speech|tty|tv)\s*(?:,|$)\s*/i, 'paged': /\s*(?:^|,)\s*(?:handheld|embossed|print|projection|tv)\s*(?:,|$)\s*/i, 'visual': /\s*(?:^|,)\s*(?:handheld|print|projection|screen|tty|tv)\s*(?:,|$)\s*/i, 'audio': /\s*(?:^|,)\s*(?:handheld|screen|tv)\s*(?:,|$)\s*/i, 'speechg': /\s*(?:^|,)\s*(?:handheld|speech)\s*(?:,|$)\s*/i, 'tactile': /\s*(?:^|,)\s*(?:braille|embossed)\s*(?:,|$)\s*/i, 'grid': /\s*(?:^|,)\s*(?:braille|embossed|handheld|tty)\s*(?:,|$)\s*/i, 'bitmap': /\s*(?:^|,)\s*(?:handheld|print|projection|screen|tv)\s*(?:,|$)\s*/i, 'interactive': /\s*(?:^|,)\s*(?:braille|handheld|projection|screen|speech|tty|tv)\s*(?:,|$)\s*/i, 'static': /\s*(?:^|,)\s*(?:braille|embossed|handheld|print|screen|speech|tty|tv)\s*(?:,|$)\s*/i, // 'braille': /\s*(?:^|,)\s*(?:continuous|tactile|grid|interactive|static)\s*(?:,|$)\s*/i, 'embossed': /\s*(?:^|,)\s*(?:paged|tactile|grid|static)\s*(?:,|$)\s*/i, 'handheld': /\s*(?:^|,)\s*(?:continuous|paged|visual|audio|speech|grid|bitmap|interactive|static)\s*(?:,|$)\s*/i, 'print': /\s*(?:^|,)\s*(?:paged|visual|bitmap|static)\s*(?:,|$)\s*/i, 'projection': /\s*(?:^|,)\s*(?:paged|visual|bitmap|interactive)\s*(?:,|$)\s*/i, 'screen': /\s*(?:^|,)\s*(?:continuous|visual|audio|bitmap|interactive|static)\s*(?:,|$)\s*/i, 'speech': /\s*(?:^|,)\s*(?:continuous|speech|interactive|static)\s*(?:,|$)\s*/i, 'tty': /\s*(?:^|,)\s*(?:continuous|visual|grid|interactive|static)\s*(?:,|$)\s*/i, 'tv': /\s*(?:^|,)\s*(?:continuous|paged|visual|audio|bitmap|interactive|static)\s*(?:,|$)\s*/i }; // var p_media_query_prefix = new RegExp('^' + S0 + '(' + O + N + L + Y + '|' + N + O + T + ')?' + S0 + '(' + IDENT + ')' + S0, 'i'); var p_media_query_and = new RegExp('^' + A + N + D + S1, 'i'); var p_media_query = new RegExp; p_media_query.exec = function (stringData) { var src = stringData; var cmp; var res1 = []; var res2 = []; var code1; var code2; A: { if ((cmp = p_media_query_prefix.exec(src))) { // only | not code1 = (code1 = cmp[1]) ? f_unescape(code1).toLowerCase() : 'only'; code2 = f_unescape(cmp[2]).toLowerCase(); break A; } if ((cmp = p_media_expression.exec(src))) { code1 = 'only'; code2 = 'all'; res2[res2.length] = new Function('w', cmp.slice(1).join('')); break A; } return null; } cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); // only or not code1 = (code1 === 'not') ? 'return\x20!b;' : 'return\x20b;'; // media type if (code2 === 'all') { code2 = 'return\x20true;'; } else { var pattern = o_media_groups[code2]; code2 = 'if(/(?:^|' + S0 + ',)' + S0 + '(?:' + code2.replace(/\W/g, '\\$&') + ')' + S0 + '(?:,' + S0 + '|$)/i.test(m))\x20return\x20true;'; if (pattern) { code2 += 'return\x20' + pattern + '.test(m);'; // be careful not to contain '/' } else { code2 += 'return\x20false;'; } } res2 = [].concat(new Function('b', code1), new Function('m', code2), res2); // media queries while ((cmp = p_media_query_and.exec(src))) { cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); if ((cmp = p_media_expression.exec(src))) { res2[res2.length] = new Function('w', cmp.slice(1).join('')); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); continue; } return null; } return [].concat(res1.join(''), res2); }; // var p_media_query_list_prefix = new RegExp('^' + S0); var p_media_query_list_infix = new RegExp('^' + COMMA + S0, 'i'); var p_media_query_list = new RegExp; p_media_query_list.exec = function (stringData) { var src = stringData; var cmp; if ((cmp = p_media_query_list_prefix.exec(src))) { var res1 = []; var res2 = []; cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); if ((cmp = p_media_query.exec(src))) { res2[res2.length] = cmp.slice(1); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); while ((cmp = p_media_query_list_infix.exec(src))) { cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); if ((cmp = p_media_query.exec(src))) { res2[res2.length] = cmp.slice(1); cmp = cmp[0]; res1[res1.length] = cmp; src = src.slice(cmp.length); continue; } break; } } return [].concat(res1.join(''), res2); } return null; }; // var o_media_query_list_cache = { }; var f_create_media_query_list = function (stringData) { var queries = p_media_query_list.exec(stringData); if (!queries) { throw new Error('malformed Media Queries'); } var fn = o_media_query_list_cache[stringData]; if ('function' === typeof fn) { return fn; } return o_media_query_list_cache[stringData] = function (view, mediaType) { var queryCount = queries.length; var i; for (i = 1; i < queryCount; i++) { var exprs = queries[i]; var exprCount = exprs.length; var j; if (exprs[1].call(this, mediaType)) { var bool = true; for (j = 2; j < exprCount; j++) { if (!exprs[j].call(this, view)) { bool = false; break; } } if (exprs[0].call(this, bool)) { return true; } } } return false; }; }; this._media_query_list = f_create_media_query_list; // // shortcut methods var f_matches_media_interactive = function (queries, view, thisArg) { return f_create_media_query_list(queries).call(thisArg, view, 'interactive'); }; this.matchesWindow = f_matches_media_interactive; var f_apply_selectors = function (selectors, root, thisArg) { selectors = f_create_selectors_group(selectors); if (! thisArg) { thisArg = { }; } thisArg.all = [ ].concat(thisArg.all || root); var result = [ ]; var es = root.getElementsByTagName('*'); var I = es.length; var i; var r; for (i = 0; i < I; i++) { if ((r = selectors.call(thisArg, es[i]))) { r = r[0]; result[result.length] = r[1] || r[0]; } } return result; }; this.applySelectors = f_apply_selectors; };
- 初出:2011-07-07/08/09/10/11/12、修正 2011-08-12