]> BookStack Code Mirror - bookstack/blob - resources/assets/js/global.js
Updated issue template and added TinyMCE autolinking
[bookstack] / resources / assets / js / global.js
1 "use strict";
2
3 // AngularJS - Create application and load components
4 import angular from "angular";
5 import "angular-resource";
6 import "angular-animate";
7 import "angular-sanitize";
8 import "angular-ui-sortable";
9
10 // Url retrieval function
11 window.baseUrl = function(path) {
12     let basePath = document.querySelector('meta[name="base-url"]').getAttribute('content');
13     if (basePath[basePath.length-1] === '/') basePath = basePath.slice(0, basePath.length-1);
14     if (path[0] === '/') path = path.slice(1);
15     return basePath + '/' + path;
16 };
17
18 let ngApp = angular.module('bookStack', ['ngResource', 'ngAnimate', 'ngSanitize', 'ui.sortable']);
19
20 // Translation setup
21 // Creates a global function with name 'trans' to be used in the same way as Laravel's translation system
22 import Translations from "./translations"
23 let translator = new Translations(window.translations);
24 window.trans = translator.get.bind(translator);
25
26 // Global Event System
27 class EventManager {
28     constructor() {
29         this.listeners = {};
30     }
31
32     emit(eventName, eventData) {
33         if (typeof this.listeners[eventName] === 'undefined') return this;
34         let eventsToStart = this.listeners[eventName];
35         for (let i = 0; i < eventsToStart.length; i++) {
36             let event = eventsToStart[i];
37             event(eventData);
38         }
39         return this;
40     }
41
42     listen(eventName, callback) {
43         if (typeof this.listeners[eventName] === 'undefined') this.listeners[eventName] = [];
44         this.listeners[eventName].push(callback);
45         return this;
46     }
47 }
48
49 window.Events = new EventManager();
50
51 // Load in angular specific items
52 import Services from './services';
53 import Directives from './directives';
54 import Controllers from './controllers';
55 Services(ngApp, window.Events);
56 Directives(ngApp, window.Events);
57 Controllers(ngApp, window.Events);
58
59 //Global jQuery Config & Extensions
60
61 // Smooth scrolling
62 jQuery.fn.smoothScrollTo = function () {
63     if (this.length === 0) return;
64     $('html, body').animate({
65         scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin
66     }, 300); // Adjust to change animations speed (ms)
67     return this;
68 };
69
70 // Making contains text expression not worry about casing
71 jQuery.expr[":"].contains = $.expr.createPseudo(function (arg) {
72     return function (elem) {
73         return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
74     };
75 });
76
77 // Global jQuery Elements
78 let notifications = $('.notification');
79 let successNotification = notifications.filter('.pos');
80 let errorNotification = notifications.filter('.neg');
81 let warningNotification = notifications.filter('.warning');
82 // Notification Events
83 window.Events.listen('success', function (text) {
84     successNotification.hide();
85     successNotification.find('span').text(text);
86     setTimeout(() => {
87         successNotification.show();
88     }, 1);
89 });
90 window.Events.listen('warning', function (text) {
91     warningNotification.find('span').text(text);
92     warningNotification.show();
93 });
94 window.Events.listen('error', function (text) {
95     errorNotification.find('span').text(text);
96     errorNotification.show();
97 });
98
99 // Notification hiding
100 notifications.click(function () {
101     $(this).fadeOut(100);
102 });
103
104 // Chapter page list toggles
105 $('.chapter-toggle').click(function (e) {
106     e.preventDefault();
107     $(this).toggleClass('open');
108     $(this).closest('.chapter').find('.inset-list').slideToggle(180);
109 });
110
111 // Back to top button
112 $('#back-to-top').click(function() {
113      $('#header').smoothScrollTo();
114 });
115 let scrollTopShowing = false;
116 let scrollTop = document.getElementById('back-to-top');
117 let scrollTopBreakpoint = 1200;
118 window.addEventListener('scroll', function() {
119     let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0;
120     if (!scrollTopShowing && scrollTopPos > scrollTopBreakpoint) {
121         scrollTop.style.display = 'block';
122         scrollTopShowing = true;
123         setTimeout(() => {
124             scrollTop.style.opacity = 0.4;
125         }, 1);
126     } else if (scrollTopShowing && scrollTopPos < scrollTopBreakpoint) {
127         scrollTop.style.opacity = 0;
128         scrollTopShowing = false;
129         setTimeout(() => {
130             scrollTop.style.display = 'none';
131         }, 500);
132     }
133 });
134
135 // Common jQuery actions
136 $('[data-action="expand-entity-list-details"]').click(function() {
137     $('.entity-list.compact').find('p').not('.empty-text').slideToggle(240);
138 });
139
140 // Popup close
141 $('.popup-close').click(function() {
142     $(this).closest('.overlay').fadeOut(240);
143 });
144 $('.overlay').click(function(event) {
145     if (!$(event.target).hasClass('overlay')) return;
146     $(this).fadeOut(240);
147 });
148
149 // Detect IE for css
150 if(navigator.userAgent.indexOf('MSIE')!==-1
151     || navigator.appVersion.indexOf('Trident/') > 0
152     || navigator.userAgent.indexOf('Safari') !== -1){
153     $('body').addClass('flexbox-support');
154 }
155
156 // Page specific items
157 import "./pages/page-show";