diff --git a/sphinx_search/static/js/rtd_sphinx_search.js b/sphinx_search/static/js/rtd_sphinx_search.js index 65d68ff..6097ab6 100644 --- a/sphinx_search/static/js/rtd_sphinx_search.js +++ b/sphinx_search/static/js/rtd_sphinx_search.js @@ -6,6 +6,38 @@ const FETCH_RESULTS_DELAY = 250; const CLEAR_RESULTS_DELAY = 300; const RTD_SEARCH_PARAMETER = "rtd_search"; + +/** + * Mark a string as safe to be used as HTML in setNodeContent. + */ +function SafeHtmlString(value) { + this.value = value; + this.isSafe = true; +} + +/** + * Create a SafeHtmlString instance from a string. + * + * @param {String} value + */ +function markAsSafe(value) { + return new SafeHtmlString(value); +} + +/** + * Set the content of an element as text or HTML. + * + * @param {Element} element + * @param {String|SafeHtmlString} content + */ +function setElementContent(element, content) { + if (content.isSafe) { + element.innerHTML = content.value; + } else { + element.innerText = content; + } +} + /** * Debounce the function. * Usage:: @@ -68,14 +100,14 @@ const debounce = (func, wait) => { */ const buildSection = function (id, title, link, contents) { let span_element = createDomNode("span", {class: "search__result__subheading"}); - span_element.innerHTML = title; + setElementContent(span_element, title) let div_element = createDomNode("div", {class: "outer_div_page_results", id: id}); div_element.appendChild(span_element); for (var i = 0; i < contents.length; i += 1) { let p_element = createDomNode("p", {class: "search__result__content"}); - p_element.innerHTML = contents[i]; + setElementContent(p_element, contents[i]); div_element.appendChild(p_element); } @@ -168,7 +200,7 @@ const get_section_html = (sectionData, page_link, id) => { let section_subheading = sectionData.title; let highlights = sectionData.highlights; if (highlights.title.length) { - section_subheading = highlights.title[0]; + section_subheading = markAsSafe(highlights.title[0]); } let section_content = [ @@ -183,7 +215,7 @@ const get_section_html = (sectionData, page_link, id) => { j < highlight_content.length && j < MAX_SECTION_RESULTS; ++j ) { - section_content.push("... " + highlight_content[j] + " ..."); + section_content.push(markAsSafe("... " + highlight_content[j] + " ...")); } } @@ -192,43 +224,6 @@ const get_section_html = (sectionData, page_link, id) => { return buildSection(section_id, section_subheading, section_link, section_content); }; -/** - * Generate and return html structure - * for a sphinx domain result. - * - * @param {Object} domainData object containing the result data - * @param {String} page_link link of the main page. It is used to construct the section link - * @param {Number} id to be used in for this section - */ -const get_domain_html = (domainData, page_link, id) => { - let domain_link = `${page_link}#${domainData.id}`; - let domain_role_name = domainData.role; - let domain_name = domainData.name; - let domain_content = - domainData.content.substr(0, MAX_SUBSTRING_LIMIT) + " ..."; - - let highlights = domainData.highlights; - if (highlights.name.length) { - domain_name = highlights.name[0]; - } - if (highlights.content.length) { - domain_content = highlights.content[0]; - } - - let domain_id = "hit__" + id; - - let div_role_name = createDomNode("div", {class: "search__domain_role_name"}); - div_role_name.innerText = `[${domain_role_name}]`; - domain_name += div_role_name.outerHTML; - - return buildSection( - domain_id, - domain_name, - domain_link, - [domain_content] - ); -}; - /** * Generate search results for a single page. @@ -265,11 +260,11 @@ const generateSingleResult = (resultData, projectName, id) => { let highlights = resultData.highlights; if (highlights.title.length) { - page_title = highlights.title[0]; + page_title = markAsSafe(highlights.title[0]); } let h2_element = createDomNode("h2", {class: "search__result__title"}); - h2_element.innerHTML = page_title; + setElementContent(h2_element, page_title); // Results can belong to different projects. // If the result isn't from the current project, add a note about it. @@ -301,12 +296,6 @@ const generateSingleResult = (resultData, projectName, id) => { page_link, id, ); - } else if (block.type === "domain") { - section = get_domain_html( - block, - page_link, - id, - ); } if (section !== null) { @@ -479,7 +468,7 @@ const getErrorDiv = err_msg => { let err_div = createDomNode("div", { class: "search__result__box search__error__box" }); - err_div.innerHTML = err_msg; + err_div.innerText = err_msg; return err_div; }; diff --git a/sphinx_search/static/js/rtd_sphinx_search.min.js b/sphinx_search/static/js/rtd_sphinx_search.min.js index ee0b300..9bb6a07 100644 --- a/sphinx_search/static/js/rtd_sphinx_search.min.js +++ b/sphinx_search/static/js/rtd_sphinx_search.min.js @@ -1 +1 @@ -"use strict";function _createForOfIteratorHelper(e,t){var r;if("undefined"==typeof Symbol||null==e[Symbol.iterator]){if(Array.isArray(e)||(r=_unsupportedIterableToArray(e))||t&&e&&"number"==typeof e.length){r&&(e=r);var n=0,t=function(){};return{s:t,n:function(){return n>=e.length?{done:!0}:{done:!1,value:e[n++]}},e:function(e){throw e},f:t}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,o=!0,l=!1;return{s:function(){r=e[Symbol.iterator]()},n:function(){var e=r.next();return o=e.done,e},e:function(e){l=!0,a=e},f:function(){try{o||null==r.return||r.return()}finally{if(l)throw a}}}}function _slicedToArray(e,t){return _arrayWithHoles(e)||_iterableToArrayLimit(e,t)||_unsupportedIterableToArray(e,t)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(e,t){if(e){if("string"==typeof e)return _arrayLikeToArray(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Map"===(r="Object"===r&&e.constructor?e.constructor.name:r)||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?_arrayLikeToArray(e,t):void 0}}function _arrayLikeToArray(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);rSearching ....",a.appendChild(e);return debounce(function(){updateUrl(),updateSearchBar();var e=t+"?"+new URLSearchParams(r).toString();fetch(e,{method:"GET"}).then(function(e){if(!e.ok)throw new Error;return e.json()}).then(function(e){var t;0=e.length?{done:!0}:{done:!1,value:e[n++]}},e:function(e){throw e},f:t}}throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}var a,o=!0,l=!1;return{s:function(){r=e[Symbol.iterator]()},n:function(){var e=r.next();return o=e.done,e},e:function(e){l=!0,a=e},f:function(){try{o||null==r.return||r.return()}finally{if(l)throw a}}}}function _slicedToArray(e,t){return _arrayWithHoles(e)||_iterableToArrayLimit(e,t)||_unsupportedIterableToArray(e,t)||_nonIterableRest()}function _nonIterableRest(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")}function _unsupportedIterableToArray(e,t){if(e){if("string"==typeof e)return _arrayLikeToArray(e,t);var r=Object.prototype.toString.call(e).slice(8,-1);return"Map"===(r="Object"===r&&e.constructor?e.constructor.name:r)||"Set"===r?Array.from(e):"Arguments"===r||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(r)?_arrayLikeToArray(e,t):void 0}}function _arrayLikeToArray(e,t){(null==t||t>e.length)&&(t=e.length);for(var r=0,n=new Array(t);rSearching ....",a.appendChild(e);return debounce(function(){updateUrl(),updateSearchBar();var e=t+"?"+new URLSearchParams(r).toString();fetch(e,{method:"GET"}).then(function(e){if(!e.ok)throw new Error;return e.json()}).then(function(e){var t;0