import Clipboard from "clipboard/dist/clipboard.min";
import Code from "../services/code";
+import * as DOM from "../services/dom";
+import {scrollAndHighlightElement} from "../services/util";
class PageDisplay {
Code.highlight();
this.setupPointer();
- this.setupStickySidebar();
this.setupNavHighlighting();
// Check the hash on load
}
// Sidebar page nav click event
- $('.sidebar-page-nav').on('click', 'a', event => {
- this.goToText(event.target.getAttribute('href').substr(1));
- });
+ const sidebarPageNav = document.querySelector('.sidebar-page-nav');
+ if (sidebarPageNav) {
+ DOM.onChildEvent(sidebarPageNav, 'a', 'click', (event, child) => {
+ event.preventDefault();
+ window.components['tri-layout'][0].showContent();
+ const contentId = child.getAttribute('href').substr(1);
+ this.goToText(contentId);
+ window.history.pushState(null, null, '#' + contentId);
+ });
+ }
}
goToText(text) {
- let idElem = document.getElementById(text);
- $('.page-content [data-highlighted]').attr('data-highlighted', '').css('background-color', '');
+ const idElem = document.getElementById(text);
+
+ DOM.forEach('.page-content [data-highlighted]', elem => {
+ elem.removeAttribute('data-highlighted');
+ elem.style.backgroundColor = null;
+ });
+
if (idElem !== null) {
- window.scrollAndHighlight(idElem);
+ scrollAndHighlightElement(idElem);
} else {
- $('.page-content').find(':contains("' + text + '")').smoothScrollTo();
+ const textElem = DOM.findText('.page-content > div > *', text);
+ if (textElem) {
+ scrollAndHighlightElement(textElem);
+ }
}
}
setupPointer() {
- if (document.getElementById('pointer') === null) return;
+ let pointer = document.getElementById('pointer');
+ if (!pointer) {
+ return;
+ }
+
// Set up pointer
- let $pointer = $('#pointer').detach();
+ pointer = pointer.parentNode.removeChild(pointer);
+ const pointerInner = pointer.querySelector('div.pointer');
+
+ // Instance variables
let pointerShowing = false;
- let $pointerInner = $pointer.children('div.pointer').first();
let isSelection = false;
let pointerModeLink = true;
let pointerSectionId = '';
// Select all contents on input click
- $pointer.on('click', 'input', event => {
- $(this).select();
+ DOM.onChildEvent(pointer, 'input', 'click', (event, input) => {
+ input.select();
event.stopPropagation();
});
- $pointer.on('click focus', event => {
+ // Prevent closing pointer when clicked or focused
+ DOM.onEvents(pointer, ['click', 'focus'], event => {
event.stopPropagation();
});
// Pointer mode toggle
- $pointer.on('click', 'span.icon', event => {
+ DOM.onChildEvent(pointer, 'span.icon', 'click', (event, icon) => {
event.stopPropagation();
- let $icon = $(event.currentTarget);
pointerModeLink = !pointerModeLink;
- $icon.find('[data-icon="include"]').toggle(!pointerModeLink);
- $icon.find('[data-icon="link"]').toggle(pointerModeLink);
+ icon.querySelector('[data-icon="include"]').style.display = (!pointerModeLink) ? 'inline' : 'none';
+ icon.querySelector('[data-icon="link"]').style.display = (pointerModeLink) ? 'inline' : 'none';
updatePointerContent();
});
// Set up clipboard
- let clipboard = new Clipboard($pointer[0].querySelector('button'));
+ new Clipboard(pointer.querySelector('button'));
// Hide pointer when clicking away
- $(document.body).find('*').on('click focus', event => {
+ DOM.onEvents(document.body, ['click', 'focus'], event => {
if (!pointerShowing || isSelection) return;
- $pointer.detach();
+ pointer = pointer.parentElement.removeChild(pointer);
pointerShowing = false;
});
- let updatePointerContent = ($elem) => {
+ let updatePointerContent = (element) => {
let inputText = pointerModeLink ? window.baseUrl(`/link/${this.pageId}#${pointerSectionId}`) : `{{@${this.pageId}#${pointerSectionId}}}`;
- if (pointerModeLink && inputText.indexOf('http') !== 0) inputText = window.location.protocol + "//" + window.location.host + inputText;
+ if (pointerModeLink && !inputText.startsWith('http')) {
+ inputText = window.location.protocol + "//" + window.location.host + inputText;
+ }
- $pointer.find('input').val(inputText);
+ pointer.querySelector('input').value = inputText;
- // update anchor if present
- const $editAnchor = $pointer.find('#pointer-edit');
- if ($editAnchor.length !== 0 && $elem) {
- const editHref = $editAnchor.data('editHref');
- const element = $elem[0];
+ // Update anchor if present
+ const editAnchor = pointer.querySelector('#pointer-edit');
+ if (editAnchor && element) {
+ const editHref = editAnchor.dataset.editHref;
const elementId = element.id;
// get the first 50 characters.
- let queryContent = element.textContent && element.textContent.substring(0, 50);
- $editAnchor[0].href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`;
+ const queryContent = element.textContent && element.textContent.substring(0, 50);
+ editAnchor.href = `${editHref}?content-id=${elementId}&content-text=${encodeURIComponent(queryContent)}`;
}
};
// Show pointer when selecting a single block of tagged content
- $('.page-content [id^="bkmrk"]').on('mouseup keyup', function (e) {
- e.stopPropagation();
- let selection = window.getSelection();
- if (selection.toString().length === 0) return;
-
- // Show pointer and set link
- let $elem = $(this);
- pointerSectionId = $elem.attr('id');
- updatePointerContent($elem);
-
- $elem.before($pointer);
- $pointer.show();
- pointerShowing = true;
-
- // Set pointer to sit near mouse-up position
- let pointerLeftOffset = (e.pageX - $elem.offset().left - ($pointerInner.width() / 2));
- if (pointerLeftOffset < 0) pointerLeftOffset = 0;
- let pointerLeftOffsetPercent = (pointerLeftOffset / $elem.width()) * 100;
- $pointerInner.css('left', pointerLeftOffsetPercent + '%');
-
- isSelection = true;
- setTimeout(() => {
- isSelection = false;
- }, 100);
- });
- }
-
- setupStickySidebar() {
- // Make the sidebar stick in view on scroll
- let $window = $(window);
- let $sidebar = $("#sidebar .scroll-body");
- let $bookTreeParent = $sidebar.parent();
-
- // Check the page is scrollable and the content is taller than the tree
- let pageScrollable = ($(document).height() > ($window.height() + 40)) && ($sidebar.height() < $('.page-content').height());
-
- // Get current tree's width and header height
- let headerHeight = $("#header").height() + $(".toolbar").height();
- let isFixed = $window.scrollTop() > headerHeight;
-
- // Fix the tree as a sidebar
- function stickTree() {
- $sidebar.width($bookTreeParent.width() - 32);
- $sidebar.addClass("fixed");
- isFixed = true;
- }
-
- // Un-fix the tree back into position
- function unstickTree() {
- $sidebar.css('width', 'auto');
- $sidebar.removeClass("fixed");
- isFixed = false;
- }
-
- // Checks if the tree stickiness state should change
- function checkTreeStickiness(skipCheck) {
- let shouldBeFixed = $window.scrollTop() > headerHeight;
- if (shouldBeFixed && (!isFixed || skipCheck)) {
- stickTree();
- } else if (!shouldBeFixed && (isFixed || skipCheck)) {
- unstickTree();
- }
- }
- // The event ran when the window scrolls
- function windowScrollEvent() {
- checkTreeStickiness(false);
- }
-
- // If the page is scrollable and the window is wide enough listen to scroll events
- // and evaluate tree stickiness.
- if (pageScrollable && $window.width() > 1000) {
- $window.on('scroll', windowScrollEvent);
- checkTreeStickiness(true);
- }
-
- // Handle window resizing and switch between desktop/mobile views
- $window.on('resize', event => {
- if (pageScrollable && $window.width() > 1000) {
- $window.on('scroll', windowScrollEvent);
- checkTreeStickiness(true);
- } else {
- $window.off('scroll', windowScrollEvent);
- unstickTree();
- }
+ DOM.forEach('.page-content [id^="bkmrk"]', bookMarkElem => {
+ DOM.onEvents(bookMarkElem, ['mouseup', 'keyup'], event => {
+ event.stopPropagation();
+ let selection = window.getSelection();
+ if (selection.toString().length === 0) return;
+
+ // Show pointer and set link
+ pointerSectionId = bookMarkElem.id;
+ updatePointerContent(bookMarkElem);
+
+ bookMarkElem.parentNode.insertBefore(pointer, bookMarkElem);
+ pointer.style.display = 'block';
+ pointerShowing = true;
+ isSelection = true;
+
+ // Set pointer to sit near mouse-up position
+ requestAnimationFrame(() => {
+ const bookMarkBounds = bookMarkElem.getBoundingClientRect();
+ let pointerLeftOffset = (event.pageX - bookMarkBounds.left - 164);
+ if (pointerLeftOffset < 0) {
+ pointerLeftOffset = 0
+ }
+ const pointerLeftOffsetPercent = (pointerLeftOffset / bookMarkBounds.width) * 100;
+
+ pointerInner.style.left = pointerLeftOffsetPercent + '%';
+
+ setTimeout(() => {
+ isSelection = false;
+ }, 100);
+ });
+
+ });
});
}
setupNavHighlighting() {
// Check if support is present for IntersectionObserver
- if (!'IntersectionObserver' in window ||
- !'IntersectionObserverEntry' in window ||
- !'intersectionRatio' in window.IntersectionObserverEntry.prototype) {
+ if (!('IntersectionObserver' in window) ||
+ !('IntersectionObserverEntry' in window) ||
+ !('intersectionRatio' in window.IntersectionObserverEntry.prototype)) {
return;
}
let pageNavObserver = new IntersectionObserver(headingVisibilityChange, intersectOpts);
// observe each heading
- for (let i = 0; i !== headings.length; ++i) {
- pageNavObserver.observe(headings[i]);
+ for (let heading of headings) {
+ pageNavObserver.observe(heading);
}
}
}
function toggleAnchorHighlighting(elementId, shouldHighlight) {
- let anchorsToHighlight = pageNav.querySelectorAll('a[href="#' + elementId + '"]');
- for (let i = 0; i < anchorsToHighlight.length; i++) {
- // Change below to use classList.toggle when IE support is dropped.
- if (shouldHighlight) {
- anchorsToHighlight[i].classList.add('current-heading');
- } else {
- anchorsToHighlight[i].classList.remove('current-heading');
- }
- }
+ DOM.forEach('a[href="#' + elementId + '"]', anchor => {
+ anchor.closest('li').classList.toggle('current-heading', shouldHighlight);
+ });
}
}
}