]> BookStack Code Mirror - bookstack/blob - resources/assets/js/global.js
Merge pull request #3 from BookStackApp/master
[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     let scrollElem = document.documentElement.scrollTop === 0 ?  document.body : document.documentElement;
65     $(scrollElem).animate({
66         scrollTop: this.offset().top - 60 // Adjust to change final scroll position top margin
67     }, 800); // Adjust to change animations speed (ms)
68     return this;
69 };
70
71 // Making contains text expression not worry about casing
72 jQuery.expr[":"].contains = $.expr.createPseudo(function (arg) {
73     return function (elem) {
74         return $(elem).text().toUpperCase().indexOf(arg.toUpperCase()) >= 0;
75     };
76 });
77
78 // Global jQuery Elements
79 let notifications = $('.notification');
80 let successNotification = notifications.filter('.pos');
81 let errorNotification = notifications.filter('.neg');
82 let warningNotification = notifications.filter('.warning');
83 // Notification Events
84 window.Events.listen('success', function (text) {
85     successNotification.hide();
86     successNotification.find('span').text(text);
87     setTimeout(() => {
88         successNotification.show();
89     }, 1);
90 });
91 window.Events.listen('warning', function (text) {
92     warningNotification.find('span').text(text);
93     warningNotification.show();
94 });
95 window.Events.listen('error', function (text) {
96     errorNotification.find('span').text(text);
97     errorNotification.show();
98 });
99
100 // Notification hiding
101 notifications.click(function () {
102     $(this).fadeOut(100);
103 });
104
105 // Chapter page list toggles
106 $('.chapter-toggle').click(function (e) {
107     e.preventDefault();
108     $(this).toggleClass('open');
109     $(this).closest('.chapter').find('.inset-list').slideToggle(180);
110 });
111
112 // Back to top button
113 $('#back-to-top').click(function() {
114      $('#header').smoothScrollTo();
115 });
116 let scrollTopShowing = false;
117 let scrollTop = document.getElementById('back-to-top');
118 let scrollTopBreakpoint = 1200;
119 window.addEventListener('scroll', function() {
120     let scrollTopPos = document.documentElement.scrollTop || document.body.scrollTop || 0;
121     if (!scrollTopShowing && scrollTopPos > scrollTopBreakpoint) {
122         scrollTop.style.display = 'block';
123         scrollTopShowing = true;
124         setTimeout(() => {
125             scrollTop.style.opacity = 0.4;
126         }, 1);
127     } else if (scrollTopShowing && scrollTopPos < scrollTopBreakpoint) {
128         scrollTop.style.opacity = 0;
129         scrollTopShowing = false;
130         setTimeout(() => {
131             scrollTop.style.display = 'none';
132         }, 500);
133     }
134 });
135
136 // Common jQuery actions
137 $('[data-action="expand-entity-list-details"]').click(function() {
138     $('.entity-list.compact').find('p').not('.empty-text').slideToggle(240);
139 });
140
141 // Popup close
142 $('.popup-close').click(function() {
143     $(this).closest('.overlay').fadeOut(240);
144 });
145 $('.overlay').click(function(event) {
146     if (!$(event.target).hasClass('overlay')) return;
147     $(this).fadeOut(240);
148 });
149
150 // Detect IE for css
151 if(navigator.userAgent.indexOf('MSIE')!==-1
152     || navigator.appVersion.indexOf('Trident/') > 0
153     || navigator.userAgent.indexOf('Safari') !== -1){
154     $('body').addClass('flexbox-support');
155 }
156
157 // Page specific items
158 import "./pages/page-show";