Skip to content
Draft
Show file tree
Hide file tree
Changes from all 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
10 changes: 9 additions & 1 deletion .eslintrc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,12 @@ globals:
ENV: readonly
ignorePatterns:
- esbuild.mjs
rules: {}
rules:
no-undef: "warn"
"@typescript-eslint/no-unused-vars":
- "warn"
- {
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_"
}
9 changes: 0 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 1 addition & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,7 @@
"url": "https://github.com/atomicjolt/atomic-search-widget"
},
"keywords": [],
"dependencies": {
"jquery": "^3.6.0"
},
"dependencies": {},
"devDependencies": {
"@aws-sdk/client-s3": "^3.470.0",
"@typescript-eslint/eslint-plugin": "8.25.0",
Expand Down
115 changes: 68 additions & 47 deletions src/canvas/app.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import $ from 'jquery';
import './desktop_widget';
import './mobile_widget';
import { SEARCH_EVENT, EQUELLA_SEARCH } from './widget_common';
Expand All @@ -9,6 +8,7 @@ import {
receiveQueryVariables,
sendQueryVariables,
} from './query_params';
import { htmlToElement } from '../common/html';

let APP_IFRAME;

Expand Down Expand Up @@ -73,15 +73,20 @@ function allModuleProgress(courseIds, cb) {
const promises = courseIds.map(
(id) =>
new Promise((resolve) => {
$.ajax({
url: `/courses/${id}/modules/progressions.json?user_id=${ENV.current_user_id}`,
dataType: 'text',
})
.done((data) => {
fetch(
`/courses/${id}/modules/progressions.json?user_id=${ENV.current_user_id}`,
)
.then((response) => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.text();
})
.then((data) => {
const json = JSON.parse(data.replace(/^while\(1\);/, ''));
resolve({ [id]: json });
})
.fail(() => {
.catch(() => {
// sometimes they will get 401's from this call. proceed with modules we
// did manage to load, otherwise they will be stuck waiting
resolve({});
Expand Down Expand Up @@ -157,7 +162,7 @@ function ajHandleComm(event) {
default:
break;
}
} catch (error) {
} catch (_error) {
// Ignore errors
}
}
Expand Down Expand Up @@ -205,6 +210,10 @@ const SEARCH_WORDS = [
'Tüm',
];

function elementMatchesSearchWord(el) {
return SEARCH_WORDS.some((word) => el.textContent.trim() === word)
}

function getToolUrl() {
if (atomicSearchConfig.accountId && atomicSearchConfig.externalToolId) {
const toolPath = `external_tools/${atomicSearchConfig.externalToolId}`;
Expand All @@ -217,32 +226,40 @@ function getToolUrl() {
return `/accounts/${atomicSearchConfig.accountId}/${toolPath}?launch_type=global_navigation`;
}

for (let i = 0; i < SEARCH_WORDS.length; i++) {
const word = SEARCH_WORDS[i];
const baseSelector = `a:contains("${word}")`;
// this could be within a course or subaccount
const localNavElement = $(`#section-tabs ${baseSelector}`);
const globalNavElement = $(`#menu ${baseSelector}`);

if (
localNavElement.attr('href') &&
localNavElement.attr('href').match(EXTERNAL_TOOL_REGEX) &&
localNavElement[0].text.trim() === word
) {
return localNavElement.attr('href');
}
if (
globalNavElement.attr('href') &&
globalNavElement.find('.menu-item__text').text().trim() === word
) {
const toolPath = globalNavElement.attr('href').match(EXTERNAL_TOOL_REGEX);
const contextMatch = window.location.pathname.match(PATH_REGEX);
if (contextMatch && toolPath) {
return `${contextMatch[0]}${toolPath[0]}`;
}
// local nav could be within a course or subaccount
const localNavLinks = Array.from(
document.querySelectorAll('#section-tabs a[href*="/external_tools"]'),
);
const localNavElement = localNavLinks.find(
(link) =>
link.href.match(EXTERNAL_TOOL_REGEX) &&
elementMatchesSearchWord(link)
);

if (localNavElement) {
return localNavElement.href;
}

return globalNavElement.attr('href');
const globalNavLinks = Array.from(
document.querySelectorAll(`#menu a[href*="/external_tools"]`),
);
const globalNavElement = globalNavLinks.find((link) => {
const textEl = link.querySelector('.menu-item__text');
return (
textEl &&
elementMatchesSearchWord(textEl) &&
link.href.match(EXTERNAL_TOOL_REGEX)
);
});

if (globalNavElement) {
const toolPath = globalNavElement.href.match(EXTERNAL_TOOL_REGEX);
const contextMatch = window.location.pathname.match(PATH_REGEX);
if (contextMatch && toolPath) {
return `${contextMatch[0]}${toolPath[0]}`;
}

return globalNavElement.href;
}

return null;
Expand All @@ -252,36 +269,39 @@ const BIG_WIDGET_ID = 'ajas-search-widget';

function addBigWidget(placeholder) {
function buildHTML(cssClass) {
return `
const htmlText = `
<atomic-search-desktop-widget
id="${BIG_WIDGET_ID}"
data-css-class="${cssClass}"
data-placeholder="${placeholder}"
></atomic-search-widget>
`;
return htmlToElement(htmlText);
}

const path = window.location.pathname;
let node;

if (path === '/') {
// Dashboard page.
const html = buildHTML('ajas-search-widget--dashboard');
node = $(html).prependTo('.ic-Dashboard-header__actions');
node = buildHTML('ajas-search-widget--dashboard');

document.querySelector('.ic-Dashboard-header__actions').appendChild(node);
} else if (path.match(/^\/courses\/?$/i)) {
// All courses page.
const html = buildHTML('ajas-search-widget--all-courses');
node = $(html).insertAfter('.header-bar');
node = buildHTML('ajas-search-widget--all-courses');

document.querySelector('.header-bar').after(node);
} else if (path.match(/^\/courses\/[\d]+\/files\/?$/i)) {
// Course files page. Not individual file pages though.
// NOTE This one is not working at the moment. It seems that the parent node
// is removed, and the mutation observer never fires
const html = buildHTML('ajas-search-widget--files');
node = $(html).insertAfter('.ic-app-crumbs');
node = buildHTML('ajas-search-widget--files');
document.querySelector('.ic-app-crumbs').after(node);
} else {
// Any course page.
const html = buildHTML('ajas-search-widget--files');
node = $(html).appendTo('.right-of-crumbs');
node = buildHTML('ajas-search-widget--files');
node = document.querySelector('.right-of-crumbs').appendChild(node);
}

return [node, BIG_WIDGET_ID];
Expand All @@ -290,14 +310,15 @@ function addBigWidget(placeholder) {
const SMALL_WIDGET_ID = 'ajas-search-widget-mobile';

function addSmallWidget(placeholder) {
const html = `
const node = htmlToElement(`
<atomic-search-mobile-widget
id="${SMALL_WIDGET_ID}"
data-placeholder="${placeholder}"
></atomic-search-widget>
`;
`);


const node = $(html).insertAfter('.mobile-header-title');
document.querySelector('.mobile-header-title').after(node);
node.parent().css('position', 'relative');

return [node, SMALL_WIDGET_ID];
Expand Down Expand Up @@ -335,14 +356,14 @@ function addWidget(addToDOM, attemptNumber) {
}

const [widget, id] = addToDOM(placeholder);
if (widget.length === 0) {
if (!widget) {
// not incrementing attemptNumber here because repeating this isn't too
// bad
setTimeout(() => addWidget(addToDOM, attemptNumber), 50);
return;
}

widget[0].addEventListener(SEARCH_EVENT, (e) => {
widget.addEventListener(SEARCH_EVENT, (e) => {
const { searchText, searchType } = e.detail;
if (APP_IFRAME) {
const query = getQuery();
Expand Down Expand Up @@ -387,7 +408,7 @@ function addWidget(addToDOM, attemptNumber) {
}
});

observer.observe(widget.parent()[0], { childList: true });
observer.observe(widget.parentElement, { childList: true });
}

// an instance of the script is already running
Expand Down