Skip to content

Embedded js: remove more dependency on jquery #9515

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
Aug 24, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion common
56 changes: 24 additions & 32 deletions readthedocs/core/static-src/core/js/doc-embed/footer.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,39 +12,29 @@ function injectFooter(data) {
// * All other pages just get it appended to the <body>

var config = rtddata.get();
var placement = $(EXPLICIT_FLYOUT_PLACEMENT_SELECTOR);
if (placement.length > 0) {
placement.html(data['html']);
let placement = document.querySelector(EXPLICIT_FLYOUT_PLACEMENT_SELECTOR);
if (placement !== null) {
placement.innerHTML = data['html'];
}
else if (config.is_sphinx_builder() && config.is_rtd_like_theme()) {
$("div.rst-other-versions").html(data['html']);
let placement = document.querySelector('div.rst-other-versions');
if (placement !== null) {
placement.innerHTML = data['html'];
}
} else {
$("body").append(data['html']);
document.body.insertAdjacentHTML('beforeend', data['html']);
}

if (!data['version_active']) {
$('.rst-current-version').addClass('rst-out-of-date');
for (let element of document.getElementsByClassName('rst-current-version')) {
element.classList.add('rst-out-of-date');
}
} else if (!data['version_supported']) {
//$('.rst-current-version').addClass('rst-active-old-version')
}
}


function setupBookmarkCSRFToken() {
function csrfSafeMethod(method) {
// these HTTP methods do not require CSRF protection
return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
}

$.ajaxSetup({
beforeSend: function (xhr, settings) {
if (!csrfSafeMethod(settings.type)) {
xhr.setRequestHeader("X-CSRFToken", $('a.bookmark[token]').attr('token'));
}
}
});
}

function init() {
var rtd = rtddata.get();

Expand Down Expand Up @@ -86,25 +76,27 @@ function init() {
versionCompare.init(data.version_compare);
}
injectFooter(data);
setupBookmarkCSRFToken();
},
error: function () {
console.error('Error loading Read the Docs footer');
}
});

// Register page view.
$.ajax({
url: rtd.proxied_api_host + "/api/v2/analytics/",
data: {
project: rtd['project'],
version: rtd['version'],
absolute_uri: window.location.href,
},
cache: false,
error: function () {
console.error('Error registering page view');
let data = {
project: rtd['project'],
version: rtd['version'],
absolute_uri: window.location.href,
};
let url = rtd.proxied_api_host + '/api/v2/analytics/?' + new URLSearchParams(data).toString();
fetch(url, {method: 'GET', cache: 'no-store'})
.then(response => {
if (!response.ok) {
throw new Error();
}
})
.catch(error => {
console.error('Error registering page view');
});
}

Expand Down
176 changes: 92 additions & 84 deletions readthedocs/core/static-src/core/js/doc-embed/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,11 @@
* Sphinx and Mkdocs search overrides
*/

var rtddata = require('./rtd-data');
var xss = require('xss/lib/index');
var MAX_RESULT_PER_SECTION = 3;
var MAX_SUBSTRING_LIMIT = 100;

const rtddata = require('./rtd-data');
const xss = require('xss/lib/index');
const { createDomNode } = require("./utils");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need to specify that we're using this function from utils, or is the compiler smart enough to know what is happening if we add additional utils functions?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The compile step will resolve the functions in utils.js for use here, yeah. This syntax will only import createDomNode from utils.js. If more functions are added to utils.js, they won't automatically be imported here, but could be with const { createDomNode, someOtherUtil } = ..

const MAX_RESULT_PER_SECTION = 3;
const MAX_SUBSTRING_LIMIT = 100;

/*
* Search query override for hitting our local API instead of the standard
Expand Down Expand Up @@ -58,19 +58,19 @@ function attach_elastic_search_query_sphinx(data) {
* @param {String} link.
* @param {Array} contents.
*/
var buildSection = function (title, link, contents) {
const buildSection = function (title, link, contents) {
var div_title = document.createElement("div");
var a_element = document.createElement("a");
a_element.href = link;
a_element.innerHTML = title;
div_title.appendChild(a_element);
html = div_title.outerHTML;
for (var i = 0; i < contents.length; i += 1) {
var div_content = document.createElement("div");
div_content.innerHTML = contents[i];
html += div_content.outerHTML;
let elements = [div_title];
for (let content of contents) {
let div_content = document.createElement("div");
div_content.innerHTML = content;
elements.push(div_content);
}
return html;
return elements;
};

search_def
Expand All @@ -81,7 +81,7 @@ function attach_elastic_search_query_sphinx(data) {
for (var i = 0; i < results.length; i += 1) {
var result = results[i];
var blocks = result.blocks;
var list_item = $('<li>');
let list_item = createDomNode('li');

var title = result.title;
// if highlighted title is present, use that.
Expand All @@ -91,23 +91,24 @@ function attach_elastic_search_query_sphinx(data) {

var link = result.path + "?highlight=" + encodeURIComponent(query);

var item = $('<a>', {'href': link});

item.html(title);
item.find('span').addClass('highlighted');
list_item.append(item);
let item = createDomNode('a', {href: link});
item.innerHTML = title;
for (let element of item.getElementsByTagName('span')) {
element.className = 'highlighted';
}
list_item.appendChild(item);

// If the document is from a subproject, add extra information
if (result.project !== project) {
var text = " (from project " + result.project_alias + ")";
var extra = $('<span>', {'text': text});
list_item.append(extra);
let extra = createDomNode('span');
extra.innerText = " (from project " + result.project_alias + ")";
list_item.appendChild(extra);
}

for (var block_index = 0; block_index < blocks.length; block_index += 1) {
var current_block = blocks[block_index];

var contents = $('<div class="context">');
let contents = createDomNode('div', {class: 'context'});

// if the result is page section
if (current_block.type === "section") {
Expand All @@ -131,12 +132,12 @@ function attach_elastic_search_query_sphinx(data) {
section_content.push("... " + xss(content[k]) + " ...");
}
}

contents.append(buildSection(
let sections = buildSection(
section_subtitle,
section_subtitle_link,
section_content
));
);
sections.forEach(element => { contents.appendChild(element); });
}

// if the result is a sphinx domain object
Expand All @@ -161,27 +162,30 @@ function attach_elastic_search_query_sphinx(data) {

var domain_subtitle = "[" + domain_role_name + "]: " + domain_name;

contents.append(buildSection(
let sections = buildSection(
domain_subtitle,
domain_subtitle_link,
[domain_content]
));
);
sections.forEach(element => { contents.appendChild(element); });
}

contents.find('span').addClass('highlighted');
list_item.append(contents);
for (let element of contents.getElementsByTagName('span')) {
element.className = 'highlighted';
}
list_item.appendChild(contents);

// Create some spacing between the results.
// Also, don't add this spacing in the last hit.
if (block_index < blocks.length - 1) {
list_item.append($("<div class='rtd_search_hits_spacing'></div>"));
list_item.appendChild(createDomNode('div', {class: 'rtd_search_hits_spacing'}));
}
}

if (Search.output.jquery) {
Search.output.append(list_item);
Search.output.append($(list_item));
} else {
Search.output.appendChild(list_item.get(0));
Search.output.appendChild(list_item);
}
}
setText(
Expand All @@ -198,30 +202,30 @@ function attach_elastic_search_query_sphinx(data) {
Search.query_fallback(query);
})
.always(function () {
$('#search-progress').empty();
let progress = document.getElementById('search-progress');
if (progress !== null) {
progress.replaceChildren();
}
Search.stopPulse();
setText(Search.title, _('Search Results'));
});

$.ajax({
url: search_url.href,
crossDomain: true,
xhrFields: {
withCredentials: true,
},
complete: function (resp, status_code) {
if (
status_code !== 'success' ||
typeof (resp.responseJSON) === 'undefined' ||
resp.responseJSON.count === 0
) {
return search_def.reject();
}
return search_def.resolve(resp.responseJSON);
fetch(search_url.href, {method: 'GET'})
.then(response => {
if (!response.ok) {
throw new Error();
}
return response.json();
})
.fail(function (resp, status_code, error) {
return search_def.reject();
.then(data => {
if (data.results.length > 0) {
search_def.resolve(data);
} else {
search_def.reject();
}
})
.catch(error => {
search_def.reject();
});
};

Expand Down Expand Up @@ -275,23 +279,27 @@ function attach_elastic_search_query_mkdocs(data) {
var results = data.results || [];

if (results.length) {
var searchResults = $('#mkdocs-search-results');
searchResults.empty();
let searchResults = document.getElementById('mkdocs-search-results');
if (searchResults != null) {
searchResults.replaceChildren();
}

for (var i = 0; i < results.length; i += 1) {
var result = results[i];
var blocks = result.blocks;

var link = result.path;

var item = $('<article>');
item.append(
$('<h3>').append($('<a>', {'href': link, 'text': result.title}))
);
let item = createDomNode('article');
let a_element = createDomNode('a', {href: link});
a_element.innerText = result.title;
let title_element = createDomNode('h3');
title_element.appendChild(a_element);
item.appendChild(title_element);

if (result.project !== project) {
var text = '(from project ' + result.project_alias + ')';
item.append($('<span>', {'text': text}));
let text = '(from project ' + result.project_alias + ')';
item.appendChild(createDomNode('span', {'text': text}));
}

for (var j = 0; j < blocks.length; j += 1) {
Expand Down Expand Up @@ -325,20 +333,23 @@ function attach_elastic_search_query_mkdocs(data) {
section_title = xss(section_title)
.replace(/<span>/g, '<mark>')
.replace(/<\/span>/g, '</mark>');
item.append(
$('<h4>')
.append($('<a>', {'href': section_link}).html(section_title))
);

let title_element = createDomNode('h4');
let a_element = createDomNode('a', {href: section_link});
a_element.innerHTML = section_title;
title_element.appendChild(a_element);
item.appendChild(title_element);

for (var m = 0; m < section_contents.length; m += 1) {
var content = xss(section_contents[m]);
let content = xss(section_contents[m]);
content = content
.replace(/<span>/g, '<mark>')
.replace(/<\/span>/g, '</mark>');
item.append(
$('<p>').html(content)
);
let p_element = createDomNode('p');
p_element.innerHTML = content;
item.appendChild(p_element);
}
searchResults.append(item);
searchResults.appendChild(item);
}
}
}
Expand All @@ -352,25 +363,22 @@ function attach_elastic_search_query_mkdocs(data) {
fallbackSearch();
});

$.ajax({
url: search_url.href,
crossDomain: true,
xhrFields: {
withCredentials: true,
},
complete: function (resp, status_code) {
if (
status_code !== 'success' ||
typeof (resp.responseJSON) === 'undefined' ||
resp.responseJSON.count === 0
) {
return search_def.reject();
}
return search_def.resolve(resp.responseJSON);
fetch(search_url.href, {method: 'GET'})
.then(response => {
if (!response.ok) {
throw new Error();
}
return response.json();
})
.then(data => {
if (data.results.length > 0) {
search_def.resolve(data);
} else {
search_def.reject();
}
})
.fail(function (resp, status_code, error) {
return search_def.reject();
.catch(error => {
search_def.reject();
});
};

Expand Down
Loading