From 04077a95aa8aa56c7312a366fc6fdd2f4d5b83d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gregor=20M=C3=BCllegger?= Date: Thu, 10 Sep 2015 12:20:00 +0200 Subject: [PATCH] Highlight searchterms in mkdocs projects Sphinx has a theme agnostic feature to highlight terms given by the "highlight" GET parameter. This is used by RTD when linking from the search page to the documentation page. This did not work for mkdocs projects yet. We add the logic for this to readthedocs-embed-js in order to make this feature available independently of the used mkdocs theme. --- .../static-src/core/js/doc-embed/mkdocs.js | 4 ++ .../core/js/highlight-searchterm.js | 60 +++++++++++++++++++ .../core/js/jquery.highlighttext.js | 29 +++++++++ .../static/core/js/readthedocs-doc-embed.js | 2 +- 4 files changed, 94 insertions(+), 1 deletion(-) create mode 100644 readthedocs/core/static-src/core/js/highlight-searchterm.js create mode 100644 readthedocs/core/static-src/core/js/jquery.highlighttext.js diff --git a/readthedocs/core/static-src/core/js/doc-embed/mkdocs.js b/readthedocs/core/static-src/core/js/doc-embed/mkdocs.js index 2060a37a4a0..272e7b26496 100644 --- a/readthedocs/core/static-src/core/js/doc-embed/mkdocs.js +++ b/readthedocs/core/static-src/core/js/doc-embed/mkdocs.js @@ -4,6 +4,7 @@ var rtddata = require('./rtd-data'); +var highlightSearchterm = require('../highlight-searchterm'); function init() { @@ -42,6 +43,9 @@ function init() { }; win.on('resize', apply_stickynav); apply_stickynav(); + + // Init searchterm highlighting + highlightSearchterm.init(); } } diff --git a/readthedocs/core/static-src/core/js/highlight-searchterm.js b/readthedocs/core/static-src/core/js/highlight-searchterm.js new file mode 100644 index 00000000000..233c1a94f1c --- /dev/null +++ b/readthedocs/core/static-src/core/js/highlight-searchterm.js @@ -0,0 +1,60 @@ +/* + * Allow highlighting of search terms, passed in as "highlight" GET parameter. + * + * This imitades the behaviour of what is implemented in Sphinx's doctools.js. + * Mkdocs does not provide a similiar logic, we implement it here instead which + * will work theme agnostic. + */ + + +require('./jquery.highlighttext'); + + +function init() { + highlightSearchWords(); +} + + +function urldecode(x) { + return decodeURIComponent(x).replace(/\+/g, ' '); +} + + +function getQueryParameters(s) { + if (typeof s == 'undefined') + s = document.location.search; + var parts = s.substr(s.indexOf('?') + 1).split('&'); + var result = {}; + for (var i = 0; i < parts.length; i++) { + var tmp = parts[i].split('=', 2); + var key = urldecode(tmp[0]); + var value = urldecode(tmp[1]); + if (key in result) + result[key].push(value); + else + result[key] = [value]; + } + return result; +} + + +function highlightSearchWords() { + var params = getQueryParameters(); + var terms = (params.highlight) ? params.highlight[0].split(/\s+/) : []; + if (terms.length) { + var body = $('div.body'); + if (!body.length) { + var body = $('body'); + } + window.setTimeout(function() { + $.each(terms, function() { + body.highlightText(this.toLowerCase(), 'highlighted'); + }); + }, 10); + } +} + + +module.exports = { + init: init +}; diff --git a/readthedocs/core/static-src/core/js/jquery.highlighttext.js b/readthedocs/core/static-src/core/js/jquery.highlighttext.js new file mode 100644 index 00000000000..2e36f913820 --- /dev/null +++ b/readthedocs/core/static-src/core/js/jquery.highlighttext.js @@ -0,0 +1,29 @@ +/** + * highlight a given string on a jquery object by wrapping it in + * span elements with the given class name. + */ +jQuery.fn.highlightText = function(text, className) { + function highlight(node) { + if (node.nodeType == 3) { + var val = node.nodeValue; + var pos = val.toLowerCase().indexOf(text); + if (pos >= 0 && !jQuery(node.parentNode).hasClass(className)) { + var span = document.createElement("span"); + span.className = className; + span.appendChild(document.createTextNode(val.substr(pos, text.length))); + node.parentNode.insertBefore(span, node.parentNode.insertBefore( + document.createTextNode(val.substr(pos + text.length)), + node.nextSibling)); + node.nodeValue = val.substr(0, pos); + } + } + else if (!jQuery(node).is("button, select, textarea")) { + jQuery.each(node.childNodes, function() { + highlight(this); + }); + } + } + return this.each(function() { + highlight(this); + }); +}; diff --git a/readthedocs/core/static/core/js/readthedocs-doc-embed.js b/readthedocs/core/static/core/js/readthedocs-doc-embed.js index 717352f2272..7610f58cf00 100644 --- a/readthedocs/core/static/core/js/readthedocs-doc-embed.js +++ b/readthedocs/core/static/core/js/readthedocs-doc-embed.js @@ -1 +1 @@ -!function t(e,n,r){function o(s,a){if(!n[s]){if(!e[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(i)return i(s,!0);var d=new Error("Cannot find module '"+s+"'");throw d.code="MODULE_NOT_FOUND",d}var l=n[s]={exports:{}};e[s][0].call(l.exports,function(t){var n=e[s][1][t];return o(n?n:t)},l,l.exports,t,e,n,r)}return n[s].exports}for(var i="function"==typeof require&&require,s=0;s"),t(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var n=t(this);expand=t(''),expand.on("click",function(t){return e.toggleCurrent(n),t.stopPropagation(),!1}),n.prepend(expand)})},t.reset=function(){var t=encodeURI(window.location.hash);if(t)try{var e=$(".wy-menu-vertical").find('[href="'+t+'"]');$(".wy-menu-vertical li.toctree-l1 li.current").removeClass("current"),e.closest("li.toctree-l2").addClass("current"),e.closest("li.toctree-l3").addClass("current"),e.closest("li.toctree-l4").addClass("current")}catch(n){console.log("Error expanding nav for anchor",n)}},t.onScroll=function(){this.winScroll=!1;var t=this.win.scrollTop(),e=t+this.winHeight,n=this.navBar.scrollTop(),r=n+(t-this.winPosition);0>t||e>this.docHeight||(this.navBar.scrollTop(r),this.winPosition=t)},t.onResize=function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},t.hashChange=function(){this.linkScroll=!0,this.win.one("hashchange",function(){this.linkScroll=!1})},t.toggleCurrent=function(t){var e=t.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")},t}var o="undefined"!=typeof window?window.jQuery:t("jquery");e.exports.ThemeNav=r(),"undefined"!=typeof window&&(window.SphinxRtdTheme={StickyNav:e.exports.ThemeNav})},{jquery:"jquery"}],2:[function(t,e,n){function r(){var t=s.get(),e={project:t.project,version:t.version,page:t.page,theme:t.get_theme_name(),format:"jsonp"};"docroot"in t&&(e.docroot=t.docroot),"source_suffix"in t&&(e.source_suffix=t.source_suffix),0===window.location.pathname.indexOf("/projects/")&&(e.subproject=!0),$.ajax({url:t.api_host+"/api/v2/footer_html/",crossDomain:!0,xhrFields:{withCredentials:!0},dataType:"jsonp",data:e,success:function(t){a.init(t.version_compare),o(t),i()},error:function(){console.error("Error loading Read the Docs footer")}})}function o(t){var e=s.get();if(e.is_rtd_theme()?$("div.rst-other-versions").html(t.html):$("body").append(t.html),t.version_active?!t.version_supported:$(".rst-current-version").addClass("rst-out-of-date"),t.promo&&e.show_promo()){var n=new c.Promo(t.promo_data.id,t.promo_data.text,t.promo_data.link,t.promo_data.image);n&&n.display()}}function i(){function t(t){return/^(GET|HEAD|OPTIONS|TRACE)$/.test(t)}$.ajaxSetup({beforeSend:function(e,n){t(n.type)||e.setRequestHeader("X-CSRFToken",$("a.bookmark[token]").attr("token"))}})}var s=t("./rtd-data"),a=t("./version-compare"),c=t("../sponsorship");e.exports={init:r}},{"../sponsorship":9,"./rtd-data":5,"./version-compare":7}],3:[function(t,e,n){function r(){$.ajax({url:"https://api.grokthedocs.com/static/javascript/bundle-client.js",crossDomain:!0,dataType:"script"})}e.exports={init:r}},{}],4:[function(t,e,n){function r(){var t=o.get();if("builder"in t&&"mkdocs"==t.builder){$("").attr({type:"hidden",name:"project",value:t.project}).appendTo("#rtd-search-form"),$("").attr({type:"hidden",name:"version",value:t.version}).appendTo("#rtd-search-form"),$("").attr({type:"hidden",name:"type",value:"file"}).appendTo("#rtd-search-form"),$("#rtd-search-form").prop("action",t.api_host+"/search/");var e=$("nav.wy-nav-side:first"),n=$(window),r="stickynav",i=function(){e.height()<=n.height()?e.addClass(r):e.removeClass(r)};n.on("resize",i),i()}}var o=t("./rtd-data");e.exports={init:r}},{"./rtd-data":5}],5:[function(t,e,n){function r(){var t=Object.create(o),e={api_host:"https://readthedocs.org"};return $.extend(t,e,window.READTHEDOCS_DATA),t}var o={is_rtd_theme:function(){return"sphinx_rtd_theme"===this.get_theme_name()},is_sphinx_builder:function(){return!("builder"in this)||"mkdocs"!=this.builder},get_theme_name:function(){return"sphinx_rtd_theme"!==this.theme&&1===$("div.rst-other-versions").length?"sphinx_rtd_theme":this.theme},show_promo:function(){return"https://readthedocs.com"!==this.api_host&&this.is_sphinx_builder()&&this.is_rtd_theme()}};e.exports={get:r}},{}],6:[function(t,e,n){function r(){var t=o.get();if($(document).on("click","[data-toggle='rst-current-version']",function(){var t=$("[data-toggle='rst-versions']").hasClass("shift-up")?"was_open":"was_closed";_gaq&&_gaq.push(["rtfd._setAccount","UA-17997319-1"],["rtfd._trackEvent","Flyout","Click",t])}),!("builder"in t)||"builder"in t&&"mkdocs"!=t.builder){var e=i.ThemeNav;if($(document).ready(function(){setTimeout(function(){e.navBar||e.enable()},1e3)}),t.is_rtd_theme()){var n=jquery("div.wy-side-scroll:first");if(!n.length){var r=jquery("nav.wy-nav-side:first"),s=$("
").addClass("wy-side-scroll");r.children().detach().appendTo(s),s.prependTo(r),e.navBar=s}}}}var o=t("./rtd-data"),i=t("./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js");e.exports={init:r}},{"./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js":1,"./rtd-data":5}],7:[function(t,e,n){function r(t){var e=o.get();if(!t.is_highest){var n=window.location.pathname.replace(e.version,t.slug),r=$('

Note

You are not using the most up to date version of the library. is the newest version.

');r.find("a").attr("href",n).text(t.version);var i=$("div.body");i.length||(i=$("div.document")),i.prepend(r)}}var o=t("./rtd-data");e.exports={init:r}},{"./rtd-data":5}],8:[function(t,e,n){var r=(t("./sponsorship"),t("./doc-embed/footer.js")),o=t("./doc-embed/grokthedocs-client"),i=t("./doc-embed/mkdocs"),s=(t("./doc-embed/rtd-data"),t("./doc-embed/sphinx"));$(document).ready(function(){r.init(),s.init(),o.init(),i.init()})},{"./doc-embed/footer.js":2,"./doc-embed/grokthedocs-client":3,"./doc-embed/mkdocs":4,"./doc-embed/rtd-data":5,"./doc-embed/sphinx":6,"./sponsorship":9}],9:[function(t,e,n){function r(t,e,n,r){this.id=t,this.text=e,this.link=n,this.image=r,this.promo=null}e.exports={Promo:r},r.prototype.create=function(){function t(){_gaq&&_gaq.push(["rtfd._setAccount","UA-17997319-1"],["rtfd._trackEvent","Promo","Click",e.id])}var e=this,n=$("nav.wy-nav-side");if(n.length){promo=$("
").attr("class","wy-menu rst-pro");{var r=$("
").attr("class","rst-pro-about"),o=$("").attr("href","http://docs.readthedocs.org/en/latest/sponsors.html#sponsorship-information").appendTo(r);$("").attr("class","fa fa-info-circle").appendTo(o)}if(r.appendTo(promo),e.image){{var i=$("").attr("class","rst-pro-image-wrapper").attr("href",e.link).attr("target","_blank").on("click",t);$("").attr("class","rst-pro-image").attr("src",e.image).appendTo(i)}promo.append(i)}var s=$("").html(e.text);return $(s).find("a").each(function(){$(this).attr("class","rst-pro-link").attr("href",e.link).attr("target","_blank").on("click",t)}),promo.append(s),promo.appendTo(n),promo.wrapper=$("
").attr("class","rst-pro-wrapper").appendTo(n),promo}},r.prototype.display=function(){var t=this.promo;t||(t=this.promo=this.create()),t&&t.show()},r.prototype.disable=function(){},r.from_variants=function(t){if(0==t.length)return null;var e=Math.floor(Math.random()*t.length),n=t[e],o=n.text,i=n.link,s=n.image,a=n.id;return new r(a,o,i,s)}},{}]},{},[8]); \ No newline at end of file +!function t(e,n,i){function r(s,a){if(!n[s]){if(!e[s]){var c="function"==typeof require&&require;if(!a&&c)return c(s,!0);if(o)return o(s,!0);var d=new Error("Cannot find module '"+s+"'");throw d.code="MODULE_NOT_FOUND",d}var l=n[s]={exports:{}};e[s][0].call(l.exports,function(t){var n=e[s][1][t];return r(n?n:t)},l,l.exports,t,e,n,i)}return n[s].exports}for(var o="function"==typeof require&&require,s=0;s
"),t(".wy-menu-vertical ul").not(".simple").siblings("a").each(function(){var n=t(this);expand=t(''),expand.on("click",function(t){return e.toggleCurrent(n),t.stopPropagation(),!1}),n.prepend(expand)})},t.reset=function(){var t=encodeURI(window.location.hash);if(t)try{var e=$(".wy-menu-vertical").find('[href="'+t+'"]');$(".wy-menu-vertical li.toctree-l1 li.current").removeClass("current"),e.closest("li.toctree-l2").addClass("current"),e.closest("li.toctree-l3").addClass("current"),e.closest("li.toctree-l4").addClass("current")}catch(n){console.log("Error expanding nav for anchor",n)}},t.onScroll=function(){this.winScroll=!1;var t=this.win.scrollTop(),e=t+this.winHeight,n=this.navBar.scrollTop(),i=n+(t-this.winPosition);0>t||e>this.docHeight||(this.navBar.scrollTop(i),this.winPosition=t)},t.onResize=function(){this.winResize=!1,this.winHeight=this.win.height(),this.docHeight=$(document).height()},t.hashChange=function(){this.linkScroll=!0,this.win.one("hashchange",function(){this.linkScroll=!1})},t.toggleCurrent=function(t){var e=t.closest("li");e.siblings("li.current").removeClass("current"),e.siblings().find("li.current").removeClass("current"),e.find("> ul li.current").removeClass("current"),e.toggleClass("current")},t}var r="undefined"!=typeof window?window.jQuery:t("jquery");e.exports.ThemeNav=i(),"undefined"!=typeof window&&(window.SphinxRtdTheme={StickyNav:e.exports.ThemeNav})},{jquery:"jquery"}],2:[function(t,e,n){function i(){var t=s.get(),e={project:t.project,version:t.version,page:t.page,theme:t.get_theme_name(),format:"jsonp"};"docroot"in t&&(e.docroot=t.docroot),"source_suffix"in t&&(e.source_suffix=t.source_suffix),0===window.location.pathname.indexOf("/projects/")&&(e.subproject=!0),$.ajax({url:t.api_host+"/api/v2/footer_html/",crossDomain:!0,xhrFields:{withCredentials:!0},dataType:"jsonp",data:e,success:function(t){a.init(t.version_compare),r(t),o()},error:function(){console.error("Error loading Read the Docs footer")}})}function r(t){var e=s.get();if(e.is_rtd_theme()?$("div.rst-other-versions").html(t.html):$("body").append(t.html),t.version_active?!t.version_supported:$(".rst-current-version").addClass("rst-out-of-date"),t.promo&&e.show_promo()){var n=new c.Promo(t.promo_data.id,t.promo_data.text,t.promo_data.link,t.promo_data.image);n&&n.display()}}function o(){function t(t){return/^(GET|HEAD|OPTIONS|TRACE)$/.test(t)}$.ajaxSetup({beforeSend:function(e,n){t(n.type)||e.setRequestHeader("X-CSRFToken",$("a.bookmark[token]").attr("token"))}})}var s=t("./rtd-data"),a=t("./version-compare"),c=t("../sponsorship");e.exports={init:i}},{"../sponsorship":11,"./rtd-data":5,"./version-compare":7}],3:[function(t,e,n){function i(){$.ajax({url:"https://api.grokthedocs.com/static/javascript/bundle-client.js",crossDomain:!0,dataType:"script"})}e.exports={init:i}},{}],4:[function(t,e,n){function i(){var t=r.get();if("builder"in t&&"mkdocs"==t.builder){$("").attr({type:"hidden",name:"project",value:t.project}).appendTo("#rtd-search-form"),$("").attr({type:"hidden",name:"version",value:t.version}).appendTo("#rtd-search-form"),$("").attr({type:"hidden",name:"type",value:"file"}).appendTo("#rtd-search-form"),$("#rtd-search-form").prop("action",t.api_host+"/search/");var e=$("nav.wy-nav-side:first"),n=$(window),i="stickynav",s=function(){e.height()<=n.height()?e.addClass(i):e.removeClass(i)};n.on("resize",s),s(),o.init()}}var r=t("./rtd-data"),o=t("../highlight-searchterm");e.exports={init:i}},{"../highlight-searchterm":8,"./rtd-data":5}],5:[function(t,e,n){function i(){var t=Object.create(r),e={api_host:"https://readthedocs.org"};return $.extend(t,e,window.READTHEDOCS_DATA),t}var r={is_rtd_theme:function(){return"sphinx_rtd_theme"===this.get_theme_name()},is_sphinx_builder:function(){return!("builder"in this)||"mkdocs"!=this.builder},get_theme_name:function(){return"sphinx_rtd_theme"!==this.theme&&1===$("div.rst-other-versions").length?"sphinx_rtd_theme":this.theme},show_promo:function(){return"https://readthedocs.com"!==this.api_host&&this.is_sphinx_builder()&&this.is_rtd_theme()}};e.exports={get:i}},{}],6:[function(t,e,n){function i(){var t=r.get();if($(document).on("click","[data-toggle='rst-current-version']",function(){var t=$("[data-toggle='rst-versions']").hasClass("shift-up")?"was_open":"was_closed";_gaq&&_gaq.push(["rtfd._setAccount","UA-17997319-1"],["rtfd._trackEvent","Flyout","Click",t])}),!("builder"in t)||"builder"in t&&"mkdocs"!=t.builder){var e=o.ThemeNav;if($(document).ready(function(){setTimeout(function(){e.navBar||e.enable()},1e3)}),t.is_rtd_theme()){var n=jquery("div.wy-side-scroll:first");if(!n.length){var i=jquery("nav.wy-nav-side:first"),s=$("
").addClass("wy-side-scroll");i.children().detach().appendTo(s),s.prependTo(i),e.navBar=s}}}}var r=t("./rtd-data"),o=t("./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js");e.exports={init:i}},{"./../../../../../../bower_components/sphinx-rtd-theme/js/theme.js":1,"./rtd-data":5}],7:[function(t,e,n){function i(t){var e=r.get();if(!t.is_highest){var n=window.location.pathname.replace(e.version,t.slug),i=$('');i.find("a").attr("href",n).text(t.version);var o=$("div.body");o.length||(o=$("div.document")),o.prepend(i)}}var r=t("./rtd-data");e.exports={init:i}},{"./rtd-data":5}],8:[function(t,e,n){function i(){s()}function r(t){return decodeURIComponent(t).replace(/\+/g," ")}function o(t){"undefined"==typeof t&&(t=document.location.search);for(var e=t.substr(t.indexOf("?")+1).split("&"),n={},i=0;i=0&&!jQuery(i.parentNode).hasClass(e)){var s=document.createElement("span");s.className=e,s.appendChild(document.createTextNode(r.substr(o,t.length))),i.parentNode.insertBefore(s,i.parentNode.insertBefore(document.createTextNode(r.substr(o+t.length)),i.nextSibling)),i.nodeValue=r.substr(0,o)}}else jQuery(i).is("button, select, textarea")||jQuery.each(i.childNodes,function(){n(this)})}return this.each(function(){n(this)})}},{}],10:[function(t,e,n){var i=(t("./sponsorship"),t("./doc-embed/footer.js")),r=t("./doc-embed/grokthedocs-client"),o=t("./doc-embed/mkdocs"),s=(t("./doc-embed/rtd-data"),t("./doc-embed/sphinx"));$(document).ready(function(){i.init(),s.init(),r.init(),o.init()})},{"./doc-embed/footer.js":2,"./doc-embed/grokthedocs-client":3,"./doc-embed/mkdocs":4,"./doc-embed/rtd-data":5,"./doc-embed/sphinx":6,"./sponsorship":11}],11:[function(t,e,n){function i(t,e,n,i){this.id=t,this.text=e,this.link=n,this.image=i,this.promo=null}e.exports={Promo:i},i.prototype.create=function(){function t(){_gaq&&_gaq.push(["rtfd._setAccount","UA-17997319-1"],["rtfd._trackEvent","Promo","Click",e.id])}var e=this,n=$("nav.wy-nav-side");if(n.length){promo=$("
").attr("class","wy-menu rst-pro");{var i=$("
").attr("class","rst-pro-about"),r=$("").attr("href","http://docs.readthedocs.org/en/latest/sponsors.html#sponsorship-information").appendTo(i);$("").attr("class","fa fa-info-circle").appendTo(r)}if(i.appendTo(promo),e.image){{var o=$("").attr("class","rst-pro-image-wrapper").attr("href",e.link).attr("target","_blank").on("click",t);$("").attr("class","rst-pro-image").attr("src",e.image).appendTo(o)}promo.append(o)}var s=$("").html(e.text);return $(s).find("a").each(function(){$(this).attr("class","rst-pro-link").attr("href",e.link).attr("target","_blank").on("click",t)}),promo.append(s),promo.appendTo(n),promo.wrapper=$("
").attr("class","rst-pro-wrapper").appendTo(n),promo}},i.prototype.display=function(){var t=this.promo;t||(t=this.promo=this.create()),t&&t.show()},i.prototype.disable=function(){},i.from_variants=function(t){if(0==t.length)return null;var e=Math.floor(Math.random()*t.length),n=t[e],r=n.text,o=n.link,s=n.image,a=n.id;return new i(a,r,o,s)}},{}]},{},[10]); \ No newline at end of file