Page MenuHomeSoftware Heritage

webapp-utils.js
No OneTemporary

webapp-utils.js

/**
* Copyright (C) 2018-2021 The Software Heritage developers
* See the AUTHORS file at the top-level directory of this distribution
* License: GNU Affero General Public License version 3, or any later version
* See top-level LICENSE file for more information
*/
import objectFitImages from 'object-fit-images';
import {selectText} from 'utils/functions';
import {BREAKPOINT_MD} from 'utils/constants';
let collapseSidebar = false;
const previousSidebarState = localStorage.getItem('remember.lte.pushmenu');
if (previousSidebarState !== undefined) {
collapseSidebar = previousSidebarState === 'sidebar-collapse';
}
$(document).on('DOMContentLoaded', () => {
// set state to collapsed on smaller devices
if ($(window).width() < BREAKPOINT_MD) {
collapseSidebar = true;
}
// restore previous sidebar state (collapsed/expanded)
if (collapseSidebar) {
// hack to avoid animated transition for collapsing sidebar
// when loading a page
const sidebarTransition = $('.main-sidebar, .main-sidebar:before').css('transition');
const sidebarEltsTransition = $('.sidebar .nav-link p, .main-sidebar .brand-text, .sidebar .user-panel .info').css('transition');
$('.main-sidebar, .main-sidebar:before').css('transition', 'none');
$('.sidebar .nav-link p, .main-sidebar .brand-text, .sidebar .user-panel .info').css('transition', 'none');
$('body').addClass('sidebar-collapse');
$('.swh-words-logo-swh').css('visibility', 'visible');
// restore transitions for user navigation
setTimeout(() => {
$('.main-sidebar, .main-sidebar:before').css('transition', sidebarTransition);
$('.sidebar .nav-link p, .main-sidebar .brand-text, .sidebar .user-panel .info').css('transition', sidebarEltsTransition);
});
}
});
$(document).on('collapsed.lte.pushmenu', event => {
if ($('body').width() >= BREAKPOINT_MD) {
$('.swh-words-logo-swh').css('visibility', 'visible');
}
});
$(document).on('shown.lte.pushmenu', event => {
$('.swh-words-logo-swh').css('visibility', 'hidden');
});
function ensureNoFooterOverflow() {
$('body').css('padding-bottom', $('footer').outerHeight() + 'px');
}
$(document).ready(() => {
// redirect to last browse page if any when clicking on the 'Browse' entry
// in the sidebar
$(`.swh-browse-link`).click(event => {
const lastBrowsePage = sessionStorage.getItem('last-browse-page');
if (lastBrowsePage) {
event.preventDefault();
window.location = lastBrowsePage;
}
});
const mainSideBar = $('.main-sidebar');
function updateSidebarState() {
const body = $('body');
if (body.hasClass('sidebar-collapse') &&
!mainSideBar.hasClass('swh-sidebar-collapsed')) {
mainSideBar.removeClass('swh-sidebar-expanded');
mainSideBar.addClass('swh-sidebar-collapsed');
$('.swh-words-logo-swh').css('visibility', 'visible');
} else if (!body.hasClass('sidebar-collapse') &&
!mainSideBar.hasClass('swh-sidebar-expanded')) {
mainSideBar.removeClass('swh-sidebar-collapsed');
mainSideBar.addClass('swh-sidebar-expanded');
$('.swh-words-logo-swh').css('visibility', 'hidden');
}
// ensure correct sidebar state when loading a page
if (body.hasClass('hold-transition')) {
setTimeout(() => {
updateSidebarState();
});
}
}
// set sidebar state after collapse / expand animation
mainSideBar.on('transitionend', evt => {
updateSidebarState();
});
updateSidebarState();
// ensure footer do not overflow main content for mobile devices
// or after resizing the browser window
ensureNoFooterOverflow();
$(window).resize(function() {
ensureNoFooterOverflow();
if ($('body').hasClass('sidebar-collapse') && $('body').width() >= BREAKPOINT_MD) {
$('.swh-words-logo-swh').css('visibility', 'visible');
}
});
// activate css polyfill 'object-fit: contain' in old browsers
objectFitImages();
// reparent the modals to the top navigation div in order to be able
// to display them
$('.swh-browse-top-navigation').append($('.modal'));
let selectedCode = null;
function getCodeOrPreEltUnderPointer(e) {
const elts = document.elementsFromPoint(e.clientX, e.clientY);
for (const elt of elts) {
if (elt.nodeName === 'CODE' || elt.nodeName === 'PRE') {
return elt;
}
}
return null;
}
// click handler to set focus on code block for copy
$(document).click(e => {
selectedCode = getCodeOrPreEltUnderPointer(e);
});
function selectCode(event, selectedCode) {
if (selectedCode) {
const hljsLnCodeElts = $(selectedCode).find('.hljs-ln-code');
if (hljsLnCodeElts.length) {
selectText(hljsLnCodeElts[0], hljsLnCodeElts[hljsLnCodeElts.length - 1]);
} else {
selectText(selectedCode.firstChild, selectedCode.lastChild);
}
event.preventDefault();
}
}
// select the whole text of focused code block when user
// double clicks or hits Ctrl+A
$(document).dblclick(e => {
if ((e.ctrlKey || e.metaKey)) {
selectCode(e, getCodeOrPreEltUnderPointer(e));
}
});
$(document).keydown(e => {
if ((e.ctrlKey || e.metaKey) && e.key === 'a') {
selectCode(e, selectedCode);
}
});
// show/hide back-to-top button
let scrollThreshold = 0;
scrollThreshold += $('.swh-top-bar').height() || 0;
scrollThreshold += $('.navbar').height() || 0;
$(window).scroll(() => {
if ($(window).scrollTop() > scrollThreshold) {
$('#back-to-top').css('display', 'block');
} else {
$('#back-to-top').css('display', 'none');
}
});
// navbar search form submission callback
$('#swh-origins-search-top').submit(event => {
event.preventDefault();
if (event.target.checkValidity()) {
$(event.target).removeClass('was-validated');
const searchQueryText = $('#swh-origins-search-top-input').val().trim();
const queryParameters = new URLSearchParams();
queryParameters.append('q', searchQueryText);
queryParameters.append('with_visit', true);
queryParameters.append('with_content', true);
window.location = `${Urls.browse_search()}?${queryParameters.toString()}`;
} else {
$(event.target).addClass('was-validated');
}
});
});
export function initPage(page) {
$(document).ready(() => {
// set relevant sidebar link to page active
$(`.swh-${page}-item`).addClass('active');
$(`.swh-${page}-link`).addClass('active');
// triggered when unloading the current page
$(window).on('unload', () => {
// backup current browse page
if (page === 'browse') {
sessionStorage.setItem('last-browse-page', window.location);
}
});
});
}
export function initHomePage() {
$(document).ready(async() => {
$('.swh-coverage-list').iFrameResize({heightCalculationMethod: 'taggedElement'});
const response = await fetch(Urls.stat_counters());
const data = await response.json();
if (data.stat_counters && !$.isEmptyObject(data.stat_counters)) {
for (const objectType of ['content', 'revision', 'origin', 'directory', 'person', 'release']) {
const count = data.stat_counters[objectType];
if (count !== undefined) {
$(`#swh-${objectType}-count`).html(count.toLocaleString());
} else {
$(`#swh-${objectType}-count`).closest('.swh-counter-container').hide();
}
}
} else {
$('.swh-counter').html('0');
}
if (data.stat_counters_history && !$.isEmptyObject(data.stat_counters_history)) {
for (const objectType of ['content', 'revision', 'origin']) {
const history = data.stat_counters_history[objectType];
if (history) {
swh.webapp.drawHistoryCounterGraph(`#swh-${objectType}-count-history`, history);
} else {
$(`#swh-${objectType}-count-history`).hide();
}
}
} else {
$('.swh-counter-history').hide();
}
});
initPage('home');
}
export function showModalMessage(title, message) {
$('#swh-web-modal-message .modal-title').text(title);
$('#swh-web-modal-message .modal-content p').text(message);
$('#swh-web-modal-message').modal('show');
}
export function showModalConfirm(title, message, callback) {
$('#swh-web-modal-confirm .modal-title').text(title);
$('#swh-web-modal-confirm .modal-content p').text(message);
$('#swh-web-modal-confirm #swh-web-modal-confirm-ok-btn').bind('click', () => {
callback();
$('#swh-web-modal-confirm').modal('hide');
$('#swh-web-modal-confirm #swh-web-modal-confirm-ok-btn').unbind('click');
});
$('#swh-web-modal-confirm').modal('show');
}
export function showModalHtml(title, html, width = '500px') {
$('#swh-web-modal-html .modal-title').text(title);
$('#swh-web-modal-html .modal-body').html(html);
$('#swh-web-modal-html .modal-dialog').css('max-width', width);
$('#swh-web-modal-html .modal-dialog').css('width', width);
$('#swh-web-modal-html').modal('show');
}
export function addJumpToPagePopoverToDataTable(dataTableElt) {
dataTableElt.on('draw.dt', function() {
$('.paginate_button.disabled').css('cursor', 'pointer');
$('.paginate_button.disabled').on('click', event => {
const pageInfo = dataTableElt.page.info();
let content = '<select class="jump-to-page">';
for (let i = 1; i <= pageInfo.pages; ++i) {
let selected = '';
if (i === pageInfo.page + 1) {
selected = 'selected';
}
content += `<option value="${i}" ${selected}>${i}</option>`;
}
content += `</select><span> / ${pageInfo.pages}</span>`;
$(event.target).popover({
'title': 'Jump to page',
'content': content,
'html': true,
'placement': 'top',
'sanitizeFn': swh.webapp.filterXSS
});
$(event.target).popover('show');
$('.jump-to-page').on('change', function() {
$('.paginate_button.disabled').popover('hide');
const pageNumber = parseInt($(this).val()) - 1;
dataTableElt.page(pageNumber).draw('page');
});
});
});
dataTableElt.on('preXhr.dt', () => {
$('.paginate_button.disabled').popover('hide');
});
}
let swhObjectIcons;
export function setSwhObjectIcons(icons) {
swhObjectIcons = icons;
}
export function getSwhObjectIcon(swhObjectType) {
return swhObjectIcons[swhObjectType];
}
let browsedSwhObjectMetadata = {};
export function setBrowsedSwhObjectMetadata(metadata) {
browsedSwhObjectMetadata = metadata;
}
export function getBrowsedSwhObjectMetadata() {
return browsedSwhObjectMetadata;
}
// This will contain a mapping between an archived object type
// and its related SWHID metadata for each object reachable from
// the current browse view.
// SWHID metadata contain the following keys:
// * object_type: type of archived object
// * object_id: sha1 object identifier
// * swhid: SWHID without contextual info
// * swhid_url: URL to resolve SWHID without contextual info
// * context: object describing SWHID context
// * swhid_with_context: SWHID with contextual info
// * swhid_with_context_url: URL to resolve SWHID with contextual info
let swhidsContext_ = {};
export function setSwhIdsContext(swhidsContext) {
swhidsContext_ = {};
for (const swhidContext of swhidsContext) {
swhidsContext_[swhidContext.object_type] = swhidContext;
}
}
export function getSwhIdsContext() {
return swhidsContext_;
}
function setFullWidth(fullWidth) {
if (fullWidth) {
$('#swh-web-content').removeClass('container');
$('#swh-web-content').addClass('container-fluid');
} else {
$('#swh-web-content').removeClass('container-fluid');
$('#swh-web-content').addClass('container');
}
localStorage.setItem('swh-web-full-width', JSON.stringify(fullWidth));
$('#swh-full-width-switch').prop('checked', fullWidth);
}
export function fullWidthToggled(event) {
setFullWidth($(event.target).prop('checked'));
}
export function setContainerFullWidth() {
const previousFullWidthState = JSON.parse(localStorage.getItem('swh-web-full-width'));
if (previousFullWidthState !== null) {
setFullWidth(previousFullWidthState);
}
}
function coreSWHIDIsLowerCase(swhid) {
const qualifiersPos = swhid.indexOf(';');
let coreSWHID = swhid;
if (qualifiersPos !== -1) {
coreSWHID = swhid.slice(0, qualifiersPos);
}
return coreSWHID.toLowerCase() === coreSWHID;
}
export async function validateSWHIDInput(swhidInputElt) {
const swhidInput = swhidInputElt.value.trim();
let customValidity = '';
if (swhidInput.toLowerCase().startsWith('swh:')) {
if (coreSWHIDIsLowerCase(swhidInput)) {
const resolveSWHIDUrl = Urls.api_1_resolve_swhid(swhidInput);
const response = await fetch(resolveSWHIDUrl);
const responseData = await response.json();
if (responseData.hasOwnProperty('exception')) {
customValidity = responseData.reason;
}
} else {
const qualifiersPos = swhidInput.indexOf(';');
if (qualifiersPos === -1) {
customValidity = 'Invalid SWHID: all characters must be in lowercase. ';
customValidity += `Valid SWHID is ${swhidInput.toLowerCase()}`;
} else {
customValidity = 'Invalid SWHID: the core part must be in lowercase. ';
const coreSWHID = swhidInput.slice(0, qualifiersPos);
customValidity += `Valid SWHID is ${swhidInput.replace(coreSWHID, coreSWHID.toLowerCase())}`;
}
}
}
swhidInputElt.setCustomValidity(customValidity);
$(swhidInputElt).siblings('.invalid-feedback').text(customValidity);
}
export function isUserLoggedIn() {
return JSON.parse($('#swh_user_logged_in').text());
}

File Metadata

Mime Type
text/x-java
Expires
Jun 4 2025, 7:41 PM (10 w, 4 d ago)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
3399326

Event Timeline