diff --git a/js/element-picker.js b/js/element-picker.js index 90d920e84..324bd40e3 100644 --- a/js/element-picker.js +++ b/js/element-picker.js @@ -401,31 +401,11 @@ var cosmeticFilterFromElement = function(elem) { } } - if ( suffix.length === 0 ) { - return; - } - return prefix + suffix.join(''); }; /******************************************************************************/ -var stopPicker = function() { - if ( pickerRoot !== null ) { - taCandidate.removeEventListener('change', onCandidateChanged); - taCandidate.removeEventListener('propertychange', onCandidateChanged); - divDialog.removeEventListener('click', onDialogClicked); - svgRoot.removeEventListener('mousemove', onSvgHovered); - svgRoot.removeEventListener('click', onSvgClicked); - document.body.removeChild(pickerRoot); - pickerRoot = divDialog = svgRoot = svgOcean = svgIslands = null; - messaging.stop(); - } - targetElements = []; -}; - -/******************************************************************************/ - var selectorFromCandidate = function() { var selector = ''; var v = taCandidate.value; @@ -476,7 +456,7 @@ var userFilterFromCandidate = function() { /******************************************************************************/ -var onCandidateChanged = function() { +var onCandidateChanged = function(ev) { var selector = selectorFromCandidate(); divDialog.querySelector('#create').disabled = selector === ''; if ( selector === '' ) { @@ -488,6 +468,36 @@ var onCandidateChanged = function() { /******************************************************************************/ +var candidateFromClickEvent = function(ev) { + var target = ev.target; + if ( !target ) { + return ''; + } + + // Bare + if ( ev.ctrlKey || ev.metaKey ) { + return target.textContent; + } + + // For net filters there no such thing as a path + if ( target.textContent.slice(0, 2) === '||' ) { + return target.textContent; + } + + // Return path: the target element, then all siblings prepended + var selector = []; + while ( target ) { + if ( target.nodeType !== 1 || target.tagName.toLowerCase() !== 'li' ) { + continue; + } + selector.unshift(target.textContent.replace(/^##/, '')); + target = target.nextSibling; + } + return '##' + selector.join(' > '); +}; + +/******************************************************************************/ + var onDialogClicked = function(ev) { if ( ev.target === null ) { /* do nothing */ @@ -511,7 +521,7 @@ var onDialogClicked = function(ev) { } else if ( ev.target.tagName.toLowerCase() === 'li' && pickerRootDistance(ev.target) === 5 ) { - taCandidate.value = ev.target.textContent; + taCandidate.value = candidateFromClickEvent(ev); onCandidateChanged(); } @@ -591,7 +601,33 @@ var onSvgClicked = function() { /******************************************************************************/ -var startPicker = function(details) { +var onKeyPressed = function(ev) { + if ( ev.key === 27 || ev.keyCode === 27 ) { + ev.stopPropagation(); + ev.preventDefault(); + stopPicker(); + } +}; + +/******************************************************************************/ + +var stopPicker = function() { + if ( pickerRoot !== null ) { + document.removeEventListener('keydown', onKeyPressed); + taCandidate.removeEventListener('input', onCandidateChanged); + divDialog.removeEventListener('click', onDialogClicked); + svgRoot.removeEventListener('mousemove', onSvgHovered); + svgRoot.removeEventListener('click', onSvgClicked); + document.body.removeChild(pickerRoot); + pickerRoot = divDialog = svgRoot = svgOcean = svgIslands = taCandidate = null; + messaging.stop(); + } + targetElements = []; +}; + +/******************************************************************************/ + +var startPicker = function() { pickerRoot = document.querySelector('.' + µBlockClassName); if ( pickerRoot !== null ) { return; @@ -672,7 +708,7 @@ var startPicker = function(details) { 'padding: 0;', 'box-sizing: border-box;', 'width: 100%;', - 'height: 6em;', + 'height: 8em;', 'position: relative;', '}', '.µBlock > div > div > textarea {', @@ -727,12 +763,16 @@ var startPicker = function(details) { svgRoot = document.createElementNS(svgns, 'svg'); svgRoot.innerHTML = ''; - var rect = document.documentElement.getBoundingClientRect(); + var nullRect = { left: 0, top: 0, width: 0, height: 0 }; + var htmlRect = document.documentElement ? document.documentElement.getBoundingClientRect() : nullRect; + var bodyRect = document.body ? document.body.getBoundingClientRect() : nullRect; + var svgWidth = Math.max(htmlRect.width, bodyRect.width); + var svgHeight = Math.max(htmlRect.height, bodyRect.height); svgRoot.setAttribute('x', 0); svgRoot.setAttribute('y', 0); - svgRoot.setAttribute('width', rect.width); - svgRoot.setAttribute('height', rect.height); - svgRoot.setAttribute("viewBox", '0 0 ' + rect.width + ' ' + rect.height); + svgRoot.setAttribute('width', svgWidth); + svgRoot.setAttribute('height', svgHeight); + svgRoot.setAttribute("viewBox", '0 0 ' + svgWidth + ' ' + svgHeight); svgOcean = svgRoot.querySelector('path:first-child'); svgIslands = svgRoot.querySelector('path + path'); pickerRoot.appendChild(svgRoot); @@ -765,7 +805,7 @@ var startPicker = function(details) { divDialog.addEventListener('click', onDialogClicked); taCandidate = divDialog.querySelector('textarea'); taCandidate.addEventListener('input', onCandidateChanged); - taCandidate.addEventListener('onpropertychange', onCandidateChanged); + document.addEventListener('keydown', onKeyPressed); }; /******************************************************************************/