]> BookStack Code Mirror - bookstack/blob - resources/assets/js/pages/page-show.js
Merge branch 'Abijeet-master'
[bookstack] / resources / assets / js / pages / page-show.js
1 "use strict";
2 // Configure ZeroClipboard
3 const Clipboard = require("clipboard");
4 const Code = require('../code');
5
6 let setupPageShow = window.setupPageShow = function (pageId) {
7
8     Code.highlight();
9
10     if (!pageId) return;
11
12     // Set up pointer
13     let $pointer = $('#pointer').detach();
14     let pointerShowing = false;
15     let $pointerInner = $pointer.children('div.pointer').first();
16     let isSelection = false;
17     let pointerModeLink = true;
18     let pointerSectionId = '';
19
20     // Select all contents on input click
21     $pointer.on('click', 'input', function (e) {
22         $(this).select();
23         e.stopPropagation();
24     });
25
26     // Pointer mode toggle
27     $pointer.on('click', 'span.icon', event => {
28         let $icon = $(event.currentTarget);
29         pointerModeLink = !pointerModeLink;
30         $icon.html(pointerModeLink ? '<i class="zmdi zmdi-link"></i>' : '<i class="zmdi zmdi-square-down"></i>');
31         updatePointerContent();
32     });
33
34     // Set up clipboard
35     let clipboard = new Clipboard('#pointer button');
36
37     // Hide pointer when clicking away
38     $(document.body).find('*').on('click focus', event => {
39         if (!pointerShowing || isSelection) return;
40         let target = $(event.target);
41         if (target.is('.zmdi') || $(event.target).closest('#pointer').length === 1) return;
42
43         $pointer.detach();
44         pointerShowing = false;
45     });
46
47     function updatePointerContent() {
48         let inputText = pointerModeLink ? window.baseUrl(`/link/${pageId}#${pointerSectionId}`) : `{{@${pageId}#${pointerSectionId}}}`;
49         if (pointerModeLink && inputText.indexOf('http') !== 0) inputText = window.location.protocol + "//" + window.location.host + inputText;
50
51         $pointer.find('input').val(inputText);
52     }
53
54     // Show pointer when selecting a single block of tagged content
55     $('.page-content [id^="bkmrk"]').on('mouseup keyup', function (e) {
56         e.stopPropagation();
57         let selection = window.getSelection();
58         if (selection.toString().length === 0) return;
59
60         // Show pointer and set link
61         let $elem = $(this);
62         pointerSectionId = $elem.attr('id');
63         updatePointerContent();
64
65         $elem.before($pointer);
66         $pointer.show();
67         pointerShowing = true;
68
69         // Set pointer to sit near mouse-up position
70         let pointerLeftOffset = (e.pageX - $elem.offset().left - ($pointerInner.width() / 2));
71         if (pointerLeftOffset < 0) pointerLeftOffset = 0;
72         let pointerLeftOffsetPercent = (pointerLeftOffset / $elem.width()) * 100;
73         $pointerInner.css('left', pointerLeftOffsetPercent + '%');
74
75         isSelection = true;
76         setTimeout(() => {
77             isSelection = false;
78         }, 100);
79     });
80
81     // Go to, and highlight if necessary, the specified text.
82     function goToText(text) {
83         let idElem = document.getElementById(text);
84         $('.page-content [data-highlighted]').attr('data-highlighted', '').css('background-color', '');
85         if (idElem !== null) {
86             let $idElem = $(idElem);
87             let color = $('#custom-styles').attr('data-color-light');
88             $idElem.css('background-color', color).attr('data-highlighted', 'true').smoothScrollTo();
89             setTimeout(() => {
90                 $idElem.addClass('anim').addClass('selectFade').css('background-color', '');
91                 setTimeout(() => {
92                    $idElem.removeClass('selectFade');
93                 }, 3000);
94             }, 100);
95         } else {
96             $('.page-content').find(':contains("' + text + '")').smoothScrollTo();
97         }
98     }
99
100     // Check the hash on load
101     if (window.location.hash) {
102         let text = window.location.hash.replace(/\%20/g, ' ').substr(1);
103         goToText(text);
104     }
105
106     // Sidebar page nav click event
107     $('.sidebar-page-nav').on('click', 'a', event => {
108         goToText(event.target.getAttribute('href').substr(1));
109     });
110
111     // Make the book-tree sidebar stick in view on scroll
112     let $window = $(window);
113     let $bookTree = $(".book-tree");
114     let $bookTreeParent = $bookTree.parent();
115     // Check the page is scrollable and the content is taller than the tree
116     let pageScrollable = ($(document).height() > $window.height()) && ($bookTree.height() < $('.page-content').height());
117     // Get current tree's width and header height
118     let headerHeight = $("#header").height() + $(".toolbar").height();
119     let isFixed = $window.scrollTop() > headerHeight;
120     // Function to fix the tree as a sidebar
121     function stickTree() {
122         $bookTree.width($bookTreeParent.width() + 15);
123         $bookTree.addClass("fixed");
124         isFixed = true;
125     }
126     // Function to un-fix the tree back into position
127     function unstickTree() {
128         $bookTree.css('width', 'auto');
129         $bookTree.removeClass("fixed");
130         isFixed = false;
131     }
132     // Checks if the tree stickiness state should change
133     function checkTreeStickiness(skipCheck) {
134         let shouldBeFixed = $window.scrollTop() > headerHeight;
135         if (shouldBeFixed && (!isFixed || skipCheck)) {
136             stickTree();
137         } else if (!shouldBeFixed && (isFixed || skipCheck)) {
138             unstickTree();
139         }
140     }
141     // The event ran when the window scrolls
142     function windowScrollEvent() {
143         checkTreeStickiness(false);
144     }
145
146     // If the page is scrollable and the window is wide enough listen to scroll events
147     // and evaluate tree stickiness.
148     if (pageScrollable && $window.width() > 1000) {
149         $window.on('scroll', windowScrollEvent);
150         checkTreeStickiness(true);
151     }
152
153     // Handle window resizing and switch between desktop/mobile views
154     $window.on('resize', event => {
155         if (pageScrollable && $window.width() > 1000) {
156             $window.on('scroll', windowScrollEvent);
157             checkTreeStickiness(true);
158         } else {
159             $window.off('scroll', windowScrollEvent);
160             unstickTree();
161         }
162     });
163
164     // in order to call from other places.
165     window.setupPageShow.goToText = goToText;
166 };
167
168 module.exports = setupPageShow;