|
- /*
- * Copyright (C) 2007-2018 Diego Perini
- * All rights reserved.
- *
- * CSS3 pseudo-classes extension for NWMatcher
- *
- * Added capabilities:
- *
- * - structural pseudo-classes
- *
- * :root, :empty,
- * :nth-child(), nth-of-type(),
- * :nth-last-child(), nth-last-of-type(),
- * :first-child, :last-child, :only-child
- * :first-of-type, :last-of-type, :only-of-type
- *
- * - negation, language, target and UI element pseudo-classes
- *
- * :not(), :target, :lang(), :target
- * :link, :visited, :active, :focus, :hover,
- * :checked, :disabled, :enabled, :selected
- */
-
- (function(global) {
-
- var LINK_NODES = {
- 'a': 1, 'A': 1,
- 'area': 1, 'AREA': 1,
- 'link': 1, 'LINK': 1
- },
-
- root = document.documentElement,
-
- contains = 'compareDocumentPosition' in root ?
- function(container, element) {
- return (container.compareDocumentPosition(element) & 16) == 16;
- } : 'contains' in root ?
- function(container, element) {
- return element.nodeType == 1 && container.contains(element);
- } :
- function(container, element) {
- while ((element = element.parentNode) && element.nodeType == 1) {
- if (element === container) return true;
- }
- return false;
- },
-
- isLink =
- function(element) {
- return element.getAttribute('href') && LINK_NODES[element.nodeName];
- },
-
- isEmpty =
- function(node) {
- node = node.firstChild;
- while (node) {
- if (node.nodeType == 3 || node.nodeName > '@') return false;
- node = node.nextSibling;
- }
- return true;
- },
-
- nthElement =
- function(element, last) {
- var count = 1, succ = last ? 'nextSibling' : 'previousSibling';
- while ((element = element[succ])) {
- if (element.nodeName > '@') ++count;
- }
- return count;
- },
-
- nthOfType =
- function(element, last) {
- var count = 1, succ = last ? 'nextSibling' : 'previousSibling', type = element.nodeName;
- while ((element = element[succ])) {
- if (element.nodeName == type) ++count;
- }
- return count;
- };
-
- NW.Dom.Snapshot['contains'] = contains;
-
- NW.Dom.Snapshot['isLink'] = isLink;
- NW.Dom.Snapshot['isEmpty'] = isEmpty;
- NW.Dom.Snapshot['nthOfType'] = nthOfType;
- NW.Dom.Snapshot['nthElement'] = nthElement;
-
- })(this);
-
- NW.Dom.registerSelector(
- 'nwmatcher:spseudos',
- /^\:(root|empty|(?:first|last|only)(?:-child|-of-type)|nth(?:-last)?(?:-child|-of-type)\(\s*(even|odd|(?:[-+]{0,1}\d*n\s*)?[-+]{0,1}\s*\d*)\s*\))?(.*)/i,
- (function(global) {
-
- return function(match, source) {
-
- var a, n, b, status = true, test, type;
-
- switch (match[1]) {
-
- case 'root':
- if (match[3])
- source = 'if(e===h||s.contains(h,e)){' + source + '}';
- else
- source = 'if(e===h){' + source + '}';
- break;
-
- case 'empty':
- source = 'if(s.isEmpty(e)){' + source + '}';
- break;
-
- default:
- if (match[1] && match[2]) {
-
- if (match[2] == 'n') {
- source = 'if(e!==h){' + source + '}';
- break;
- } else if (match[2] == 'even') {
- a = 2;
- b = 0;
- } else if (match[2] == 'odd') {
- a = 2;
- b = 1;
- } else {
- b = ((n = match[2].match(/(-?\d+)$/)) ? parseInt(n[1], 10) : 0);
- a = ((n = match[2].match(/(-?\d*)n/i)) ? parseInt(n[1], 10) : 0);
- if (n && n[1] == '-') a = -1;
- }
- test = a > 1 ?
- (/last/i.test(match[1])) ? '(n-(' + b + '))%' + a + '==0' :
- 'n>=' + b + '&&(n-(' + b + '))%' + a + '==0' : a < -1 ?
- (/last/i.test(match[1])) ? '(n-(' + b + '))%' + a + '==0' :
- 'n<=' + b + '&&(n-(' + b + '))%' + a + '==0' : a === 0 ?
- 'n==' + b : a == -1 ? 'n<=' + b : 'n>=' + b;
- source =
- 'if(e!==h){' +
- 'n=s[' + (/-of-type/i.test(match[1]) ? '"nthOfType"' : '"nthElement"') + ']' +
- '(e,' + (/last/i.test(match[1]) ? 'true' : 'false') + ');' +
- 'if(' + test + '){' + source + '}' +
- '}';
-
- } else if (match[1]) {
-
- a = /first/i.test(match[1]) ? 'previous' : 'next';
- n = /only/i.test(match[1]) ? 'previous' : 'next';
- b = /first|last/i.test(match[1]);
- type = /-of-type/i.test(match[1]) ? '&&n.nodeName!==e.nodeName' : '&&n.nodeName<"@"';
- source = 'if(e!==h){' +
- ( 'n=e;while((n=n.' + a + 'Sibling)' + type + ');if(!n){' + (b ? source :
- 'n=e;while((n=n.' + n + 'Sibling)' + type + ');if(!n){' + source + '}') + '}' ) + '}';
-
- } else {
-
- status = false;
-
- }
- break;
- }
-
- return {
- 'source': source,
- 'status': status
- };
-
- };
-
- })(this));
-
- NW.Dom.registerSelector(
- 'nwmatcher:dpseudos',
- /^\:(link|visited|target|active|focus|hover|checked|disabled|enabled|selected|lang\(([-\w]{2,})\)|not\(\s*(:nth(?:-last)?(?:-child|-of-type)\(\s*(?:even|odd|(?:[-+]{0,1}\d*n\s*)?[-+]{0,1}\s*\d*)\s*\)|[^()]*)\s*\))?(.*)/i,
- (function(global) {
-
- var doc = global.document,
- Config = NW.Dom.Config,
- Tokens = NW.Dom.Tokens,
-
- reTrimSpace = RegExp('^\\s+|\\s+$', 'g'),
-
- reSimpleNot = RegExp('^((?!:not)' +
- '(' + Tokens.prefixes + '|' + Tokens.identifier +
- '|\\([^()]*\\))+|\\[' + Tokens.attributes + '\\])$');
-
- return function(match, source) {
-
- var expr, status = true, test;
-
- switch (match[1].match(/^\w+/)[0]) {
-
- case 'not':
- expr = match[3].replace(reTrimSpace, '');
- if (Config.SIMPLENOT && !reSimpleNot.test(expr)) {
- NW.Dom.emit('Negation pseudo-class only accepts simple selectors "' + selector + '"');
- } else {
- if ('compatMode' in doc) {
- source = 'if(!' + NW.Dom.compile(expr, '', false) + '(e,s,d,h,g)){' + source + '}';
- } else {
- source = 'if(!s.match(e, "' + expr.replace(/\x22/g, '\\"') + '",g)){' + source +'}';
- }
- }
- break;
-
- case 'checked':
- source = 'if((typeof e.form!=="undefined"&&(/^(?:radio|checkbox)$/i).test(e.type)&&e.checked)' +
- (Config.USE_HTML5 ? '||(/^option$/i.test(e.nodeName)&&(e.selected||e.checked))' : '') +
- '){' + source + '}';
- break;
-
- case 'disabled':
- source = 'if(((typeof e.form!=="undefined"' +
- (Config.USE_HTML5 ? '' : '&&!(/^hidden$/i).test(e.type)') +
- ')||s.isLink(e))&&e.disabled===true){' + source + '}';
- break;
-
- case 'enabled':
- source = 'if(((typeof e.form!=="undefined"' +
- (Config.USE_HTML5 ? '' : '&&!(/^hidden$/i).test(e.type)') +
- ')||s.isLink(e))&&e.disabled===false){' + source + '}';
- break;
-
- case 'lang':
- test = '';
- if (match[2]) test = match[2].substr(0, 2) + '-';
- source = 'do{(n=e.lang||"").toLowerCase();' +
- 'if((n==""&&h.lang=="' + match[2].toLowerCase() + '")||' +
- '(n&&(n=="' + match[2].toLowerCase() +
- '"||n.substr(0,3)=="' + test.toLowerCase() + '")))' +
- '{' + source + 'break;}}while((e=e.parentNode)&&e!==g);';
- break;
-
- case 'target':
- source = 'if(e.id==d.location.hash.slice(1)){' + source + '}';
- break;
-
- case 'link':
- source = 'if(s.isLink(e)&&!e.visited){' + source + '}';
- break;
-
- case 'visited':
- source = 'if(s.isLink(e)&&e.visited){' + source + '}';
- break;
-
- case 'active':
- source = 'if(e===d.activeElement){' + source + '}';
- break;
-
- case 'hover':
- source = 'if(e===d.hoverElement){' + source + '}';
- break;
-
- case 'focus':
- source = 'hasFocus' in doc ?
- 'if(e===d.activeElement&&d.hasFocus()&&(e.type||e.href||typeof e.tabIndex=="number")){' + source + '}' :
- 'if(e===d.activeElement&&(e.type||e.href)){' + source + '}';
- break;
-
- case 'selected':
- source = 'if(/^option$/i.test(e.nodeName)&&(e.selected||e.checked)){' + source + '}';
- break;
-
- default:
- status = false;
- break;
- }
-
- return {
- 'source': source,
- 'status': status
- };
-
- };
-
- })(this));
-
- NW.Dom.registerSelector(
- 'nwmatcher:epseudos',
- /^((?:[:]{1,2}(?:after|before|first-letter|first-line))|(?:[:]{2,2}(?:selection|backdrop|placeholder)))?(.*)/i,
- (function(global) {
-
- return function(match, source) {
-
- var status = true;
-
- switch (match[1].match(/(\w+)$/)[0]) {
-
- case 'after':
- case 'before':
- case 'first-letter':
- case 'first-line':
- case 'selection':
- case 'backdrop':
- case 'placeholder':
- source = 'if(!(/1|11/).test(e.nodeType)){' + source + '}';
- break;
-
- default:
- status = false;
- break;
- }
-
- return {
- 'source': source,
- 'status': status
- };
-
- };
-
- })(this));
|