diff --git a/bin/Release/AppX/vs.appxrecipe b/bin/Release/AppX/vs.appxrecipe index af81a47e..a343def7 100644 --- a/bin/Release/AppX/vs.appxrecipe +++ b/bin/Release/AppX/vs.appxrecipe @@ -32,7 +32,7 @@ AppxManifest.xml true - 2017-08-19T13:17:37.811 + 2017-08-20T18:41:06.455 @@ -399,7 +399,7 @@ www\css\app.css - 2017-08-17T13:55:29.992 + 2017-08-20T18:09:44.037 www\css\bootstrap-theme.css @@ -415,7 +415,7 @@ www\index.html - 2017-08-19T13:17:20.030 + 2017-08-20T14:54:56.576 www\favicon.ico @@ -543,7 +543,7 @@ www\js\app.js - 2017-08-19T13:17:32.154 + 2017-08-20T18:03:09.796 www\js\init.js @@ -587,7 +587,7 @@ www\js\lib\util.js - 2017-08-19T13:11:37.419 + 2017-08-20T18:40:59.430 www\js\lib\xzdec.js diff --git a/bin/Release/AppX/www/css/app.css b/bin/Release/AppX/www/css/app.css index 6fee3c47..7ef85d07 100644 --- a/bin/Release/AppX/www/css/app.css +++ b/bin/Release/AppX/www/css/app.css @@ -31,7 +31,7 @@ [role=region] > header { /*margin: .5rem 0 1rem 0;*/ - margin: 0 0.75em 0 0; + margin: 0 0.75em 0 1px; text-align: center; } @@ -116,7 +116,7 @@ background: inherit; } -.btn-sm { +.btn-sm, .btn-lg { background: rgba(51,122,183,0.7) !important; border: transparent !important; float: none !important; @@ -160,30 +160,34 @@ footer .glyphicon { border-color: darkgray; } +.dark a { + color: lightblue !important; +} + .darkfooter .dropdown-menu, .darkfooter .dropdown-menu a { color: lightblue !important; background-color: rgba(34,34,34,0.6) !important; border-color: darkgray; } - .darkfooter .dropdown-menu a:focus, .darkfooter .dropdown-menu a:hover { - color: lightblue !important; - background: darkslategray !important; - } +.darkfooter .dropdown-menu a:focus, .darkfooter .dropdown-menu a:hover { + color: lightblue !important; + background: darkslategray !important; +} .dark .list-group-item { color: lightblue !important; background-color: #222 !important; } -.dark a.list-group-item:hover, .dark a.list-group-item:focus, .dark nav a:hover, .dark nav a:focus { +.dark a.list-group-item:hover, .dark a.list-group-item:focus, .dark nav a:hover, .dark nav a:focus, .dark nav .active { color: lightblue !important; background-color: darkslategray !important; } -.dark .btn-default { +.dark .btn-default, .dark .input-group-addon { background: #222 !important; - color: dimgray !important; + color: lightgray !important; text-shadow: none; } diff --git a/bin/Release/AppX/www/index.html b/bin/Release/AppX/www/index.html index f9fb5590..7944ffc3 100644 --- a/bin/Release/AppX/www/index.html +++ b/bin/Release/AppX/www/index.html @@ -98,14 +98,13 @@ - diff --git a/bin/Release/AppX/www/js/app.js b/bin/Release/AppX/www/js/app.js index 19132f0b..d15b7371 100644 --- a/bin/Release/AppX/www/js/app.js +++ b/bin/Release/AppX/www/js/app.js @@ -95,17 +95,24 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies', 'abstractFile $('#findText').on('click', function (e) { var innerDocument = window.frames[0].frameElement.contentDocument || window.frames[0].frameElement.contentWindow.document; if (innerDocument.body.innerHTML.length < 10) return; + innerDocument = innerDocument.body; + if (!innerDocument) return; var searchDiv = document.getElementById('row2'); var findInArticle = document.getElementById('findInArticle'); if (searchDiv.style.display == 'none') { searchDiv.style.display = "inline"; + document.getElementById('findText').classList.add("active"); findInArticle.focus(); } else { + findInArticle.value = ""; + document.getElementById('matches').innerHTML = "Full: 0"; + document.getElementById('partial').innerHTML = "Partial: 0"; searchDiv.style.display = "none"; + document.getElementById('findText').classList.remove("active"); } if (localSearch.remove) { localSearch.remove(); - } else { + } else if (searchDiv.style.display == "inline") { localSearch = new util.Hilitor(innerDocument); //TODO: Check right-to-left language support... localSearch.setMatchType('left'); @@ -113,14 +120,32 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies', 'abstractFile findInArticle.addEventListener('keyup', function (e) { //Ensure timeout doesn't occur if another key has been pressed within time window clearTimeout(timer); + //If user pressed Alt-F, exit + if (e.altKey && e.which == 70) return; var val = this.value; + if (val && e.which == 13) { + localSearch.scrollToFullMatch(val); + return; + } //Ensure nothing happens if only one value has been entered (not specific enough), but ensure timeout is set //if no value has been entered (clears highlighting if user deletes all values in search field) if (~(val.length - 2)) { timer = setTimeout(function () { localSearch.apply(val); - var x = localSearch.countMatches(); - + if (val.length) { + var fullTotal = localSearch.countFullMatches(val); + var partialTotal = localSearch.countPartialMatches(); + fullTotal = fullTotal > partialTotal ? partialTotal : fullTotal; + document.getElementById('matches').innerHTML = 'Full: ' + fullTotal + ''; + document.getElementById('partial').innerHTML = "Partial: " + partialTotal; + document.getElementById('scrollLink').addEventListener('click', function () { + localSearch.scrollToFullMatch(val); + }); + //localSearch.scrollToFullMatch(val); + } else { + document.getElementById('matches').innerHTML = "Full: 0"; + document.getElementById('partial').innerHTML = "Partial: 0"; + } }, 500); } }, false); diff --git a/bin/Release/AppX/www/js/lib/util.js b/bin/Release/AppX/www/js/lib/util.js index 45b75490..a4686538 100644 --- a/bin/Release/AppX/www/js/lib/util.js +++ b/bin/Release/AppX/www/js/lib/util.js @@ -378,7 +378,6 @@ define(['q'], function(q) { // Please acknowledge use of this code by including this header. // For documentation see: http://www.the-art-of-web.com/javascript/search-highlight/ function Hilitor(node, tag) { - var targetNode = node || document.body; var hiliteTag = tag || "EM"; var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM)$"); @@ -388,7 +387,7 @@ define(['q'], function(q) { var colorIdx = 0; var matchRegex = ""; //Add any symbols that may prefix a start string and don't match \b (word boundary) - var leadingSymbols = "’‘¿¡"; + var leadingSymbols = "’‘¿¡-"; var openLeft = false; var openRight = false; @@ -417,11 +416,12 @@ define(['q'], function(q) { function addAccents(input) { var retval = input; retval = retval.replace(/([ao])e/ig, "$1"); - retval = retval.replace(/\\u00E[024]/ig, "a"); + retval = retval.replace(/\\u00[CE][0124]/ig, "a"); retval = retval.replace(/\\u00E7/ig, "c"); retval = retval.replace(/\\u00E[89AB]|\\u00C[9A]/ig, "e"); - retval = retval.replace(/\\u00E[DEF]/ig, "i"); - retval = retval.replace(/\\u00F[46]/ig, "o"); + retval = retval.replace(/\\u00[CE][DEF]/ig, "i"); + retval = retval.replace(/\\u00[DF]1/ig, "n"); + retval = retval.replace(/\\u00[FD][346]/ig, "o"); retval = retval.replace(/\\u00F[9BC]/ig, "u"); retval = retval.replace(/\\u00FF/ig, "y"); retval = retval.replace(/\\u00DF/ig, "s"); @@ -459,10 +459,78 @@ define(['q'], function(q) { return retval; }; - this.countMatches = function () { + this.countFullMatches = function (input) { if (node === undefined || !node) return; - var matches = matchInner(node.body.innerHTML, '<' + hiliteTag + '\\b[^>]*class="hilitor"[^>]*>', '', 'gi'); - return matches.length; + var strippedText = node.innerHTML.replace(/]*>[\s\S]*<\/title>/i, ""); + strippedText = node.innerHTML.replace(/<[^>]*>\s*/g, " "); + if (!strippedText) return 0; + strippedText = strippedText.replace(/(?: |\r?\n|[.,;:?!¿¡-])+/g, " "); + strippedText = strippedText.replace(/\s+/g, " "); + if (!strippedText.length) return 0; + input = input.replace(/[\s.,;:?!¿¡-]+/g, " "); + var inputMatcher = new RegExp(input, "ig"); + var matches = strippedText.match(inputMatcher); + if (matches) return matches.length + else return 0; + } + + this.countPartialMatches = function () { + if (node === undefined || !node) return; + var matches = matchInner(node.innerHTML, '<' + hiliteTag + '\\b[^>]*class="hilitor"[^>]*>', '', 'gi'); + if (matches) return matches.length + else return 0; + //if (matches) { + // var input = document.getElementById('findInArticle').value.replace(/\s*/g, "").toLowerCase(); + // var matchedWords = ""; + // var buffer = ""; + // var countFullMatches = 0; + // for (var i = 0; i < matches.length; i++ ) { + // var instance = matches[i].match(/<[^>]*>([^<]*) hilitedNodes.length - 1) break; + subNodes.push(hilitedNodes[f].innerHTML); + } + var nodeText = subNodes.join(" "); + if (testInput.test(nodeText)) { + //hilitedNodes[start].scrollIntoView(true); + $("#articleContent").contents().scrollTop($(hilitedNodes[start]).offset().top); + break; + } + subNodes = []; + end++; + } } // recursively apply word highlighting @@ -484,7 +552,7 @@ define(['q'], function(q) { var match = document.createElement(hiliteTag); match.appendChild(document.createTextNode(regs[1])); - match.style.backgroundColor = wordColor[regs[1].toLowerCase()]; + match.style.setProperty("background-color", wordColor[regs[1].toLowerCase()], "important"); match.style.fontStyle = "inherit"; match.style.color = "#000"; match.className = className; diff --git a/www/css/app.css b/www/css/app.css index 6fee3c47..7ef85d07 100644 --- a/www/css/app.css +++ b/www/css/app.css @@ -31,7 +31,7 @@ [role=region] > header { /*margin: .5rem 0 1rem 0;*/ - margin: 0 0.75em 0 0; + margin: 0 0.75em 0 1px; text-align: center; } @@ -116,7 +116,7 @@ background: inherit; } -.btn-sm { +.btn-sm, .btn-lg { background: rgba(51,122,183,0.7) !important; border: transparent !important; float: none !important; @@ -160,30 +160,34 @@ footer .glyphicon { border-color: darkgray; } +.dark a { + color: lightblue !important; +} + .darkfooter .dropdown-menu, .darkfooter .dropdown-menu a { color: lightblue !important; background-color: rgba(34,34,34,0.6) !important; border-color: darkgray; } - .darkfooter .dropdown-menu a:focus, .darkfooter .dropdown-menu a:hover { - color: lightblue !important; - background: darkslategray !important; - } +.darkfooter .dropdown-menu a:focus, .darkfooter .dropdown-menu a:hover { + color: lightblue !important; + background: darkslategray !important; +} .dark .list-group-item { color: lightblue !important; background-color: #222 !important; } -.dark a.list-group-item:hover, .dark a.list-group-item:focus, .dark nav a:hover, .dark nav a:focus { +.dark a.list-group-item:hover, .dark a.list-group-item:focus, .dark nav a:hover, .dark nav a:focus, .dark nav .active { color: lightblue !important; background-color: darkslategray !important; } -.dark .btn-default { +.dark .btn-default, .dark .input-group-addon { background: #222 !important; - color: dimgray !important; + color: lightgray !important; text-shadow: none; } diff --git a/www/index.html b/www/index.html index f9fb5590..7944ffc3 100644 --- a/www/index.html +++ b/www/index.html @@ -98,14 +98,13 @@ - diff --git a/www/js/app.js b/www/js/app.js index 19132f0b..d15b7371 100644 --- a/www/js/app.js +++ b/www/js/app.js @@ -95,17 +95,24 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies', 'abstractFile $('#findText').on('click', function (e) { var innerDocument = window.frames[0].frameElement.contentDocument || window.frames[0].frameElement.contentWindow.document; if (innerDocument.body.innerHTML.length < 10) return; + innerDocument = innerDocument.body; + if (!innerDocument) return; var searchDiv = document.getElementById('row2'); var findInArticle = document.getElementById('findInArticle'); if (searchDiv.style.display == 'none') { searchDiv.style.display = "inline"; + document.getElementById('findText').classList.add("active"); findInArticle.focus(); } else { + findInArticle.value = ""; + document.getElementById('matches').innerHTML = "Full: 0"; + document.getElementById('partial').innerHTML = "Partial: 0"; searchDiv.style.display = "none"; + document.getElementById('findText').classList.remove("active"); } if (localSearch.remove) { localSearch.remove(); - } else { + } else if (searchDiv.style.display == "inline") { localSearch = new util.Hilitor(innerDocument); //TODO: Check right-to-left language support... localSearch.setMatchType('left'); @@ -113,14 +120,32 @@ define(['jquery', 'zimArchiveLoader', 'util', 'uiUtil', 'cookies', 'abstractFile findInArticle.addEventListener('keyup', function (e) { //Ensure timeout doesn't occur if another key has been pressed within time window clearTimeout(timer); + //If user pressed Alt-F, exit + if (e.altKey && e.which == 70) return; var val = this.value; + if (val && e.which == 13) { + localSearch.scrollToFullMatch(val); + return; + } //Ensure nothing happens if only one value has been entered (not specific enough), but ensure timeout is set //if no value has been entered (clears highlighting if user deletes all values in search field) if (~(val.length - 2)) { timer = setTimeout(function () { localSearch.apply(val); - var x = localSearch.countMatches(); - + if (val.length) { + var fullTotal = localSearch.countFullMatches(val); + var partialTotal = localSearch.countPartialMatches(); + fullTotal = fullTotal > partialTotal ? partialTotal : fullTotal; + document.getElementById('matches').innerHTML = 'Full: ' + fullTotal + ''; + document.getElementById('partial').innerHTML = "Partial: " + partialTotal; + document.getElementById('scrollLink').addEventListener('click', function () { + localSearch.scrollToFullMatch(val); + }); + //localSearch.scrollToFullMatch(val); + } else { + document.getElementById('matches').innerHTML = "Full: 0"; + document.getElementById('partial').innerHTML = "Partial: 0"; + } }, 500); } }, false); diff --git a/www/js/lib/util.js b/www/js/lib/util.js index 45b75490..a4686538 100644 --- a/www/js/lib/util.js +++ b/www/js/lib/util.js @@ -378,7 +378,6 @@ define(['q'], function(q) { // Please acknowledge use of this code by including this header. // For documentation see: http://www.the-art-of-web.com/javascript/search-highlight/ function Hilitor(node, tag) { - var targetNode = node || document.body; var hiliteTag = tag || "EM"; var skipTags = new RegExp("^(?:" + hiliteTag + "|SCRIPT|FORM)$"); @@ -388,7 +387,7 @@ define(['q'], function(q) { var colorIdx = 0; var matchRegex = ""; //Add any symbols that may prefix a start string and don't match \b (word boundary) - var leadingSymbols = "’‘¿¡"; + var leadingSymbols = "’‘¿¡-"; var openLeft = false; var openRight = false; @@ -417,11 +416,12 @@ define(['q'], function(q) { function addAccents(input) { var retval = input; retval = retval.replace(/([ao])e/ig, "$1"); - retval = retval.replace(/\\u00E[024]/ig, "a"); + retval = retval.replace(/\\u00[CE][0124]/ig, "a"); retval = retval.replace(/\\u00E7/ig, "c"); retval = retval.replace(/\\u00E[89AB]|\\u00C[9A]/ig, "e"); - retval = retval.replace(/\\u00E[DEF]/ig, "i"); - retval = retval.replace(/\\u00F[46]/ig, "o"); + retval = retval.replace(/\\u00[CE][DEF]/ig, "i"); + retval = retval.replace(/\\u00[DF]1/ig, "n"); + retval = retval.replace(/\\u00[FD][346]/ig, "o"); retval = retval.replace(/\\u00F[9BC]/ig, "u"); retval = retval.replace(/\\u00FF/ig, "y"); retval = retval.replace(/\\u00DF/ig, "s"); @@ -459,10 +459,78 @@ define(['q'], function(q) { return retval; }; - this.countMatches = function () { + this.countFullMatches = function (input) { if (node === undefined || !node) return; - var matches = matchInner(node.body.innerHTML, '<' + hiliteTag + '\\b[^>]*class="hilitor"[^>]*>', '', 'gi'); - return matches.length; + var strippedText = node.innerHTML.replace(/]*>[\s\S]*<\/title>/i, ""); + strippedText = node.innerHTML.replace(/<[^>]*>\s*/g, " "); + if (!strippedText) return 0; + strippedText = strippedText.replace(/(?: |\r?\n|[.,;:?!¿¡-])+/g, " "); + strippedText = strippedText.replace(/\s+/g, " "); + if (!strippedText.length) return 0; + input = input.replace(/[\s.,;:?!¿¡-]+/g, " "); + var inputMatcher = new RegExp(input, "ig"); + var matches = strippedText.match(inputMatcher); + if (matches) return matches.length + else return 0; + } + + this.countPartialMatches = function () { + if (node === undefined || !node) return; + var matches = matchInner(node.innerHTML, '<' + hiliteTag + '\\b[^>]*class="hilitor"[^>]*>', '', 'gi'); + if (matches) return matches.length + else return 0; + //if (matches) { + // var input = document.getElementById('findInArticle').value.replace(/\s*/g, "").toLowerCase(); + // var matchedWords = ""; + // var buffer = ""; + // var countFullMatches = 0; + // for (var i = 0; i < matches.length; i++ ) { + // var instance = matches[i].match(/<[^>]*>([^<]*) hilitedNodes.length - 1) break; + subNodes.push(hilitedNodes[f].innerHTML); + } + var nodeText = subNodes.join(" "); + if (testInput.test(nodeText)) { + //hilitedNodes[start].scrollIntoView(true); + $("#articleContent").contents().scrollTop($(hilitedNodes[start]).offset().top); + break; + } + subNodes = []; + end++; + } } // recursively apply word highlighting @@ -484,7 +552,7 @@ define(['q'], function(q) { var match = document.createElement(hiliteTag); match.appendChild(document.createTextNode(regs[1])); - match.style.backgroundColor = wordColor[regs[1].toLowerCase()]; + match.style.setProperty("background-color", wordColor[regs[1].toLowerCase()], "important"); match.style.fontStyle = "inherit"; match.style.color = "#000"; match.className = className;