Refresh your page to take effect.`)
62 | toggleButton(true);
63 |
64 | new Promise((resolve, reject) =>
65 | chrome.storage['sync'].set({falconEnabled: true}, () =>
66 | chrome.runtime.lastError
67 | ? reject(Error(chrome.runtime.lastError.message))
68 | : resolve()
69 | )
70 | );
71 | })
72 | disableButton.on('click', function() {
73 | $('#falcon-alert').html(`
Falcon has been disabled. The only thing still enabled is the purple theme of OWL, which
does not impact any functionality since it's just a theme . Refresh your page to take effect.`)
74 | toggleButton(false);
75 |
76 | new Promise((resolve, reject) =>
77 | chrome.storage['sync'].set({falconEnabled: false}, () =>
78 | chrome.runtime.lastError
79 | ? reject(Error(chrome.runtime.lastError.message))
80 | : resolve()
81 | )
82 | );
83 | })
84 |
85 | });
86 |
87 |
--------------------------------------------------------------------------------
/src/services/dark-mode.js:
--------------------------------------------------------------------------------
1 | import FalconStorage from "./storage";
2 | import AssetInjector from "../ui/asset-injector";
3 | import FalconInterfaceInjector from "../ui/ui-injector";
4 | import FalconAnnouncement from "./announcement";
5 |
6 | class FalconDarkMode {
7 | storageKey = 'darkMode'
8 | assetUrl = './assets/falcon-dark.css';
9 | assetUrlLight = './assets/falcon.css';
10 | className = 'falcon-dark-mode';
11 | classNameLight = 'falcon-normal-mode';
12 | isDarkModeEnabled;
13 |
14 | constructor() {
15 | FalconInterfaceInjector.darkModeButton();
16 | this.setupEventListeners();
17 | this.isEnabled().then(({darkMode}) => {
18 | this.isDarkModeEnabled = darkMode;
19 | this.isDarkModeEnabled ? this.injectDarkMode() : this.removeDarkMode();
20 | })
21 | }
22 |
23 |
24 | setupEventListeners() {
25 | let self = this;
26 | $('#dark-mode-toggle').on('click', function () {
27 | self.toggle();
28 | })
29 | }
30 |
31 | static isDarkModeEnabled() {
32 | return $("#dark-mode-toggle-icon").hasClass('fa-toggle-on');
33 | }
34 |
35 | isEnabled() {
36 | return FalconStorage.sync().get(this.storageKey);
37 | }
38 |
39 | toggle() {
40 | if (this.isDarkModeEnabled) {
41 | this.removeDarkMode();
42 | this.disable();
43 | } else {
44 | this.injectDarkMode();
45 | this.enable();
46 | }
47 | }
48 |
49 | injectDarkMode() {
50 | AssetInjector.falconAssets().alsoToIframes().once().injectStyle(this.assetUrl, this.className)
51 | $("#dark-mode-toggle-icon").addClass('fa-toggle-on');
52 | this.isDarkModeEnabled = true;
53 | this.fixPortalColors();
54 | FalconAnnouncement.fixDarkModeAnnouncement();
55 | }
56 |
57 | removeDarkMode() {
58 | // AssetInjector.falconAssets().alsoToIframes().once().injectStyle(this.assetUrlLight, this.classNameLight);
59 | AssetInjector.falconAssets().alsoToIframes().removeInjectionByClassName(this.className);
60 | $("#dark-mode-toggle-icon").removeClass('fa-toggle-on');
61 | this.isDarkModeEnabled = false
62 | }
63 |
64 | fixPortalColors() {
65 | // sometimes instructors set certain colors to the portal (like black for text) which, when dark mode is enabled, cannot be overwritten as easily.
66 | // so remove those overwritten styles
67 | $('.portletBody.siteDescription [style*="background-color"]').css('background-color', '');
68 | $('.portletBody.siteDescription [style*="background"]').css('background-color', '');
69 | $('.portletBody.siteDescription [style*="color"]').css('color', '');
70 | }
71 |
72 |
73 |
74 | // Enable and disable are separate from the injectDarkMode and removeDarkMode because we don't want to save the settings everytime from the constructor
75 | enable() {
76 | FalconStorage.sync().set({darkMode: true})
77 | }
78 |
79 | disable() {
80 | FalconStorage.sync().set({darkMode: false})
81 | }
82 |
83 |
84 | }
85 |
86 | export default FalconDarkMode;
87 |
--------------------------------------------------------------------------------
/src/popup.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
Falcon
12 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
Falcon for Owl
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 | Falcon is
40 |
41 |
42 |
43 | Active Disabled
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 | Disable Falcon
60 |
61 |
62 | Enable Falcon
63 |
64 |
65 |
66 |
67 |
Reset Falcon
68 |
69 |
Reset Falcon?
70 |
Doing so will remove all your saved course names and clear your Falcon Editor. Are you sure?
71 |
Cancel
72 |
Reset Falcon
73 |
74 |
75 |
Falcon has been reset. Refresh your page to take effect.
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
--------------------------------------------------------------------------------
/src/assets/scss/bootstrap/card.scss:
--------------------------------------------------------------------------------
1 | //
2 | // card.scss
3 | // Extended from Bootstrap
4 | //
5 |
6 | //
7 | // Bootstrap Overrides =====================================
8 | //
9 |
10 | .card {
11 | display: block;
12 | margin-bottom: $spacer;
13 | border-color: $card-outline-color;
14 | box-shadow: $card-box-shadow;
15 | }
16 |
17 | .card-header {
18 | display: flex;
19 | flex-direction: row;
20 | flex-grow: 1;
21 | align-items: center;
22 | min-height: $card-header-min-height;
23 | padding-top: $card-spacer-y / 2;
24 | padding-bottom: $card-spacer-y / 2;
25 | border-bottom-color: $border-color !important;
26 | > * {
27 | flex: 1;
28 | }
29 | }
30 |
31 | .card-title {
32 | margin-bottom: .5rem;
33 | }
34 |
35 |
36 | //
37 | // Dashkit ===================================
38 | //
39 |
40 | // Card header
41 | //
42 | // Make sure the card header is always the same height with its content
43 | // centered vertically
44 |
45 | .card-header-title {
46 | margin-bottom: 0;
47 | }
48 |
49 | .card-header-tabs {
50 | margin-top: -$card-spacer-y / 2;
51 | margin-bottom: -$card-spacer-y / 2;
52 | margin-left: 0;
53 | margin-right: 0;
54 | }
55 |
56 | .card-header-tabs .nav-link {
57 | padding-top: calc((#{$card-header-min-height} - 1em * #{$line-height-base}) / 2) !important;
58 | padding-bottom: calc((#{$card-header-min-height} - 1em * #{$line-height-base}) / 2) !important;
59 | }
60 |
61 |
62 | // Card table
63 | //
64 | // Make sure the card table content is aligned with the rest of the
65 | // card content
66 |
67 | .card-table {
68 | margin-bottom:0;
69 |
70 | thead th {
71 | border-top-width: 0;
72 | }
73 |
74 | thead th, tbody td {
75 |
76 | &:first-child {
77 | padding-left: $card-spacer-x !important;
78 | }
79 | &:last-child {
80 | padding-right: $card-spacer-x !important;
81 | }
82 | }
83 | }
84 |
85 | .card > .table-responsive:first-child > .card-table,
86 | .card > .card-table:first-child {
87 |
88 | > thead, > tbody, > tfoot {
89 |
90 | &:first-child {
91 |
92 | > tr:first-child {
93 |
94 | > th, > td {
95 |
96 | &:first-child {
97 | border-top-left-radius: $card-border-radius;
98 | }
99 | &:last-child {
100 | border-top-right-radius: $card-border-radius;
101 | }
102 | }
103 | }
104 | }
105 | }
106 | }
107 |
108 |
109 | // Card avatar
110 | //
111 | // Moves card avatar up by 50%
112 |
113 | .card-avatar {
114 | display: block !important;
115 | margin-left: auto; margin-right: auto;
116 | margin-bottom: $card-spacer-y;
117 | }
118 | .card-avatar-top {
119 | margin-top: -($card-spacer-x + $avatar-size-base / 2);
120 | }
121 | .card-avatar-top.avatar-xs {
122 | margin-top: -($card-spacer-x + $avatar-size-xs / 2);
123 | }
124 | .card-avatar-top.avatar-sm {
125 | margin-top: -($card-spacer-x + $avatar-size-sm / 2);
126 | }
127 | .card-avatar-top.avatar-lg {
128 | margin-top: -($card-spacer-x + $avatar-size-lg / 2);
129 | }
130 | .card-avatar-top.avatar-xl {
131 | margin-top: -($card-spacer-x + $avatar-size-xl / 2);
132 | }
133 | .card-avatar-top.avatar-xxl {
134 | margin-top: -($card-spacer-x + $avatar-size-xxl / 2);
135 | }
136 |
137 |
138 | // Card dropdown
139 | //
140 | // Places dropdowns in the top right corner
141 |
142 | .card-dropdown {
143 | position: absolute;
144 | top: $card-spacer-x;
145 | right: $card-spacer-x;
146 | }
147 |
148 |
149 | // Card inactive
150 |
151 | .card-inactive {
152 | border-color: $border-color;
153 | border-style: dashed;
154 | background-color: transparent;
155 | box-shadow: none;
156 | }
157 |
158 |
159 | // Card flush
160 |
161 | .card-flush {
162 | background: none;
163 | border: none;
164 | box-shadow: none;
165 | }
166 |
167 |
168 | // Card sizing
169 |
170 | .card-sm .card-body {
171 | padding: $card-spacer-x-sm;
172 | }
173 |
174 |
175 | // Card header flush
176 |
177 | .card-header-flush {
178 | border-bottom: 0;
179 | }
180 |
181 | .card-header-flush + .card-body {
182 | padding-top: 0;
183 | }
184 |
--------------------------------------------------------------------------------
/src/services/course-name-editor.js:
--------------------------------------------------------------------------------
1 | import FalconStorage from "./storage";
2 | import FalconInterfaceInjector from "../ui/ui-injector";
3 |
4 | class FalconCourseNameEditor {
5 |
6 | STORAGE_KEY = 'customCourseNames';
7 | customCourseNames = [];
8 |
9 | constructor() {
10 | FalconInterfaceInjector.courseEditElements();
11 | this.addEventListeners();
12 | this.getCourseNames()
13 | }
14 |
15 |
16 |
17 | addEventListeners() {
18 |
19 | let self = this;
20 |
21 | $('.edit-course-name-button').on('click', function () {
22 | $('#custom-course-name-text').val('');
23 | let link = $(this).siblings('div.fav-title').find('a');
24 | $('#old-course-name').html(link.attr('title'));
25 | self.autoPopulateCourseNameInModal()
26 | })
27 |
28 |
29 | // once they save their custom course name
30 | $('#save-custom-course-title-button').on('click', function () {
31 | let customName = $('#custom-course-name-text').val();
32 | let oldCourseName = $('#old-course-name').html();
33 |
34 | self.saveCourseName(oldCourseName, customName).then(() => {
35 | $('#custom-course-name-text').val('');
36 | $('#edit-course-title-modal').modal('hide');
37 | });
38 | })
39 |
40 | $('#custom-course-name-text').on('keypress', function (e) {
41 | if (e.which === 13) { // enter pressed
42 | // Disable textbox to prevent multiple submit
43 | $(this).attr("disabled", "disabled");
44 | $('#save-custom-course-title-button').click();
45 | $(this).removeAttr("disabled");
46 | }
47 | });
48 |
49 | }
50 |
51 | // auto populate course name that's being edited in the text box
52 | autoPopulateCourseNameInModal() {
53 |
54 | let oldName = $('#old-course-name').html();
55 |
56 | let exists = FalconStorage.existsInStorage(this.customCourseNames, 'oldName', oldName);
57 | // exists already!
58 | if (exists) {
59 | let course = this.customCourseNames.filter(item => {
60 | return item.oldName === oldName;
61 | })[0];
62 |
63 | $('#custom-course-name-text').val(oldName === course.newName ? '' : course.newName);
64 | }
65 |
66 | }
67 |
68 |
69 | async saveCourseName(oldName, newName) {
70 |
71 | let customCourseNames = this.customCourseNames;
72 |
73 | if (!customCourseNames) {
74 | customCourseNames = [];
75 | }
76 |
77 | // no name exists... set the new name to old name
78 | if (!newName.trim()) {
79 | newName = oldName;
80 | }
81 |
82 | let exists = FalconStorage.existsInStorage(customCourseNames, 'oldName', oldName);
83 |
84 | if (exists) {
85 | customCourseNames.map(item => {
86 | if (item.oldName === oldName) {
87 | return item.newName = newName;
88 | }
89 | return item;
90 | })
91 | } else {
92 | customCourseNames.push({oldName: oldName, newName: newName})
93 | }
94 |
95 | await FalconStorage.sync().set({customCourseNames});
96 | this.replaceDomCourseNamesWithNewNames();
97 | }
98 |
99 | replaceDomCourseNamesWithNewNames() {
100 |
101 | let self = this;
102 | $('.link-container span').each(reflectCourseNameChanges);
103 | $('.fullTitle').each(reflectCourseNameChanges);
104 |
105 | function reflectCourseNameChanges() {
106 | let oldName = $(this).parent().attr('title');
107 |
108 | let exists = FalconStorage.existsInStorage(self.customCourseNames, 'oldName', oldName);
109 | if (exists) {
110 | let course = self.customCourseNames.filter(item => {
111 | return item.oldName === oldName;
112 | })[0];
113 | $(this).html(course.newName);
114 | }
115 | }
116 | }
117 |
118 | async getCourseNames() {
119 | FalconStorage.sync().get(this.STORAGE_KEY).then((data) => {
120 | let {customCourseNames} = data;
121 | if (customCourseNames && customCourseNames !== 'undefined') {
122 | this.customCourseNames = customCourseNames;
123 | this.replaceDomCourseNamesWithNewNames()
124 | }
125 | });
126 | }
127 |
128 | }
129 |
130 | export default FalconCourseNameEditor;
131 |
--------------------------------------------------------------------------------
/src/assets/scss/bootstrap/variables-dark.scss:
--------------------------------------------------------------------------------
1 | //
2 | // variables-dark.scss
3 | // Dashkit dark version
4 | //
5 |
6 | //
7 | // Bootstrap Overrides ===================================
8 | //
9 |
10 |
11 | //
12 | // Color system
13 | //
14 |
15 | $border-color: #393d3d;
16 |
17 | $gray-300: #E3EBF6 !default;
18 | $gray-600: #95AAC9 !default;
19 | $gray-700: #6E84A3 !default;
20 | $gray-900: #283E59 !default;
21 | $black: #12263F !default;
22 |
23 | $gray-600-dark: #244166 !default;
24 | $gray-700-dark: #1E3A5C !default;
25 | $gray-800-dark: #152E4D !default;
26 | $gray-900-dark: #132A46 !default;
27 | $black-dark: #12263F !default;
28 |
29 | $light: $gray-800-dark !default;
30 | $lighter: $gray-900-dark !default;
31 |
32 |
33 | // Body
34 | //
35 | // Settings for the `` element.
36 |
37 | $body-bg: $black-dark !default;
38 | $body-color: $white !default;
39 |
40 |
41 | // Components
42 | //
43 | // Define common padding and border radius sizes and more.
44 |
45 | // Fonts
46 | //
47 | // Font, line-height, and color for body text, headings, and more.
48 |
49 | $text-muted: $gray-700 !default;
50 |
51 |
52 | // Tables
53 | //
54 | // Customizes the `.table` component with basic values, each used across all table variations.
55 |
56 | $table-border-color: $border-color !default;
57 |
58 | $table-head-bg: $black-dark !default;
59 |
60 |
61 | // Forms
62 |
63 | $input-bg: $gray-700-dark !default;
64 |
65 | $input-color: $white !default;
66 | $input-border-color: $black-dark !default;
67 |
68 | $input-placeholder-color: $gray-600 !default;
69 |
70 | $custom-control-indicator-bg: $gray-600-dark !default;
71 |
72 |
73 | // Dropdowns
74 | //
75 | // Dropdown menu container and contents.
76 |
77 | $dropdown-bg: $gray-800-dark !default;
78 | $dropdown-border-color: $black !default;
79 | $dropdown-divider-bg: $black !default;
80 |
81 | $dropdown-link-color: $text-muted !default;
82 | $dropdown-link-hover-color: $white !default;
83 |
84 |
85 | // Navbar
86 |
87 | $navbar-dark-color: $gray-700 !default;
88 | $navbar-dark-hover-color: $black !default;
89 | $navbar-dark-active-color: $black !default;
90 | $navbar-dark-toggler-border-color: transparent !default;
91 |
92 | $navbar-dark-bg: $white !default;
93 | $navbar-dark-border-color: $white !default;
94 | $navbar-dark-heading-color: $text-muted !default;
95 | $navbar-dark-divider-color: $gray-300 !default;
96 | $navbar-dark-brand-filter: none;
97 |
98 | $navbar-dark-input-bg: $input-bg !default;
99 | $navbar-dark-input-border-color: $input-border-color !default;
100 |
101 | $navbar-light-hover-color: $white !default;
102 | $navbar-light-active-color: $white !default;
103 | $navbar-light-input-bg: $gray-700-dark !default;
104 | $navbar-light-input-border-color: $black-dark !default;
105 |
106 |
107 | // Pagination
108 |
109 | $pagination-color: $white !default;
110 | $pagination-bg: $gray-800-dark !default;
111 | $pagination-border-color: $gray-600-dark !default;
112 |
113 | $pagination-hover-color: $white !default;
114 | $pagination-hover-bg: $gray-900-dark !default;
115 | $pagination-hover-border-color: $gray-700-dark !default;
116 |
117 | $pagination-disabled-bg: $gray-900-dark !default;
118 | $pagination-disabled-border-color: $gray-700-dark !default;
119 |
120 |
121 | // Jumbotron
122 |
123 | $jumbotron-bg: $gray-800-dark !default;
124 |
125 |
126 | // Cards
127 |
128 | $card-bg: $gray-800-dark !default;
129 | $card-border-color: $border-color !default;
130 |
131 |
132 | // Tooltips
133 |
134 | $tooltip-bg: $gray-800-dark !default;
135 | $tooltip-color: $white !default;
136 |
137 |
138 | // Popovers
139 |
140 | $popover-bg: $gray-800-dark !default;
141 | $popover-border-color: $black !default;
142 |
143 |
144 | // Toasts
145 |
146 | $toast-background-color: $gray-800-dark !default;;
147 |
148 |
149 | // Modals
150 |
151 | $modal-content-bg: $gray-800-dark !default;
152 | $modal-content-border-color: $black !default;
153 |
154 |
155 | // Progress bars
156 |
157 | $progress-bg: $gray-600-dark !default;
158 |
159 |
160 | //
161 | // Dashkit =====================================
162 | //
163 |
164 | // Auth
165 |
166 | $auth-bg: $body-bg !default;
167 |
168 |
169 | // Avatar
170 |
171 | $avatar-title-bg: $gray-600-dark !default;
172 |
173 |
174 | // Badges
175 |
176 | $badge-soft-bg-level: 10 !default;
177 |
178 |
179 | // Cards
180 |
181 | $card-outline-color: #393d3d !important;
182 | $card-box-shadow: 0 .75rem 1.5rem transparentize($black-dark, .5) !important;
183 |
184 |
185 | // Comment
186 |
187 | $comment-body-bg: $gray-700-dark;
188 |
189 |
190 | // Header
191 |
192 | $header-body-border-color-dark: $border-color !default;
193 |
194 |
195 | // Navbar
196 |
197 | $navbar-light-bg: $gray-800-dark !default;
198 | $navbar-light-border-color: $gray-800-dark !default;
199 |
200 |
201 | // Switch
202 |
203 | $custom-switch-indicator-bg: $gray-800-dark !default;
204 | $custom-switch-indicator-active-bg: $white !default;
205 |
--------------------------------------------------------------------------------
/src/ui/asset-injector.js:
--------------------------------------------------------------------------------
1 | const AssetInjector = {
2 |
3 | getFalconAsset: false,
4 | injectToIframes: false,
5 | onlyOnce: false,
6 | appendToEndOfBody: false,
7 |
8 | falconAssets: function () {
9 | this.getFalconAsset = true;
10 | return this;
11 | },
12 |
13 | owlAssets: function () {
14 | this.getFalconAsset = false;
15 | return this;
16 | },
17 |
18 | getUrl: function (url) {
19 | if (this.getFalconAsset) {
20 | return chrome.runtime.getURL(url);
21 | }
22 | return url;
23 | },
24 |
25 | // inject asset only once... MUST HAVE className to keep track of insertion
26 | once: function () {
27 | this.onlyOnce = true;
28 | return this;
29 | },
30 |
31 | alsoToIframes: function () {
32 | this.injectToIframes = true;
33 | return this;
34 | },
35 |
36 | injectScript: function (src, className = null) {
37 | let script = document.createElement('script');
38 | script.src = this.getUrl(src);
39 | if (className) {
40 | script.className = className;
41 | }
42 | script.onload = function () {
43 | // this.remove();
44 | };
45 |
46 | // let parentElement = this.appendToEndOfBody ? document.body : (document.head || document.documentElement);
47 |
48 | if (this.onlyOnce) {
49 | if ($(`.${className}`).length === 0) {
50 | (document.head || document.documentElement).appendChild(script);
51 | }
52 | } else {
53 | (document.head || document.documentElement).appendChild(script);
54 | }
55 |
56 | return this;
57 | },
58 |
59 | endOfBody() {
60 | this.appendToEndOfBody = true;
61 | return this;
62 | },
63 | endOfHead() {
64 | this.appendToEndOfBody = false;
65 | return this;
66 | },
67 |
68 | injectStyle: function (url, className = null) {
69 |
70 | let link = document.createElement('link');
71 | link.setAttribute('rel', 'stylesheet');
72 | link.href = this.getUrl(url);
73 | if (className) {
74 | link.className = className;
75 | }
76 |
77 | if (this.onlyOnce) {
78 | if ($(`.${className}`).length === 0) {
79 | document.body.appendChild(link.cloneNode(true));
80 | }
81 | } else {
82 | document.body.appendChild(link.cloneNode(true));
83 | }
84 |
85 |
86 | if (this.injectToIframes) {
87 | // $('.portletMainIframe').contents().find('body').append(link);
88 | //
89 | // if ($('.portletMainIframe').length > 0) {
90 | // $('iframe').on('load', function() {
91 | // $('.portletMainIframe').contents().find('body').append(link);
92 | // })
93 | // }
94 |
95 |
96 | $('iframe').contents().find('body').append(link);
97 |
98 | if ( $('iframe').length > 0) {
99 | $('iframe').on('load', function() {
100 | $('iframe').contents().find('body').append(link);
101 | })
102 | }
103 |
104 |
105 | // ensure that it has been injected...
106 | // this fixes the bug that doesn't enable dark mode after page switching from pjax
107 | // setTimeout(function () {
108 | // if ($('.portletMainIframe').length > 0) {
109 | // if ($('.portletMainIframe').contents().find('.falcon-dark-mode').length === 0) {
110 | // $('.portletMainIframe').contents().find('body').append(link);
111 | // }
112 | // }
113 | // }, 500)
114 | }
115 |
116 |
117 | return this;
118 | },
119 |
120 | removeInjectionByUrl: function (url) {
121 | // find out if the URL is css or js
122 | let mimeType = url.split('.').pop();
123 |
124 | if (mimeType === 'css') {
125 | $('link').find(`[href='${url}']`).remove();
126 | } else if (mimeType === 'js') {
127 | $('script').find(`[src='${url}']`).remove();
128 | }
129 | },
130 |
131 | removeInjectionByClassName: function (className) {
132 | $(`.${className}`).remove();
133 |
134 | if (this.injectToIframes) {
135 | $('.portletMainIframe').contents().find(`.${className}`).remove();
136 | }
137 | return this;
138 | },
139 |
140 | injectRawHtml: function (html, className = null) {
141 | if (this.onlyOnce) {
142 | if ($(`.${className}`).length === 0) {
143 | $(html).appendTo(document.head);
144 | return this;
145 | }
146 | } else {
147 | $(html).appendTo(document.head);
148 | return this;
149 | }
150 |
151 | return this;
152 | }
153 |
154 |
155 | }
156 |
157 | export default AssetInjector;
158 |
--------------------------------------------------------------------------------
/src/assets/css/owl/lesson-builder-checklist.css:
--------------------------------------------------------------------------------
1 | .checklistForm {
2 | margin-left: 1em;
3 | }
4 | #checklistItems {
5 | display: inline-block;
6 | width: 90%;
7 | max-width: 500px;
8 | }
9 | #createdChecklistItems {
10 | margin-bottom: 1em;
11 | list-style: none;
12 | }
13 | #createdChecklistItems li {
14 | background: #eee;
15 | margin: 0 3px 3px 3px;
16 | padding: 0.2em 0.4em 0.2em 1.5em;
17 | font-size: 1.4em;
18 | }
19 | .handle {
20 | margin-left: -1em;
21 | }
22 |
23 | .checklist-icons {
24 | margin-top: .3em;
25 | }
26 | #createdChecklistItems li:hover {
27 | border-color: #0074D9;
28 | background-color: #ddd;
29 | }
30 | .checklist-item-name {
31 | line-height: 1.7em;
32 | width: 85%;
33 | max-width: 500px;
34 | }
35 | .checklistDescription {
36 | display: block;
37 | }
38 | #description:not(th) {
39 | height: 80px;
40 | width: 90%;
41 | max-width: 500px;
42 | }
43 | .actionContainer {
44 | float: right;
45 | }
46 | .deleteItemLink {
47 | margin-top: -3px;
48 | }
49 |
50 | ul#createdChecklistItems .handle, ul#createdChecklistItems .handle:hover {
51 | cursor: move;
52 | }
53 |
54 | #addChecklistItemButton { /** Have to use important because tool.css overrides **/
55 | display: block !important;
56 | }
57 | #addChecklistItemButton:hover { /** Have to use important because tool.css overrides **/
58 | display: block !important;
59 | }
60 | .titleBorder {
61 | border-bottom: 1px solid #ccc;
62 | }
63 | #name{
64 | vertical-align: middle;
65 | }
66 | .checklistFormInput input, .checklistFormInput textarea {
67 | margin-left: 2em;
68 | margin-top: .5em;
69 | }
70 | .checklistFormInput label{
71 | margin-left: 0;
72 | font-weight: bold;
73 | color: #555;
74 | font-size: 110%;
75 | }
76 | p.edit-group {
77 | margin-top: 2em;
78 | }
79 | .checklist-checkbox {
80 | /** Hide from sighted users **/
81 | position: absolute;
82 | left:-10000px;
83 | top:auto;
84 | }
85 | .checklist-checkbox ~ span.checklist-checkbox-label {
86 | background-image: url("https://owl.uwo.ca/lessonbuilder-tool/images/gray_unchecked.png");
87 | background-position: left center;
88 | background-repeat: no-repeat;
89 | }
90 | .checklist-checkbox:checked ~ span.checklist-checkbox-label {
91 | background-image: url("https://owl.uwo.ca/lessonbuilder-tool/images/green_checkmark.png");
92 | background-position: left center;
93 | background-repeat: no-repeat;
94 | }
95 | .checklist-checkbox-label {
96 | padding: 0.5em 0.5em 0.5em 22px;
97 | }
98 | label.checklistLabel.disabled:hover input.checklist-checkbox ~ span.checklist-checkbox-label {
99 | background-image: none;
100 | cursor: not-allowed;
101 | }
102 | label.checklistLabel:hover .checklist-checkbox ~ span.checklist-checkbox-label {
103 | background-image: url("https://owl.uwo.ca/lessonbuilder-tool/images/gray_checkmark.png");
104 | background-position: left center;
105 | background-repeat: no-repeat;
106 | cursor: pointer;
107 | }
108 | label.checklistLabel:hover .checklist-checkbox:checked ~ span.checklist-checkbox, label.checklistLabel:hover .checklist-checkbox:checked ~ span.checklist-checkbox-label {
109 | background-image: url("https://owl.uwo.ca/lessonbuilder-tool/images/green_checkmark.png");
110 | }
111 | .checklistLabel {
112 | line-height: 2em;
113 | }
114 | .hideNameCheckbox {
115 | margin: 1em .5em 0 4em !important;
116 | }
117 | .hideNameCheckboxLabel {
118 | font-size: 100% !important;
119 | }
120 | h3.checklistTitle {
121 | display: inline-block;
122 | margin-top: 0;
123 | }
124 | legend.no-border {
125 | border: none;
126 | margin: 0;
127 | padding: 0;
128 | }
129 | #additionalSettings {
130 | margin: 1em 0;
131 | max-width: 600px;
132 | }
133 | /* Override the jquery ui optional settings stylings. */
134 | .ui-accordion-header.ui-state-default.ui-state-active {
135 | border-color: #c5c5c5;
136 | background-color: #ededed;
137 | color: #212121;
138 | }
139 |
140 | .checklistList {
141 | display: inline;
142 | }
143 |
144 | .checklistList-item {
145 | display:flex;
146 | }
147 |
148 | .checklistList-radio {
149 | margin-right: 4px;
150 | }
151 |
152 | .external-link, .external-unlink {
153 | cursor: pointer;
154 | }
155 |
156 | .dialogs {
157 | display: none;
158 | }
159 |
160 |
161 | .checklistLabel.disabled:hover .externally-linked {
162 | margin-right: -19px;
163 | display: inline-block;
164 | }
165 |
166 | .tooltip-content {
167 | display: none;
168 | position: absolute;
169 | background-color: #fff;
170 | padding: .5em;
171 | border: 1px solid black;
172 | box-shadow: 2px 2px 1px rgba(0, 0, 0, 0.5);
173 | width: 20em;
174 | height: auto;
175 | line-height: normal;
176 | font-weight: normal;
177 | z-index: 900001;
178 | cursor: pointer;
179 | }
180 |
181 | span.externally-linked, label input.checklist-checkbox:checked + span.externally-linked {
182 | display: none;
183 | }
184 |
185 | h3.ui-accordion-header span:last-child {
186 | margin-left: 1.5em;
187 | }
188 |
--------------------------------------------------------------------------------
/src/services/falcon.js:
--------------------------------------------------------------------------------
1 | import Pjax from "pjax";
2 | import topbar from "topbar";
3 |
4 | import TableSorter from "./table-sorter";
5 | import $ from "jquery";
6 | import FalconEditor from "./falcon-editor";
7 | import 'bootstrap';
8 | import FalconFileManager from "./file-manager";
9 | import FalconInterfaceInjector from "../ui/ui-injector";
10 | import FalconCourseNameEditor from "./course-name-editor";
11 | import FalconDarkMode from "./dark-mode";
12 | import AssetInjector from "../ui/asset-injector";
13 | import FalconAssignments from "./falcon-assignments";
14 | import FalconAnnouncement from "./announcement";
15 | import FalconGradebook from "./gradebook";
16 |
17 | let currentCourseId; // in format 39cbafa5-fa7b-4a18-8ca8-d7ae032c8de8
18 | let currentCourseName;
19 | let pjax;
20 |
21 | const Falcon = {
22 |
23 | start: () => {
24 | // loaded only once on page load (regular page load, no pjax)
25 | Falcon.onSuccess(false);
26 |
27 | pjax = new Pjax({
28 | elements: "a[href]:not(.Mrphs-sitesNav__dropdown):not(#loginLink1):not(.nopjax):not([target=_blank]):not(.attachment), form[action]:not(#Mrphs-xlogin):not(#loginForm):not(#dfCompose):not(#takeAssessmentForm):not(#compose):not(#msgForum):not(#prefs_pvt_form):not(#selectIndexForm)",
29 | cacheBust: false,
30 | debug: false,
31 | selectors: [
32 | "title",
33 | // "head",
34 | "meta[name=description]",
35 | ".Mrphs-pagebody",
36 | ".Mrphs-container--nav-tools",
37 | "#topnav_container",
38 | ],
39 | });
40 |
41 | document.addEventListener("pjax:success", Falcon.onSuccess)
42 | document.addEventListener('pjax:send', Falcon.onSend)
43 | document.addEventListener('pjax:complete', Falcon.onComplete)
44 |
45 | Falcon.setupTopbar();
46 |
47 | },
48 |
49 | setupTopbar: () => {
50 | topbar.config({
51 | autoRun: true,
52 | barThickness: 3,
53 | barColors: {
54 | '0': '#d900ff',
55 | '.3': '#7000ff',
56 | '1.0': '#d900ff'
57 | },
58 | shadowBlur: 5,
59 | shadowColor: 'rgba(0, 0, 0, .5)',
60 | className: 'topbar',
61 | });
62 | },
63 |
64 | onSend: () => {
65 | topbar.show();
66 | },
67 |
68 | // @runOnInit = do not run it on init (i.e on a regular page load and NOT from pjax success page load)
69 | onSuccess: (runOnInit = true) => {
70 |
71 | if (runOnInit) {
72 | FalconInterfaceInjector.initAnimations();
73 | }
74 | FalconInterfaceInjector.fixAssignmentLinks();
75 | FalconInterfaceInjector.setActiveClassToNavigation();
76 | FalconInterfaceInjector.replaceIcons();
77 | FalconInterfaceInjector.announcementPaginationButtonsFix();
78 | FalconInterfaceInjector.hideFavouritesBar();
79 |
80 | // FalconInterfaceInjector.welcomeMessageAlert();
81 | // FalconInterfaceInjector.falconAssignments();
82 |
83 | Falcon.saveCourseId();
84 |
85 | new TableSorter();
86 | new FalconDarkMode();
87 | new FalconCourseNameEditor();
88 | new FalconEditor(currentCourseId);
89 |
90 | new FalconFileManager(currentCourseId, currentCourseName);
91 | new FalconAnnouncement(currentCourseId);
92 | new FalconGradebook();
93 |
94 | new FalconAssignments(currentCourseId);
95 | Falcon.injectResources();
96 | // Needed to initiate the matchParser
97 |
98 |
99 | },
100 |
101 | onComplete: () => {
102 | topbar.hide();
103 | },
104 |
105 | saveCourseId() {
106 | let linkElement = $('.Mrphs-sitesNav__menuitem.is-selected a.link-container');
107 | if (linkElement.length) {
108 | currentCourseId = linkElement.attr('href').split('/').pop();
109 | currentCourseName = linkElement.attr('title');
110 | }
111 | },
112 |
113 | injectResources() {
114 |
115 | AssetInjector.once().owlAssets()
116 | .endOfHead()
117 | .injectScript('/library/js/spinner.js?version=20_2-owl1', 'owl-spinner-src')
118 | .injectScript('/sakai-assignment-tool/js/studentViewSubmission.js?version=20_2-owl1', 'owl-stdviewsubmission-src')
119 | .injectScript('/sakai-assignment-tool/js/assignments.js?version=20_2-owl1', 'owl-assignments-src')
120 | .injectScript('/library/js/mathjax/MathJax.js?config=default,Safe', 'falcon-mathjax')
121 | .injectScript('/gradebookng-tool/scripts/gradebook-grade-summary.js?version=20_2-owl1', 'falcon-gradebook-js')
122 | .injectStyle('/gradebookng-tool/styles/gradebook-grades.css?version=20_2-owl1', 'falcon-gradebook-css')
123 | .injectStyle('/gradebookng-tool/styles/gradebook-gbgrade-table.css?version=20_2-owl1', 'falcon-gradebook-table-css')
124 | .injectStyle('/messageforums-tool/css/msgcntr.css', 'falcon-forum-css')
125 | .injectRawHtml(``, 'falcon-math-jax-parser')
126 | .injectRawHtml(``, 'falcon-math-jax-config');
127 |
128 | // MathJax Parser
129 | $(document).ready(function () {
130 | location.href = "javascript:parseMath(); void 0"
131 | });
132 | }
133 | }
134 |
135 | export default Falcon;
136 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Falcon for OWL
2 |
3 |
4 |
5 | Falcon immensely enhances the user experience on OWL. With Falcon, OWL loads over **65% faster** on average. Falcon also improves the visual layout of OWL (including styling of buttons, forms, etc.) Falcon operates completely on the front-end and has no connection to the back-end.
6 |
7 | Falcon is available for install on
Google Chrome , and is coming soon for Mozilla Firefox and Safari.
8 |
9 |
10 |
11 |
12 | # Features
13 |
14 | ### Dark Mode
15 |
16 |
17 |
18 | -----
19 |
20 | ### Load pages without refreshing
21 |
22 | It will be much faster when you navigate OWL because a full refresh is not done every time you go to a new page. (This feature is disabled on Gradebook, Test/Quizzes, and Forum)
23 |
24 |
25 |
26 | -----
27 |
28 | ### Revamped Resources page
29 |
30 | The new resources page is extremely fast and offers an instant file-browsing experience. You can also search for any files or folders instantly. No more full-page refresh just to browse folders. And if for any reason you need to access the old resources system, you are just one click away.
31 |
32 |
33 |
34 | -----
35 |
36 | ### Edit course names
37 |
38 | Especially useful when you're just starting a new semester, and you're not used to the course codes yet.
39 |
40 |
41 |
42 | -----
43 |
44 | ### New Announcements Experience
45 |
46 | Scroll through all your announcements at once like it's your personal feed.
47 |
48 |
49 |
50 | -----
51 |
52 | ### Powerful New Editor
53 |
54 | Falcon includes a new editor which you can use to create flow charts, diagrams, and more. Each course gets its own editor, and changes are saved instantly. You can also export your diagrams as PNG, JPG or SVG.
55 |
56 |
57 |
58 | -----
59 |
60 | ### Instant Search & Sorting of Announcements, Assignments, etc
61 |
62 | OWL offers sorting of announcements, assignments, etc. but it takes a *full* page refresh just to sort, making it an awful experience. Falcon sorts *instantly*. Falcon also allows you to search tables, too.
63 |
64 |
65 |
66 | ----
67 |
68 | Of course, the features listed here are the main features you can visually interact with / see on OWL. There are many minor enhancements to OWL itself that Falcon makes that improves the user experience. One of which is a more modern and updated look without taking away from the OWL you are familiar with.
69 |
70 | # Installation
71 | Falcon is available on the
Chrome Web Store for easy install.
72 |
73 | 1. Go to the
releases page and download the latest version, and extract it
74 | 2. Go to `chrome://extensions` and toggle on `Developer Mode` on the top right
75 | 3. On the same page, you should now see three new buttons. Click on the `Load unpacked` button and select `dist/chrome` from the extracted directory
76 | 4. That's it! Falcon is now running!
77 |
78 | If there are any updates, then you will need to reinstall it manually. However, once it's available on the Chrome store, updating Falcon is just like updating any other Chrome extensions.
79 |
80 | # Security Notice
81 | Falcon was built with security in mind. Using Falcon does not compromise the security of OWL. In fact, it enhances certain security elements of OWL, particularly in the case of POST-based browsing.
82 |
83 | Falcon works on top of OWL, and it makes no external requests to any external endpoints (with the exception of asset files). Falcon also does not collect any inputs, form data, session data, or any other relevant information. You are free to inspect the source code!
84 |
85 |
86 | # Run into issues?
87 | If you encounter any issues that prevent you from using OWL normally, please disable or uninstall Falcon until it is fixed.
88 |
89 | If you run into any issues, then I'd really appreciate it if you could either create a
new issue here or email me at swift@hey.com.
90 |
91 |
92 | # Contribution
93 | Feel free to fork Falcon and create a pull request!
94 |
95 | Contribution can be anything from fixing spelling mistakes to implementing new features.
96 |
97 | Some tips to help you get started:
98 | - Ensure you have
node.js and NPM installed.
99 | - While developing, you will need to build it and load it in chrome manually. i.e. run `npm run dev` from the base directory. It will create a new `dist` directory with folders for `chrome` and `firefox`.
100 | - It may be cumbersome to type in `npm run dev` every time you make any changes. You can use the `npm run watch` command to automatically compile the source code upon any change.
101 | - Use Falcon's API for fluid development
102 | - `AssetInjector` for injecting resources to any page (including `iframes`)
103 | - `FalconStorage` for saving / querying user's data
104 | - `FalconInterfaceInjector` to save and inject elements on any page
105 |
106 |
107 | If you have any questions, ideas, or concerns, please send them over to swift@hey.com or create a
new issue .
108 |
109 |
110 | # License
111 |
112 | See [LICENSE](/LICENSE.md) for more information.
113 |
--------------------------------------------------------------------------------
/src/services/announcement.js:
--------------------------------------------------------------------------------
1 | import FalconInterfaceInjector from "../ui/ui-injector";
2 | import Core from "./core";
3 | import Falcon from "./falcon";
4 | import FalconDarkMode from "./dark-mode";
5 |
6 | class FalconAnnouncement {
7 |
8 | API_URL = 'https://owl.uwo.ca/direct/announcement/site/';
9 | courseId;
10 |
11 | constructor(courseId) {
12 | this.courseId = courseId;
13 |
14 | // if currently on announcements page... and not on the user home page...
15 | if (FalconInterfaceInjector.pageContainsElement('form[name=announcementListForm]') && !FalconInterfaceInjector.urlContainsText('~')) {
16 |
17 | FalconInterfaceInjector.falconAnnouncementsSetup();
18 | this.addEventListeners();
19 |
20 | this.fetch();
21 | }
22 | }
23 |
24 | // because we have set the announcement form to be hidden by default... fix it so it's not hidden in dark mode..
25 | // and also fix the colors
26 | static fixDarkModeAnnouncement() {
27 | $('#falcon-announcements [style*="color"]').css('color', '');
28 | $('#falcon-announcements [style*="background-color"]').css('background-color', '');
29 | $('#falcon-announcements [style*="background"]').css('background-color', '');
30 | $('#falcon-announcements [style*="border-bottom"]').css('border-color', '#393d3d');
31 | $('#falcon-announcements [style*="border"]').css('border-color', '#393d3d');
32 | }
33 |
34 | // both light and dark mode...
35 | static fixAnnouncement() {
36 | $('#falcon-announcements [style*="font-size"]').css('font-size', '');
37 | $('#falcon-announcements [style*="font-family"]').css('font-family', '');
38 | }
39 |
40 | addEventListeners() {
41 |
42 | let showOriginal = false;
43 |
44 | let ogAnnouncementsElem = $('form[name="announcementListForm"]');
45 |
46 | $('#toggle-announcements-viewer').on('click', function () {
47 | if (showOriginal) {
48 | $('#falcon-announcements').fadeIn();
49 | ogAnnouncementsElem.hide();
50 | showOriginal = false;
51 | $(this).html('Classic Viewer');
52 |
53 | } else {
54 | $('#falcon-announcements').hide();
55 | ogAnnouncementsElem.fadeIn();
56 | showOriginal = true;
57 | $(this).html('Falcon Viewer');
58 | }
59 | })
60 | }
61 |
62 | fetch() {
63 | let url = `${this.API_URL}/${this.courseId}.json?n=120`;
64 |
65 | fetch(url)
66 | .then(response => response.json())
67 | .then(response => {
68 | this.setupAnnouncements(response.announcement_collection);
69 | }).then(() => {
70 | if (FalconDarkMode.isDarkModeEnabled()) {
71 | FalconAnnouncement.fixDarkModeAnnouncement();
72 | }
73 | FalconAnnouncement.fixAnnouncement();
74 | })
75 | }
76 |
77 | setupAnnouncements(announcements) {
78 | let announcementElem = $('#falcon-announcements');
79 | announcementElem.html('');
80 |
81 | if (!announcements.length) {
82 | return;
83 | }
84 | for (let announcement of announcements) {
85 | this.insertAnnouncement(announcement);
86 | }
87 |
88 |
89 | // Fix the dark mode...
90 | }
91 |
92 | getAttachments(announcement) {
93 |
94 | let attachments = announcement.attachments;
95 |
96 | if (!attachments.length) {
97 | return [];
98 | }
99 |
100 | let allAttachments = [];
101 | for (let attachment of attachments) {
102 | allAttachments.push({
103 | name: attachment.name,
104 | url: attachment.url,
105 | type: attachment.type,
106 | });
107 | }
108 |
109 | return allAttachments;
110 | }
111 |
112 | renderAttachments(attachments) {
113 | if (!attachments.length) {
114 | return "";
115 | }
116 | let html = '
';
117 | for (let i = 0; i < attachments.length; i++) {
118 | let isImage = attachments[i].type.includes('image/');
119 | let isPdf = attachments[i].type.includes('application/pdf');
120 | let icon = isImage ? 'fe fe-image' : (isPdf ? 'fa fa-file-pdf-o' : 'fe fe-file');
121 | html += `
${attachments[i].name}`
122 |
123 | if (i !== attachments.length - 1) {
124 | html += `
· `
125 | }
126 | }
127 | html += "
";
128 | return html;
129 | }
130 |
131 | insertAnnouncement(announcement) {
132 |
133 | let attachments = this.getAttachments(announcement);
134 | let attachmentElem = this.renderAttachments(attachments);
135 |
136 | let time = new Date(announcement.createdOn);
137 | let announcementElem = $('#falcon-announcements');
138 | $(`
139 |
140 |
141 |
147 |
148 | ${announcement.body}
149 | ${attachmentElem}
150 |
151 |
152 | `).appendTo(announcementElem)
153 | }
154 |
155 | }
156 |
157 | export default FalconAnnouncement;
158 |
--------------------------------------------------------------------------------
/src/services/falcon-editor.js:
--------------------------------------------------------------------------------
1 | import FalconStorage from "./storage";
2 | import FalconInterfaceInjector from "../ui/ui-injector";
3 | import config from "devextreme/core/config";
4 | import Diagram from "devextreme/ui/diagram";
5 |
6 | class FalconEditor {
7 |
8 | STORAGE_KEY = 'falconEditor';
9 | uiEditor;
10 | falconEditor = []; // array of all diagrams from all courses
11 | currentCourse;
12 |
13 | constructor(currentCourse) {
14 | this.currentCourse = currentCourse;
15 | FalconInterfaceInjector.falconEditorButton();
16 | this.addEventListeners();
17 | }
18 |
19 | addEventListeners() {
20 | let isOpen = false;
21 | let self = this;
22 |
23 | if (!isOpen) {
24 | cleanupEditor();
25 | }
26 |
27 | $('#falcon-editor-button').on('click', function () {
28 | $('#falcon-editor-icon').addClass('fa-spin fe-loader').removeClass('fe-edit-2 fe-x');
29 | if (isOpen) {
30 | $('#falcon-editor-title').html('Saving...');
31 | self.saveFalconEdits(self.uiEditor.export()).then(item => {
32 | $('#falcon-editor-title').html('Saved!');
33 | })
34 | }
35 |
36 | // Async to prevent from the slight freeze up
37 | setTimeout(function () {
38 | isOpen = !isOpen;
39 | if (isOpen) {
40 | $('.Mrphs-pagebody').hide();
41 | $('a.Mrphs-toolsNav__menuitem--link').not('#falcon-editor-button').parent().hide();
42 | $('#falcon-editor-title').html('Close Editor');
43 | $('#falcon-editor-icon').removeClass('fa-spin fe-loader fe-edit-2').addClass('fe-x')
44 | $('#pageBody').append(`
`)
45 | self.setupEditor();
46 | self.getEditorDataFromStorage();
47 | } else {
48 | cleanupEditor();
49 | }
50 | }, 0)
51 | })
52 |
53 | function cleanupEditor() {
54 | $('#falcon-editor-title').html('Falcon Editor');
55 | $('a.Mrphs-toolsNav__menuitem--link').not('#falcon-editor-button').parent().show();
56 | $('#falcon-editor-icon').removeClass('fa-spin fe-loader fe-x').addClass('fe-edit-2')
57 | $('#falcon-editor-diagram').remove();
58 | $('.Mrphs-pagebody').show();
59 | }
60 | }
61 |
62 | setupEditor() {
63 | let autoSaveIntervalMs = 2000;
64 | let autoSaveTimeout = -1;
65 |
66 | let self = this;
67 |
68 | this.uiEditor = new Diagram(document.getElementById("falcon-editor-diagram"), {
69 |
70 | "height": function () {
71 | return window.innerHeight / 1.1;
72 | },
73 | "nodes": {
74 | "autoLayout": {
75 | "orientation": "horizontal"
76 | }
77 | },
78 | propertiesPanel: {
79 | visibility: 'disabled',
80 | },
81 | "simpleView": true,
82 | "toolbox": {
83 | "visible": true
84 | },
85 | historyToolbar: {
86 | visible: false
87 | },
88 | mainToolbar: {
89 | visible: true,
90 | },
91 |
92 | onOptionChanged: function (e) {
93 | if (e.name === "hasChanges" && e.value && autoSaveTimeout === -1) {
94 |
95 | autoSaveTimeout = setTimeout(function () {
96 | let data = e.component.export();
97 | console.log(data);
98 | autoSaveTimeout = -1;
99 | self.saveFalconEdits(data).then(function () {
100 | e.component.option("hasChanges", false);
101 | });
102 |
103 | }, autoSaveIntervalMs);
104 | }
105 | },
106 |
107 | "width": '100%'
108 | });
109 | }
110 |
111 |
112 | saveFalconEdits(data) {
113 | let exists = FalconStorage.existsInStorage(this.falconEditor, 'courseName', this.currentCourse);
114 | if (exists) {
115 | this.falconEditor.map((item => {
116 | if (item.courseName === this.currentCourse) {
117 | return item.diagramData = data;
118 | }
119 | return item;
120 | }));
121 | } else {
122 | this.falconEditor.push({
123 | courseName: this.currentCourse,
124 | diagramData: data
125 | })
126 | }
127 |
128 | return FalconStorage.set({falconEditor: this.falconEditor})
129 | }
130 |
131 | async getEditorDataFromStorage() {
132 | let {falconEditor} = await FalconStorage.local().get(this.STORAGE_KEY);
133 | this.falconEditor = falconEditor;
134 |
135 | // if there's no data... it means that it's a new user visiting the falcon editor
136 | // populate it with default data and show them the welcome page
137 | // It's NOT saved in storage (because it's dummy data)
138 | if (!falconEditor) {
139 | this.falconEditor = [];
140 | this.importDataToEditor(this.defaultData());
141 | return;
142 | }
143 |
144 | let exists = FalconStorage.existsInStorage(falconEditor, 'courseName', this.currentCourse);
145 | if (exists) {
146 | let falconEdit = falconEditor.filter(item => {
147 | return item.courseName === this.currentCourse;
148 | })[0];
149 | this.importDataToEditor(falconEdit.diagramData);
150 | }
151 | }
152 |
153 | importDataToEditor(data) {
154 | this.uiEditor.import(data);
155 | }
156 |
157 | // Default falcon editor data
158 | defaultData() {
159 | return `{"page":{"width":16782,"height":23812,"pageColor":-1,"pageWidth":8391,"pageHeight":11906,"pageLandscape":false},"connectors":[{"key":"20","locked":false,"zIndex":0,"points":[{"x":9540,"y":10620},{"x":10980,"y":10620}],"style":{"stroke":"#e86048"},"beginItemKey":"6","beginConnectionPointIndex":1,"endItemKey":"5","endConnectionPointIndex":3},{"key":"21","locked":false,"zIndex":0,"points":[{"x":12960,"y":10620},{"x":14040,"y":10620}],"style":{"stroke":"#2d47b8"},"beginItemKey":"5","beginConnectionPointIndex":1,"endItemKey":"14","endConnectionPointIndex":3},{"key":"23","locked":false,"zIndex":0,"points":[{"x":11610,"y":16200},{"x":11610,"y":17100}],"style":{"stroke":"#fd513a"},"beginItemKey":"13","beginConnectionPointIndex":-1,"endItemKey":"3","endConnectionPointIndex":-1}],"shapes":[{"key":"3","dataKey":"d054a3b3-9b51-45a9-96cb-5b31e958c513","locked":false,"zIndex":0,"type":"heart","text":"Good\\nLuck ;)","x":9540,"y":16560,"width":4140,"height":3600,"style":{"fill":"#ce8898","stroke":"#ffffff"},"styleText":{"fill":"#a6414b","font-family":"Helvetica","font-size":"22pt","font-weight":"bold"}},{"key":"4","dataKey":"c33421dc-650b-4ace-89de-b0c9048d4e02","locked":false,"zIndex":0,"type":"rectangle","text":"Falcon Editor","x":7062,"y":8486,"width":9000,"height":900,"style":{"fill":"#6400ff","stroke":"#ffffff"},"styleText":{"fill":"#ffffff","font-family":"Helvetica","font-size":"28pt","font-weight":"bold"}},{"key":"5","dataKey":"d97730d1-3f1a-45b5-9b75-651fa3c90327","locked":false,"zIndex":0,"type":"ellipse","text":"Draw diagrams","x":10980,"y":9720,"width":1980.0000000000002,"height":1800,"style":{"fill":"#2d47b8","stroke":"#ffffff"},"styleText":{"fill":"#9ceee0","font-family":"Helvetica","font-size":"14pt","font-weight":"bold"}},{"key":"6","dataKey":"0463af6f-c987-4f2d-8069-9318cec6efd5","locked":false,"zIndex":0,"type":"ellipse","text":"Draw flow-charts","x":7560,"y":9720,"width":1980,"height":1800,"style":{"fill":"#e86048","stroke":"#ffffff"},"styleText":{"fill":"#d2efcf","font-family":"Helvetica","font-size":"14pt","font-weight":"bold"}},{"key":"13","locked":false,"zIndex":0,"type":"rectangle","text":"","x":7560,"y":11880,"width":8100,"height":4320,"style":{"fill":"#fd513a","stroke":"#ffffff"}},{"key":"14","locked":false,"zIndex":0,"type":"ellipse","text":"Brainstorm ideas","x":14040,"y":9720,"width":1980.0000000000002,"height":1800,"style":{"fill":"#34db6a","stroke":"#ffffff"},"styleText":{"fill":"#126551","font-family":"Helvetica","font-size":"14pt","font-weight":"bold"}},{"key":"16","locked":false,"zIndex":0,"type":"rectangle","text":"Each course has its own editor","x":8100,"y":12240,"width":7020,"height":1080,"style":{"fill":"#c9f1cd","stroke":"#c9f1cd"},"styleText":{"fill":"#fd513a","font-family":"Helvetica","font-size":"18pt","font-weight":"bold"}},{"key":"17","locked":false,"zIndex":0,"type":"rectangle","text":"You can export your diagrams as PNG, JPG and SVG","x":8100,"y":13500,"width":7020,"height":1080,"style":{"fill":"#cef563","stroke":"#cef563"},"styleText":{"fill":"#4202f5","font-family":"Helvetica","font-size":"18pt","font-weight":"bold"}},{"key":"18","locked":false,"zIndex":0,"type":"rectangle","text":"To get started, select all these elements and hit delete!","x":8100,"y":14760,"width":7020,"height":1080,"style":{"fill":"#c6e3c5","stroke":"#c6e3c5"},"styleText":{"fill":"#126551","font-family":"Helvetica","font-size":"18pt","font-weight":"bold"}}]}`;
160 | }
161 |
162 | }
163 |
164 | export default FalconEditor;
165 |
--------------------------------------------------------------------------------
/src/ui/ui-injector.js:
--------------------------------------------------------------------------------
1 | import $ from "jquery";
2 |
3 | const FalconInterfaceInjector = {
4 |
5 | darkModeButton: () => {
6 | let $dark_mode_button = ``;
7 | if ($('#dark-mode-toggle').length === 0) {
8 | $(".Mrphs-loginNav").prepend($dark_mode_button);
9 | }
10 | },
11 |
12 | falconEditorButton: () => {
13 | $('.Mrphs-toolsNav__menu ul').append(`
`)
14 | },
15 |
16 | welcomeMessageAlert: () => {
17 | $('.Mrphs-pagebody').prepend(`
18 |
19 |
Falcon is installed!
20 |
21 |
Thanks for installing Falcon!
22 |
Remember, Falcon does not know who you are, see your courses, or track how you use Falcon.
23 |
It is open-source , so you can provide feedback and even contribute!
24 |
25 |
Default Settings
26 |
Falcon has many great features, all of which are enabled by default. Select the ones you'd like enabled.
27 |
28 |
29 |
30 | Enable Falcon
31 |
32 |
33 | Falcon Resources - Entirely New Resources Page
34 |
35 | Falcon Editor - A brand new editor allows you to draw flow-charts, diagrams, and more.
36 |
37 | Custom Course Names - Customize your course names and avoid those ridicules long course codes.
38 |
39 | Custom Falcon Icons - Enable custom icons on the sidebar (notice how beautiful they look ;)
40 |
41 |
42 |
You can change these settings anytime from the top right corner: [Your Name] -> Falcon Settings
43 |
44 |
45 | `);
46 | },
47 |
48 |
49 | courseEditElements: () => {
50 | // only add this if user is logged in...
51 | // if it's not logged in, this element doesn't exist.
52 | if ($('#loginUser').length !== 1) {
53 | return;
54 | }
55 | let $courseNameEditModal = `
56 |
57 |
58 |
61 |
62 | Falcon allows you to give this course
ENGSCI 4498F 001 SP21 a custom name.
63 |
64 |
65 |
66 |
67 | Leave empty to reset to normal.
68 |
69 |
70 |
71 |
75 |
76 |
77 |
`
78 | if (!$('#edit-course-title-modal').length) {
79 | $(`
Edit `).insertBefore('.toolMenus')
80 | $('body').append($courseNameEditModal);
81 | }
82 | },
83 |
84 |
85 | falconResources: () => {
86 | if ($('.page-header h1').html() === 'Site Resources') {
87 | $(`
Classic Viewer
`).insertBefore($('.page-header h1'));
88 | $(`
`).insertAfter($('.page-header'));
89 | $('#showForm').hide();
90 | $(`
Loading resources...`).insertAfter('.page-header');
91 | }
92 | },
93 |
94 | // add is-selected to selected site...
95 | setActiveClassToNavigation: () => {
96 | $('.link-container').on('click', function () {
97 | $('.Mrphs-sitesNav__menuitem').removeClass('is-selected');
98 | $(this).parent().addClass('is-selected');
99 | })
100 | },
101 |
102 | falconAssignments: () => {
103 | // $('#listAssignmentsForm')
104 | let originalAssignmentForm = $('[name=listAssignmentsForm]');
105 |
106 | if (!originalAssignmentForm) {
107 | return;
108 | }
109 |
110 | let assignmentToolbar = originalAssignmentForm.siblings('.sakai-table-toolBar');
111 |
112 | if (!assignmentToolbar) {
113 | return;
114 | }
115 |
116 | $(`
Loading assignments...`).insertBefore(assignmentToolbar);
117 | },
118 |
119 | initAnimations: () => {
120 | $('.Mrphs-pagebody').addClass('animate__animated animate__fadeIn');
121 | $('#selectSiteModal').addClass('animate__animated animate__fadeIn');
122 | $('.Mrphs-userNav__subnav').addClass('animate__animated animate__fadeIn');
123 | },
124 |
125 | // replace all font-awesome icons with feather-icons
126 | replaceIcons() {
127 | let icons = {
128 | 'icon-sakai--sakai-iframe-site': 'fe fe-list',
129 | 'icon-sakai--sakai-syllabus': 'fe fe-map',
130 | 'icon-sakai--sakai-lessonbuildertool': 'fe fe-book',
131 | 'icon-sakai--sakai-samigo': 'fe fe-check-circle',
132 | 'fa fa-video-camera': 'fe fe-video',
133 | 'fa fa-play': 'fe fe-play',
134 | 'icon-sakai--sakai-siteinfo': 'fe fe-info',
135 | 'icon-sakai--sakai-gradebookng': 'fe fe-grid',
136 | 'icon-sakai--sakai-schedule': 'fe fe-calendar',
137 | 'icon-sakai--sakai-resources': 'fe fe-folder-plus',
138 | 'icon-sakai--sakai-web-168': 'fe fe-globe',
139 | 'icon-sakai--sakai-researchguideslti': 'fe fe-globe',
140 | 'icon-sakai--sakai-basiclti': 'fe fe-globe',
141 | 'icon-sakai--sakai-poll': 'fe fe-bar-chart-2',
142 | 'icon-sakai--sakai-messages': 'fe fe-inbox',
143 | 'icon-sakai--help': 'fe fe-help-circle',
144 | 'icon-sakai--sakai-assignment-grades': 'fe fe-file-text',
145 | 'icon-sakai--sakai-forums': 'fe fe-message-circle',
146 | 'fa fa-eye': 'fe fe-eye',
147 | 'fa fa-home': 'fe fe-home',
148 | 'icon-sakai--sakai-iframe': 'fe fe-globe',
149 | 'icon-sakai--sakai-signup': 'fe fe-user-plus',
150 | 'icon-sakai--sakai-dropbox': 'fe fe-upload-cloud',
151 | 'icon-sakai--sakai-singleuser': 'fe fe-user',
152 | 'icon-sakai--sakai-preferences': 'fe fe-settings',
153 | 'icon-sakai--sakai-sitesetup': 'fe fe-sliders',
154 | 'icon-sakai--sakai-membership': 'fe fe-users',
155 | 'icon-sakai--sakai-motd': 'fe fe-list',
156 | 'fa fa-print': 'fe fe-printer',
157 | 'fa fa-list-ul': 'fe fe-list',
158 | 'Mrphs-toolTitleNav__link--directurl': 'fe fe-link',
159 | 'Mrphs-toolTitleNav__link--help-popup': 'fe fe-help-circle',
160 | 'icon-sakai--sakai-resetpass': 'fe fe-more-horizontal',
161 | 'icon-sakai--sakai-sitebrowser': 'fe fe-globe'
162 | }
163 |
164 | // elements to check for and replace icons in
165 | let elements = [
166 | '.Mrphs-toolsNav__menuitem--icon',
167 | '.Mrphs-breadcrumb--icon',
168 | '.toolMenuIcon',
169 | ]
170 |
171 | elements.forEach(element => {
172 | let all = $(element);
173 | if (all.length > 0) {
174 | all.each(function () {
175 |
176 | Object.keys(icons).forEach(oldIcon => {
177 | if ($(this).hasClass(oldIcon)) {
178 | $(this).removeClass(oldIcon);
179 | $(this).addClass(icons[oldIcon]);
180 | }
181 | })
182 | })
183 |
184 | }
185 | })
186 |
187 | // share button
188 | $('.Mrphs-breadcrumb--reset-icon').removeClass('fa fa-share').addClass('fe fe-arrow-left');
189 | },
190 |
191 | announcementPaginationButtonsFix() {
192 | let order = [0, 1, 2];
193 | // ANNOUNCEMENTS click on next, previous, or return to list button.
194 | $('input[name="eventSubmit_doPrev_message"]').on('click', function () {
195 | order = [0, 1, 2];
196 | switchUp();
197 | })
198 |
199 | $('input[name="eventSubmit_doLinkcancel"]').on('click', function () {
200 | order = [1, 0, 2];
201 | switchUp();
202 | })
203 |
204 | $('input[name="eventSubmit_doNext_message"]').on('click', function () {
205 | order = [2, 0, 1];
206 | switchUp();
207 | })
208 |
209 | function switchUp() {
210 | var wrapper = $('.itemNav'),
211 | items = wrapper.children('input');
212 | wrapper.append($.map(order, function (v) {
213 | return items[v]
214 | }));
215 | wrapper.hide();
216 | }
217 | },
218 |
219 | falconAnnouncementsSetup() {
220 | $(`
Loading Announcements... `).insertAfter($('.page-header'));
221 | $(`
Classic Viewer `).insertBefore($('.page-header h1'));
222 | this.removeToolbar();
223 | this.hideElement($('form[name="announcementListForm"]'))
224 | },
225 |
226 | removeToolbar() {
227 | this.removeElement($('.sakai-table-toolBar'));
228 | },
229 |
230 | removeElement(element) {
231 | $(element).remove();
232 | },
233 |
234 | hideElement(element) {
235 | $(element).hide();
236 | },
237 |
238 | showElement(element) {
239 | $(element).hide();
240 | },
241 |
242 | // if favourites bar is open and user clicks on anything which navigates away from a page, it should close
243 | hideFavouritesBar() {
244 | if (!$('#selectSiteModal').hasClass('outscreen')) {
245 | $('.view-all-sites-btn').click();
246 | }
247 | },
248 |
249 | // Fix attachments from opening in the same page...
250 | fixAssignmentLinks() {
251 | if ($('ul.attachList li a').length === 0) {
252 | return;
253 | }
254 |
255 | $('ul.attachList li a').each(function() {
256 | $(this).addClass('nopjax');
257 | })
258 | },
259 |
260 | // determine if the current page title in UI matches
261 | isCurrentPageTitle(title, elem = '.page-header h1') {
262 | return $(elem).text().includes(title);
263 | },
264 |
265 | pageContainsElement(elem) {
266 | return !! $(elem).length;
267 | },
268 |
269 | urlContainsText(text) {
270 | return window.location.href.indexOf(text) > -1;
271 | }
272 |
273 |
274 | }
275 |
276 | export default FalconInterfaceInjector;
277 |
--------------------------------------------------------------------------------
/src/services/file-manager.js:
--------------------------------------------------------------------------------
1 | import FalconStorage from "./storage";
2 | import FalconInterfaceInjector from "../ui/ui-injector";
3 | import FileManager from "devextreme/ui/file_manager";
4 | import TextBox from "devextreme/ui/text_box";
5 | import PopUp from "devextreme/ui/popup";
6 |
7 | class FalconFileManager {
8 |
9 | API_URL = 'https://owl.uwo.ca/direct/content/site/';
10 | CACHE_TTL = 10 * 60 * 1000; // 10 minutes
11 | STORAGE_KEY = 'falconResources';
12 |
13 | forceRecache = false;
14 | falconResources = []; // all resources from all courses
15 |
16 | searchString = '';
17 |
18 | falconFileManager;
19 |
20 | constructor(courseId, courseName) {
21 | this.currentCourse = courseName; // The original Course Name
22 | this.courseId = courseId; // current course ID in format 39cbafa5-fa7b-4a18-8ca8-d7ae032c8de8
23 |
24 | FalconInterfaceInjector.falconResources();
25 | this.addEventListeners();
26 | }
27 |
28 | addEventListeners() {
29 | let showOriginal = false;
30 | let self = this;
31 |
32 | $('#toggle-original-resource').on('click', function () {
33 | if (showOriginal) {
34 | $('#showForm').hide();
35 | $('#file-manager-container').fadeIn();
36 | showOriginal = false;
37 | $(this).html('Classic Viewer');
38 |
39 | } else {
40 | $('#showForm').fadeIn();
41 | $('#file-manager-container').hide();
42 | showOriginal = true;
43 | $(this).html('Falcon Viewer');
44 | }
45 | })
46 |
47 | setTimeout(function () {
48 | self.setupResources().then(() => {
49 | $('#loading-resources').remove();
50 | });
51 | }, 0)
52 |
53 | }
54 |
55 | forceRefresh() {
56 | this.forceRecache = true;
57 | return this;
58 | }
59 |
60 |
61 | async setupResources() {
62 |
63 | let result = await this.getResourcesForCourse();
64 |
65 | function searchResources(searchText) {
66 | const localData = [...result];
67 |
68 | function getValueLogic(result, searchText) {
69 | searchText = searchText.toLowerCase();
70 | const arr = [];
71 | if (result && Array.isArray(result)) {
72 | for (let i = 0; i < result.length; i++) {
73 | const ele = result[i];
74 | ele && ele.name.toLowerCase().includes(searchText)
75 | ? arr.push(ele)
76 | : arr.push(...getValueLogic(ele.items, searchText));
77 | }
78 | }
79 | return arr;
80 | }
81 |
82 | return getValueLogic(localData, searchText);
83 | }
84 |
85 | // make sure we have the element
86 | if ($('#file-manager').length === 0) {
87 | return;
88 | }
89 |
90 | var popup = new PopUp('#photo-popup');
91 |
92 | let self = this;
93 |
94 | let falconFileManager = new FileManager(document.getElementById('file-manager'), {
95 | name: "fileManager",
96 | fileSystemProvider: result,
97 | rootFolderName: "Falcon",
98 | selectionMode: "single",
99 | currentPath: this.currentCourse,
100 | contextMenu: {
101 | items: [
102 | {
103 | text: 'Download',
104 | icon: 'download',
105 | },
106 | {
107 | name: "refresh",
108 | beginGroup: true
109 | }
110 | ]
111 | },
112 | height: function () {
113 | return window.innerHeight / 1.5;
114 | },
115 | permissions: {
116 | download: false,
117 | },
118 | onSelectedFileOpened: function (e) {
119 | if (isImage(e.file.dataItem.mimeType)) {
120 | popup.option({
121 | "title": e.file.name,
122 | "contentTemplate": `
`,
123 | });
124 |
125 | popup.show();
126 | } else {
127 | openFileInNewTab(e.file.dataItem.url);
128 | }
129 | },
130 | onContextMenuItemClick: onItemClick,
131 | toolbar: {
132 | items: [
133 | {
134 | name: "showNavPane",
135 | visible: true
136 | },
137 | 'refresh', 'separator',
138 | 'switchView',
139 | ],
140 |
141 |
142 | },
143 | itemView: {
144 | details: {
145 | columns: [
146 | "thumbnail",
147 | "name",
148 | {
149 | dataField: "size",
150 | caption: "Size",
151 | width: 'auto',
152 | },
153 | {
154 | dataField: "modified_at",
155 | caption: "Last Modified",
156 | width: 'auto',
157 | dataType: 'date',
158 |
159 | },
160 | {
161 | dataField: "created_by",
162 | caption: "Created By",
163 | width: 'auto',
164 | },
165 |
166 |
167 | ]
168 | }
169 | },
170 | });
171 |
172 | new TextBox('#file-manager-search', {
173 | placeholder: 'Search...',
174 | width: '300px',
175 | showClearButton: true,
176 | valueChangeEvent: "keyup",
177 | onValueChanged: function (event) {
178 |
179 |
180 | let searchResult;
181 | if (event.value === '' || !event.value) {
182 | searchResult = result;
183 | } else {
184 | self.searchString = event.value;
185 | searchResult = searchResources(self.searchString);
186 | }
187 | setTimeout(function () {
188 | falconFileManager.option('fileSystemProvider', searchResult);
189 | }, 500);
190 | },
191 | })
192 |
193 | // Whenever an item is (double) clicked, download it
194 | function onItemClick(args) {
195 | let url = args.fileSystemItem.dataItem.url;
196 | // they wanna download
197 | if (args.itemData.text === 'Download') {
198 | if (url) {
199 | download(url);
200 | }
201 | }
202 | }
203 |
204 | function openFileInNewTab(url) {
205 | window.open(url, '_blank');
206 | }
207 |
208 | function isImage(mimeType) {
209 | return mimeType.split('/')[0] === 'image'; //returns true or false
210 | }
211 |
212 | function download(url) {
213 | let a = document.createElement("a");
214 | a.href = url;
215 | a.download = '';
216 | a.click();
217 | }
218 |
219 | // https://stackoverflow.com/questions/1909441/how-to-delay-the-keyup-handler-until-the-user-stops-typing
220 | function delay(callback, ms) {
221 | var timer = 0;
222 | return function () {
223 | var context = this, args = arguments;
224 | clearTimeout(timer);
225 | timer = setTimeout(function () {
226 | callback.apply(context, args);
227 | }, ms || 0);
228 | };
229 | }
230 |
231 | }
232 |
233 | // Get resources
234 | async getResourcesForCourse() {
235 |
236 | let falconResources = await this.getResources();
237 |
238 | let data;
239 |
240 | // if we don't have any resources saved... or we want to RE-CACHE it
241 | if (!falconResources || this.forceRecache) {
242 | this.forceRecache = false;
243 | data = await this.fetchResourcesForCourse();
244 | return data;
245 | }
246 |
247 | let exists = FalconStorage.existsInStorage(falconResources, 'courseId', this.courseId);
248 |
249 | if (!exists) {
250 | data = await this.fetchResourcesForCourse();
251 | return data;
252 | }
253 |
254 | // if exists
255 | let falconResource = falconResources.filter(item => {
256 | return item.courseId === this.courseId;
257 | })[0];
258 |
259 | // make sure it's not older than TTL... otherwise re-fetch
260 | if (this.isExpired(falconResource)) {
261 | data = await this.fetchResourcesForCourse();
262 | return data;
263 | }
264 |
265 | return falconResource.courses;
266 |
267 | }
268 |
269 | async getResources() {
270 | // first check the local storage...
271 | let {falconResources} = await FalconStorage.local().get(this.STORAGE_KEY)
272 |
273 | // if it doesn't exist at all... then we haven't set anything in the local storage
274 | if (!falconResources) {
275 | return false;
276 | }
277 |
278 | return falconResources;
279 | }
280 |
281 | async saveResources(data) {
282 |
283 | // let {falconResources} = await this.getResources();
284 | //
285 |
286 | let currentTimeInMillis = (new Date()).getTime();
287 | let exists = FalconStorage.existsInStorage(this.falconResources, 'courseId', this.courseId);
288 |
289 | // if it exists... update it..
290 | if (exists) {
291 | this.falconResources.map(item => {
292 | if (item.courseId === this.courseId) {
293 | item.courses = data;
294 | item.lastFetched = currentTimeInMillis;
295 | return item;
296 | }
297 | return item;
298 | })
299 | } else {
300 | // otherwise, add a new record
301 | this.falconResources.push({
302 | courseName: this.currentCourse,
303 | courseId: this.courseId,
304 | courses: data,
305 | lastFetched: currentTimeInMillis
306 | })
307 | }
308 |
309 | // and save it in storage
310 | return FalconStorage.local().set({falconResources: this.falconResources});
311 | }
312 |
313 | isExpired(falconResource) {
314 | return new Date() - new Date(falconResource.lastFetched) > this.CACHE_TTL
315 | }
316 |
317 | async fetchResourcesForCourse() {
318 | let file;
319 | await fetch(this.API_URL + this.courseId + '.json')
320 | .then(response => response.json())
321 | .then(json => {
322 | file = json;
323 | });
324 |
325 | if (file) {
326 | let data = this.parseRawFileDataIntoTree(file.content_collection);
327 | await this.saveResources(data);
328 | return data;
329 | }
330 | }
331 |
332 | // save the cache of the file manager...
333 | saveCache() {
334 |
335 | }
336 |
337 | parseRawFileDataIntoTree(rawFileStructure) {
338 |
339 | // final file structure result
340 | let result = [];
341 |
342 | let level = {result};
343 |
344 | rawFileStructure.forEach(file => {
345 | let rawFilePath;
346 | if (file.type === 'collection') {
347 | rawFilePath = decodeURIComponent(file.url.slice(0, -1)).split('/');
348 | } else {
349 | rawFilePath = decodeURIComponent(file.url).split('/');
350 | }
351 | rawFilePath = rawFilePath.splice(6);
352 | rawFilePath[0] = this.currentCourse;
353 | rawFilePath = rawFilePath.join('/');
354 |
355 | let dateString = file.modifiedDate.substr(0, 8);
356 | let year = dateString.substring(0, 4);
357 | let month = dateString.substring(4, 6);
358 | let day = dateString.substring(6, 8);
359 | let date = new Date(year, month - 1, day).toLocaleString('en-us', {month: 'long', year: 'numeric', day: 'numeric'});
360 |
361 | let path = rawFilePath;
362 |
363 | let sharedDataToShow = { //TODO Fix
364 | modified_at: date,
365 | created_by: file.author,
366 | }
367 |
368 | path.split('/').reduce((r, name, i, a) => {
369 | if (!r[name]) {
370 | r[name] = {result: []};
371 | if (file.type === 'collection') {
372 | r.result.push({name, isDirectory: true, modified_at: date, size: file.size, created_by: file.author, items: r[name].result})
373 | } else {
374 | r.result.push({name, url: file.url, mimeType: file.type, modified_at: date, created_by: file.author, size: file.size, items: r[name].result})
375 |
376 | }
377 | }
378 | return r[name];
379 | }, level)
380 | })
381 |
382 | return result;
383 | }
384 |
385 |
386 | }
387 |
388 | export default FalconFileManager;
389 |
--------------------------------------------------------------------------------
/src/assets/fonts/feather.scss:
--------------------------------------------------------------------------------
1 | @font-face {
2 | font-family: 'Feather';
3 | src:
4 | url('#{$urlPath}/fonts/Feather.ttf?sdxovp') format('truetype'),
5 | url('#{$urlPath}/fonts/Feather.woff?sdxovp') format('woff'),
6 | url('#{$urlPath}/fonts/Feather.svg?sdxovp#Feather') format('svg');
7 | font-weight: normal;
8 | font-style: normal;
9 | }
10 |
11 | .fe {
12 | /* use !important to prevent issues with browser extensions that change fonts */
13 | font-family: 'Feather' !important;
14 | speak: none;
15 | font-style: normal;
16 | font-weight: normal;
17 | font-variant: normal;
18 | text-transform: none;
19 | line-height: 1;
20 |
21 | /* Better Font Rendering =========== */
22 | -webkit-font-smoothing: antialiased;
23 | -moz-osx-font-smoothing: grayscale;
24 | }
25 |
26 | .fe-activity:before {
27 | content: "\e900";
28 | }
29 | .fe-airplay:before {
30 | content: "\e901";
31 | }
32 | .fe-alert-circle:before {
33 | content: "\e902";
34 | }
35 | .fe-alert-octagon:before {
36 | content: "\e903";
37 | }
38 | .fe-alert-triangle:before {
39 | content: "\e904";
40 | }
41 | .fe-align-center:before {
42 | content: "\e905";
43 | }
44 | .fe-align-justify:before {
45 | content: "\e906";
46 | }
47 | .fe-align-left:before {
48 | content: "\e907";
49 | }
50 | .fe-align-right:before {
51 | content: "\e908";
52 | }
53 | .fe-anchor:before {
54 | content: "\e909";
55 | }
56 | .fe-aperture:before {
57 | content: "\e90a";
58 | }
59 | .fe-archive:before {
60 | content: "\e90b";
61 | }
62 | .fe-arrow-down:before {
63 | content: "\e90c";
64 | }
65 | .fe-arrow-down-circle:before {
66 | content: "\e90d";
67 | }
68 | .fe-arrow-down-left:before {
69 | content: "\e90e";
70 | }
71 | .fe-arrow-down-right:before {
72 | content: "\e90f";
73 | }
74 | .fe-arrow-left:before {
75 | content: "\e910";
76 | }
77 | .fe-arrow-left-circle:before {
78 | content: "\e911";
79 | }
80 | .fe-arrow-right:before {
81 | content: "\e912";
82 | }
83 | .fe-arrow-right-circle:before {
84 | content: "\e913";
85 | }
86 | .fe-arrow-up:before {
87 | content: "\e914";
88 | }
89 | .fe-arrow-up-circle:before {
90 | content: "\e915";
91 | }
92 | .fe-arrow-up-left:before {
93 | content: "\e916";
94 | }
95 | .fe-arrow-up-right:before {
96 | content: "\e917";
97 | }
98 | .fe-at-sign:before {
99 | content: "\e918";
100 | }
101 | .fe-award:before {
102 | content: "\e919";
103 | }
104 | .fe-bar-chart:before {
105 | content: "\e91a";
106 | }
107 | .fe-bar-chart-2:before {
108 | content: "\e91b";
109 | }
110 | .fe-battery:before {
111 | content: "\e91c";
112 | }
113 | .fe-battery-charging:before {
114 | content: "\e91d";
115 | }
116 | .fe-bell:before {
117 | content: "\e91e";
118 | }
119 | .fe-bell-off:before {
120 | content: "\e91f";
121 | }
122 | .fe-bluetooth:before {
123 | content: "\e920";
124 | }
125 | .fe-bold:before {
126 | content: "\e921";
127 | }
128 | .fe-book:before {
129 | content: "\e922";
130 | }
131 | .fe-book-open:before {
132 | content: "\e923";
133 | }
134 | .fe-bookmark:before {
135 | content: "\e924";
136 | }
137 | .fe-box:before {
138 | content: "\e925";
139 | }
140 | .fe-briefcase:before {
141 | content: "\e926";
142 | }
143 | .fe-calendar:before {
144 | content: "\e927";
145 | }
146 | .fe-camera:before {
147 | content: "\e928";
148 | }
149 | .fe-camera-off:before {
150 | content: "\e929";
151 | }
152 | .fe-cast:before {
153 | content: "\e92a";
154 | }
155 | .fe-check:before {
156 | content: "\e92b";
157 | }
158 | .fe-check-circle:before {
159 | content: "\e92c";
160 | }
161 | .fe-check-square:before {
162 | content: "\e92d";
163 | }
164 | .fe-chevron-down:before {
165 | content: "\e92e";
166 | }
167 | .fe-chevron-left:before {
168 | content: "\e92f";
169 | }
170 | .fe-chevron-right:before {
171 | content: "\e930";
172 | }
173 | .fe-chevron-up:before {
174 | content: "\e931";
175 | }
176 | .fe-chevrons-down:before {
177 | content: "\e932";
178 | }
179 | .fe-chevrons-left:before {
180 | content: "\e933";
181 | }
182 | .fe-chevrons-right:before {
183 | content: "\e934";
184 | }
185 | .fe-chevrons-up:before {
186 | content: "\e935";
187 | }
188 | .fe-chrome:before {
189 | content: "\e936";
190 | }
191 | .fe-circle:before {
192 | content: "\e937";
193 | }
194 | .fe-clipboard:before {
195 | content: "\e938";
196 | }
197 | .fe-clock:before {
198 | content: "\e939";
199 | }
200 | .fe-cloud:before {
201 | content: "\e93a";
202 | }
203 | .fe-cloud-drizzle:before {
204 | content: "\e93b";
205 | }
206 | .fe-cloud-lightning:before {
207 | content: "\e93c";
208 | }
209 | .fe-cloud-off:before {
210 | content: "\e93d";
211 | }
212 | .fe-cloud-rain:before {
213 | content: "\e93e";
214 | }
215 | .fe-cloud-snow:before {
216 | content: "\e93f";
217 | }
218 | .fe-code:before {
219 | content: "\e940";
220 | }
221 | .fe-codepen:before {
222 | content: "\e941";
223 | }
224 | .fe-command:before {
225 | content: "\e942";
226 | }
227 | .fe-compass:before {
228 | content: "\e943";
229 | }
230 | .fe-copy:before {
231 | content: "\e944";
232 | }
233 | .fe-corner-down-left:before {
234 | content: "\e945";
235 | }
236 | .fe-corner-down-right:before {
237 | content: "\e946";
238 | }
239 | .fe-corner-left-down:before {
240 | content: "\e947";
241 | }
242 | .fe-corner-left-up:before {
243 | content: "\e948";
244 | }
245 | .fe-corner-right-down:before {
246 | content: "\e949";
247 | }
248 | .fe-corner-right-up:before {
249 | content: "\e94a";
250 | }
251 | .fe-corner-up-left:before {
252 | content: "\e94b";
253 | }
254 | .fe-corner-up-right:before {
255 | content: "\e94c";
256 | }
257 | .fe-cpu:before {
258 | content: "\e94d";
259 | }
260 | .fe-credit-card:before {
261 | content: "\e94e";
262 | }
263 | .fe-crop:before {
264 | content: "\e94f";
265 | }
266 | .fe-crosshair:before {
267 | content: "\e950";
268 | }
269 | .fe-database:before {
270 | content: "\e951";
271 | }
272 | .fe-delete:before {
273 | content: "\e952";
274 | }
275 | .fe-disc:before {
276 | content: "\e953";
277 | }
278 | .fe-dollar-sign:before {
279 | content: "\e954";
280 | }
281 | .fe-download:before {
282 | content: "\e955";
283 | }
284 | .fe-download-cloud:before {
285 | content: "\e956";
286 | }
287 | .fe-droplet:before {
288 | content: "\e957";
289 | }
290 | .fe-edit:before {
291 | content: "\e958";
292 | }
293 | .fe-edit-2:before {
294 | content: "\e959";
295 | }
296 | .fe-edit-3:before {
297 | content: "\e95a";
298 | }
299 | .fe-external-link:before {
300 | content: "\e95b";
301 | }
302 | .fe-eye:before {
303 | content: "\e95c";
304 | }
305 | .fe-eye-off:before {
306 | content: "\e95d";
307 | }
308 | .fe-facebook:before {
309 | content: "\e95e";
310 | }
311 | .fe-fast-forward:before {
312 | content: "\e95f";
313 | }
314 | .fe-feather:before {
315 | content: "\e960";
316 | }
317 | .fe-file:before {
318 | content: "\e961";
319 | }
320 | .fe-file-minus:before {
321 | content: "\e962";
322 | }
323 | .fe-file-plus:before {
324 | content: "\e963";
325 | }
326 | .fe-file-text:before {
327 | content: "\e964";
328 | }
329 | .fe-film:before {
330 | content: "\e965";
331 | }
332 | .fe-filter:before {
333 | content: "\e966";
334 | }
335 | .fe-flag:before {
336 | content: "\e967";
337 | }
338 | .fe-folder:before {
339 | content: "\e968";
340 | }
341 | .fe-folder-minus:before {
342 | content: "\e969";
343 | }
344 | .fe-folder-plus:before {
345 | content: "\e96a";
346 | }
347 | .fe-gift:before {
348 | content: "\e96b";
349 | }
350 | .fe-git-branch:before {
351 | content: "\e96c";
352 | }
353 | .fe-git-commit:before {
354 | content: "\e96d";
355 | }
356 | .fe-git-merge:before {
357 | content: "\e96e";
358 | }
359 | .fe-git-pull-request:before {
360 | content: "\e96f";
361 | }
362 | .fe-github:before {
363 | content: "\e970";
364 | }
365 | .fe-gitlab:before {
366 | content: "\e971";
367 | }
368 | .fe-globe:before {
369 | content: "\e972";
370 | }
371 | .fe-grid:before {
372 | content: "\e973";
373 | }
374 | .fe-hard-drive:before {
375 | content: "\e974";
376 | }
377 | .fe-hash:before {
378 | content: "\e975";
379 | }
380 | .fe-headphones:before {
381 | content: "\e976";
382 | }
383 | .fe-heart:before {
384 | content: "\e977";
385 | }
386 | .fe-help-circle:before {
387 | content: "\e978";
388 | }
389 | .fe-home:before {
390 | content: "\e979";
391 | }
392 | .fe-image:before {
393 | content: "\e97a";
394 | }
395 | .fe-inbox:before {
396 | content: "\e97b";
397 | }
398 | .fe-info:before {
399 | content: "\e97c";
400 | }
401 | .fe-instagram:before {
402 | content: "\e97d";
403 | }
404 | .fe-italic:before {
405 | content: "\e97e";
406 | }
407 | .fe-layers:before {
408 | content: "\e97f";
409 | }
410 | .fe-layout:before {
411 | content: "\e980";
412 | }
413 | .fe-life-buoy:before {
414 | content: "\e981";
415 | }
416 | .fe-link:before {
417 | content: "\e982";
418 | }
419 | .fe-link-2:before {
420 | content: "\e983";
421 | }
422 | .fe-linkedin:before {
423 | content: "\e984";
424 | }
425 | .fe-list:before {
426 | content: "\e985";
427 | }
428 | .fe-loader:before {
429 | content: "\e986";
430 | }
431 | .fe-lock:before {
432 | content: "\e987";
433 | }
434 | .fe-log-in:before {
435 | content: "\e988";
436 | }
437 | .fe-log-out:before {
438 | content: "\e989";
439 | }
440 | .fe-mail:before {
441 | content: "\e98a";
442 | }
443 | .fe-map:before {
444 | content: "\e98b";
445 | }
446 | .fe-map-pin:before {
447 | content: "\e98c";
448 | }
449 | .fe-maximize:before {
450 | content: "\e98d";
451 | }
452 | .fe-maximize-2:before {
453 | content: "\e98e";
454 | }
455 | .fe-menu:before {
456 | content: "\e98f";
457 | }
458 | .fe-message-circle:before {
459 | content: "\e990";
460 | }
461 | .fe-message-square:before {
462 | content: "\e991";
463 | }
464 | .fe-mic:before {
465 | content: "\e992";
466 | }
467 | .fe-mic-off:before {
468 | content: "\e993";
469 | }
470 | .fe-minimize:before {
471 | content: "\e994";
472 | }
473 | .fe-minimize-2:before {
474 | content: "\e995";
475 | }
476 | .fe-minus:before {
477 | content: "\e996";
478 | }
479 | .fe-minus-circle:before {
480 | content: "\e997";
481 | }
482 | .fe-minus-square:before {
483 | content: "\e998";
484 | }
485 | .fe-monitor:before {
486 | content: "\e999";
487 | }
488 | .fe-moon:before {
489 | content: "\e99a";
490 | }
491 | .fe-more-horizontal:before {
492 | content: "\e99b";
493 | }
494 | .fe-more-vertical:before {
495 | content: "\e99c";
496 | }
497 | .fe-move:before {
498 | content: "\e99d";
499 | }
500 | .fe-music:before {
501 | content: "\e99e";
502 | }
503 | .fe-navigation:before {
504 | content: "\e99f";
505 | }
506 | .fe-navigation-2:before {
507 | content: "\e9a0";
508 | }
509 | .fe-octagon:before {
510 | content: "\e9a1";
511 | }
512 | .fe-package:before {
513 | content: "\e9a2";
514 | }
515 | .fe-paperclip:before {
516 | content: "\e9a3";
517 | }
518 | .fe-pause:before {
519 | content: "\e9a4";
520 | }
521 | .fe-pause-circle:before {
522 | content: "\e9a5";
523 | }
524 | .fe-percent:before {
525 | content: "\e9a6";
526 | }
527 | .fe-phone:before {
528 | content: "\e9a7";
529 | }
530 | .fe-phone-call:before {
531 | content: "\e9a8";
532 | }
533 | .fe-phone-forwarded:before {
534 | content: "\e9a9";
535 | }
536 | .fe-phone-incoming:before {
537 | content: "\e9aa";
538 | }
539 | .fe-phone-missed:before {
540 | content: "\e9ab";
541 | }
542 | .fe-phone-off:before {
543 | content: "\e9ac";
544 | }
545 | .fe-phone-outgoing:before {
546 | content: "\e9ad";
547 | }
548 | .fe-pie-chart:before {
549 | content: "\e9ae";
550 | }
551 | .fe-play:before {
552 | content: "\e9af";
553 | }
554 | .fe-play-circle:before {
555 | content: "\e9b0";
556 | }
557 | .fe-plus:before {
558 | content: "\e9b1";
559 | }
560 | .fe-plus-circle:before {
561 | content: "\e9b2";
562 | }
563 | .fe-plus-square:before {
564 | content: "\e9b3";
565 | }
566 | .fe-pocket:before {
567 | content: "\e9b4";
568 | }
569 | .fe-power:before {
570 | content: "\e9b5";
571 | }
572 | .fe-printer:before {
573 | content: "\e9b6";
574 | }
575 | .fe-radio:before {
576 | content: "\e9b7";
577 | }
578 | .fe-refresh-ccw:before {
579 | content: "\e9b8";
580 | }
581 | .fe-refresh-cw:before {
582 | content: "\e9b9";
583 | }
584 | .fe-repeat:before {
585 | content: "\e9ba";
586 | }
587 | .fe-rewind:before {
588 | content: "\e9bb";
589 | }
590 | .fe-rotate-ccw:before {
591 | content: "\e9bc";
592 | }
593 | .fe-rotate-cw:before {
594 | content: "\e9bd";
595 | }
596 | .fe-rss:before {
597 | content: "\e9be";
598 | }
599 | .fe-save:before {
600 | content: "\e9bf";
601 | }
602 | .fe-scissors:before {
603 | content: "\e9c0";
604 | }
605 | .fe-search:before {
606 | content: "\e9c1";
607 | }
608 | .fe-send:before {
609 | content: "\e9c2";
610 | }
611 | .fe-server:before {
612 | content: "\e9c3";
613 | }
614 | .fe-settings:before {
615 | content: "\e9c4";
616 | }
617 | .fe-share:before {
618 | content: "\e9c5";
619 | }
620 | .fe-share-2:before {
621 | content: "\e9c6";
622 | }
623 | .fe-shield:before {
624 | content: "\e9c7";
625 | }
626 | .fe-shield-off:before {
627 | content: "\e9c8";
628 | }
629 | .fe-shopping-bag:before {
630 | content: "\e9c9";
631 | }
632 | .fe-shopping-cart:before {
633 | content: "\e9ca";
634 | }
635 | .fe-shuffle:before {
636 | content: "\e9cb";
637 | }
638 | .fe-sidebar:before {
639 | content: "\e9cc";
640 | }
641 | .fe-skip-back:before {
642 | content: "\e9cd";
643 | }
644 | .fe-skip-forward:before {
645 | content: "\e9ce";
646 | }
647 | .fe-slack:before {
648 | content: "\e9cf";
649 | }
650 | .fe-slash:before {
651 | content: "\e9d0";
652 | }
653 | .fe-sliders:before {
654 | content: "\e9d1";
655 | }
656 | .fe-smartphone:before {
657 | content: "\e9d2";
658 | }
659 | .fe-speaker:before {
660 | content: "\e9d3";
661 | }
662 | .fe-square:before {
663 | content: "\e9d4";
664 | }
665 | .fe-star:before {
666 | content: "\e9d5";
667 | }
668 | .fe-stop-circle:before {
669 | content: "\e9d6";
670 | }
671 | .fe-sun:before {
672 | content: "\e9d7";
673 | }
674 | .fe-sunrise:before {
675 | content: "\e9d8";
676 | }
677 | .fe-sunset:before {
678 | content: "\e9d9";
679 | }
680 | .fe-tablet:before {
681 | content: "\e9da";
682 | }
683 | .fe-tag:before {
684 | content: "\e9db";
685 | }
686 | .fe-target:before {
687 | content: "\e9dc";
688 | }
689 | .fe-terminal:before {
690 | content: "\e9dd";
691 | }
692 | .fe-thermometer:before {
693 | content: "\e9de";
694 | }
695 | .fe-thumbs-down:before {
696 | content: "\e9df";
697 | }
698 | .fe-thumbs-up:before {
699 | content: "\e9e0";
700 | }
701 | .fe-toggle-left:before {
702 | content: "\e9e1";
703 | }
704 | .fe-toggle-right:before {
705 | content: "\e9e2";
706 | }
707 | .fe-trash:before {
708 | content: "\e9e3";
709 | }
710 | .fe-trash-2:before {
711 | content: "\e9e4";
712 | }
713 | .fe-trending-down:before {
714 | content: "\e9e5";
715 | }
716 | .fe-trending-up:before {
717 | content: "\e9e6";
718 | }
719 | .fe-triangle:before {
720 | content: "\e9e7";
721 | }
722 | .fe-truck:before {
723 | content: "\e9e8";
724 | }
725 | .fe-tv:before {
726 | content: "\e9e9";
727 | }
728 | .fe-twitter:before {
729 | content: "\e9ea";
730 | }
731 | .fe-type:before {
732 | content: "\e9eb";
733 | }
734 | .fe-umbrella:before {
735 | content: "\e9ec";
736 | }
737 | .fe-underline:before {
738 | content: "\e9ed";
739 | }
740 | .fe-unlock:before {
741 | content: "\e9ee";
742 | }
743 | .fe-upload:before {
744 | content: "\e9ef";
745 | }
746 | .fe-upload-cloud:before {
747 | content: "\e9f0";
748 | }
749 | .fe-user:before {
750 | content: "\e9f1";
751 | }
752 | .fe-user-check:before {
753 | content: "\e9f2";
754 | }
755 | .fe-user-minus:before {
756 | content: "\e9f3";
757 | }
758 | .fe-user-plus:before {
759 | content: "\e9f4";
760 | }
761 | .fe-user-x:before {
762 | content: "\e9f5";
763 | }
764 | .fe-users:before {
765 | content: "\e9f6";
766 | }
767 | .fe-video:before {
768 | content: "\e9f7";
769 | }
770 | .fe-video-off:before {
771 | content: "\e9f8";
772 | }
773 | .fe-voicemail:before {
774 | content: "\e9f9";
775 | }
776 | .fe-volume:before {
777 | content: "\e9fa";
778 | }
779 | .fe-volume-1:before {
780 | content: "\e9fb";
781 | }
782 | .fe-volume-2:before {
783 | content: "\e9fc";
784 | }
785 | .fe-volume-x:before {
786 | content: "\e9fd";
787 | }
788 | .fe-watch:before {
789 | content: "\e9fe";
790 | }
791 | .fe-wifi:before {
792 | content: "\e9ff";
793 | }
794 | .fe-wifi-off:before {
795 | content: "\ea00";
796 | }
797 | .fe-wind:before {
798 | content: "\ea01";
799 | }
800 | .fe-x:before {
801 | content: "\ea02";
802 | }
803 | .fe-x-circle:before {
804 | content: "\ea03";
805 | }
806 | .fe-x-square:before {
807 | content: "\ea04";
808 | }
809 | .fe-youtube:before {
810 | content: "\ea05";
811 | }
812 | .fe-zap:before {
813 | content: "\ea06";
814 | }
815 | .fe-zap-off:before {
816 | content: "\ea07";
817 | }
818 | .fe-zoom-in:before {
819 | content: "\ea08";
820 | }
821 | .fe-zoom-out:before {
822 | content: "\ea09";
823 | }
824 |
--------------------------------------------------------------------------------
/src/assets/css/dist/dx-diagram.css:
--------------------------------------------------------------------------------
1 | /*!
2 | * DevExpress Diagram (dx-diagram)
3 | * Version: 2.0.23
4 | * Build date: Mon Apr 19 2021
5 | *
6 | * Copyright (c) 2012 - 2021 Developer Express Inc. ALL RIGHTS RESERVED
7 | * Read about DevExpress licensing here: https://www.devexpress.com/Support/EULAs
8 | */
9 | .dxdi-control {
10 | overflow: visible;
11 | box-sizing: border-box;
12 | position: relative; }
13 | .dxdi-control.dxdi-read-only .dxdi-canvas.dxdi-drag-scroll {
14 | cursor: grab !important; }
15 | .dxdi-control.dxdi-read-only .dxdi-canvas.dxdi-drag-scroll .shape,
16 | .dxdi-control.dxdi-read-only .dxdi-canvas.dxdi-drag-scroll .shape-expand-btn,
17 | .dxdi-control.dxdi-read-only .dxdi-canvas.dxdi-drag-scroll text {
18 | cursor: grab; }
19 | .dxdi-control.dxdi-read-only .dxdi-canvas .shape,
20 | .dxdi-control.dxdi-read-only .dxdi-canvas .shape-expand-btn,
21 | .dxdi-control.dxdi-read-only .dxdi-canvas text {
22 | cursor: default; }
23 | .dxdi-control .dxdi-canvas {
24 | display: block;
25 | background-color: #d9d9d9;
26 | transform-origin: 0 0;
27 | overflow: hidden;
28 | /* Fix excess scroll size in IE */ }
29 |
30 | .dxdi-canvas.dxdi-drag-scroll {
31 | cursor: grab !important; }
32 | .dxdi-canvas.dxdi-drag-scroll .shape,
33 | .dxdi-canvas.dxdi-drag-scroll .shape .shape-expand-btn,
34 | .dxdi-canvas.dxdi-drag-scroll .connector,
35 | .dxdi-canvas.dxdi-drag-scroll .connection-point,
36 | .dxdi-canvas.dxdi-drag-scroll .connector text,
37 | .dxdi-canvas.dxdi-drag-scroll .connector-side-mark.vertical,
38 | .dxdi-canvas.dxdi-drag-scroll .connector-side-mark.horizontal,
39 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="9"][data-value="1"],
40 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="9"][data-value="2"],
41 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="9"][data-value="3"],
42 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="9"][data-value="4"],
43 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="9"][data-value="5"],
44 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="9"][data-value="6"],
45 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="9"][data-value="7"],
46 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="9"][data-value="8"],
47 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="4"],
48 | .dxdi-canvas.dxdi-drag-scroll .selection-mark[data-type="5"] {
49 | cursor: grab; }
50 |
51 | .dxdi-canvas * {
52 | user-select: none; }
53 |
54 | .dxdi-canvas text {
55 | font-family: arial, helvetica, sans-serif;
56 | font-size: 10pt; }
57 |
58 | .dxdi-canvas .page {
59 | fill: white; }
60 |
61 | .dxdi-canvas .pages-grid-line {
62 | fill: none;
63 | stroke: rgba(0, 0, 0, 0.15);
64 | stroke-dasharray: 8;
65 | stroke-width: 2; }
66 |
67 | .dxdi-canvas .grid-outer-line,
68 | .dxdi-canvas .grid-inner-line {
69 | fill: none; }
70 |
71 | .dxdi-canvas .grid-outer-line {
72 | stroke: rgba(0, 0, 0, 0.1); }
73 |
74 | .dxdi-canvas .grid-inner-line {
75 | stroke: rgba(0, 0, 0, 0.05); }
76 |
77 | .dxdi-canvas .shape,
78 | .dxdi-canvas .toolbox-item {
79 | pointer-events: bounding-box; }
80 | .dxdi-canvas .shape rect,
81 | .dxdi-canvas .shape path,
82 | .dxdi-canvas .shape line,
83 | .dxdi-canvas .shape ellipse,
84 | .dxdi-canvas .toolbox-item rect,
85 | .dxdi-canvas .toolbox-item path,
86 | .dxdi-canvas .toolbox-item line,
87 | .dxdi-canvas .toolbox-item ellipse {
88 | fill: white;
89 | stroke-width: 2;
90 | stroke: black; }
91 | .dxdi-canvas .shape text,
92 | .dxdi-canvas .toolbox-item text {
93 | fill: black;
94 | text-anchor: middle; }
95 | .dxdi-canvas .shape rect.selector,
96 | .dxdi-canvas .toolbox-item rect.selector {
97 | stroke-width: 48;
98 | stroke: transparent;
99 | fill: transparent;
100 | pointer-events: initial; }
101 |
102 | .dxdi-canvas .shape.not-valid rect,
103 | .dxdi-canvas .shape.not-valid path,
104 | .dxdi-canvas .shape.not-valid line,
105 | .dxdi-canvas .shape.not-valid ellipse {
106 | stroke: red; }
107 |
108 | .dxdi-canvas .shape {
109 | cursor: move; }
110 | .dxdi-canvas .shape.text-input > text {
111 | display: none; }
112 | .dxdi-canvas .shape.container > rect:first-child {
113 | fill: none; }
114 | .dxdi-canvas .shape .shape-expand-btn {
115 | cursor: pointer; }
116 | .dxdi-canvas .shape .shape-expand-btn > rect,
117 | .dxdi-canvas .shape .shape-expand-btn > path {
118 | stroke-dasharray: initial !important; }
119 | .dxdi-canvas .shape .shape-expand-btn > path {
120 | stroke-width: 2 !important; }
121 | .dxdi-canvas .shape .dxdi-image .dxdi-spinner {
122 | animation: loading-spinner 1s linear infinite; }
123 | .dxdi-canvas .shape .dxdi-image .dxdi-spinner ellipse {
124 | stroke: black;
125 | stroke-opacity: 0.2; }
126 | .dxdi-canvas .shape .dxdi-image .dxdi-spinner path {
127 | stroke: #fd7010;
128 | stroke-linecap: round; }
129 | .dxdi-canvas .shape .dxdi-image .dxdi-spinner ellipse,
130 | .dxdi-canvas .shape .dxdi-image .dxdi-spinner path {
131 | fill: none;
132 | stroke-width: 5; }
133 |
134 | @keyframes loading-spinner {
135 | from {
136 | transform: rotate(0deg); }
137 | to {
138 | transform: rotate(360deg); } }
139 | .dxdi-canvas .shape .dxdi-image .dxdi-user .dxdi-background {
140 | fill: black;
141 | opacity: 0.2;
142 | stroke: none; }
143 | .dxdi-canvas .shape .dxdi-image .dxdi-user ellipse,
144 | .dxdi-canvas .shape .dxdi-image .dxdi-user path {
145 | fill: white;
146 | stroke: none; }
147 | .dxdi-canvas .shape .dxdi-image .dxdi-warning ellipse {
148 | stroke: none;
149 | fill: #ee1616; }
150 | .dxdi-canvas .shape .dxdi-image .dxdi-warning rect {
151 | stroke: none;
152 | fill: white; }
153 |
154 | .dxdi-canvas .shape.locked,
155 | .dxdi-canvas .shape.locked + .container-children .shape {
156 | cursor: inherit !important; }
157 | .dxdi-canvas .shape.locked .shape-expand-btn,
158 | .dxdi-canvas .shape.locked + .container-children .shape .shape-expand-btn {
159 | cursor: inherit !important; }
160 |
161 | .dxdi-canvas .container-children .shape .selector {
162 | stroke-width: 8; }
163 |
164 | .dxdi-canvas .toolbox-item {
165 | cursor: pointer; }
166 | .dxdi-canvas .toolbox-item .selector {
167 | stroke-width: 0 !important; }
168 |
169 | .dxdi-canvas .connector path,
170 | .dxdi-canvas .connector line {
171 | stroke-width: 2;
172 | stroke: black;
173 | stroke-linejoin: round;
174 | pointer-events: stroke; }
175 |
176 | .dxdi-canvas .connector path:not(.outlined-line-ending):not(.filled-line-ending) {
177 | fill: none !important; }
178 |
179 | .dxdi-canvas .connector path.outlined-line-ending {
180 | fill: white; }
181 |
182 | .dxdi-canvas .connector path.filled-line-ending {
183 | fill: black; }
184 |
185 | .dxdi-canvas .connector path.selector,
186 | .dxdi-canvas .connector line.selector {
187 | stroke-width: 16;
188 | stroke: transparent; }
189 |
190 | .dxdi-canvas .connector text {
191 | cursor: move;
192 | fill: black;
193 | text-anchor: middle; }
194 |
195 | .dxdi-canvas .connector .text-filter-flood {
196 | flood-color: white; }
197 |
198 | .dxdi-canvas .connector.not-valid path,
199 | .dxdi-canvas .connector.not-valid line {
200 | stroke: red; }
201 |
202 | .dxdi-canvas .connector.can-move {
203 | cursor: move; }
204 |
205 | .dxdi-canvas .selection-mark,
206 | .dxdi-canvas .geometry-mark,
207 | .dxdi-canvas .connection-point,
208 | .dxdi-canvas .connection-mark,
209 | .dxdi-canvas .connector-point-mark,
210 | .dxdi-canvas .connector-side-mark {
211 | fill: white;
212 | stroke-width: 2; }
213 |
214 | .dxdi-canvas .selection-mark {
215 | stroke: dodgerblue; }
216 |
217 | .dxdi-canvas .selection-mark[data-type="9"][data-value="1"] {
218 | cursor: nw-resize; }
219 |
220 | .dxdi-canvas .selection-mark[data-type="9"][data-value="2"] {
221 | cursor: ne-resize; }
222 |
223 | .dxdi-canvas .selection-mark[data-type="9"][data-value="3"] {
224 | cursor: se-resize; }
225 |
226 | .dxdi-canvas .selection-mark[data-type="9"][data-value="4"] {
227 | cursor: sw-resize; }
228 |
229 | .dxdi-canvas .selection-mark[data-type="9"][data-value="5"] {
230 | cursor: n-resize; }
231 |
232 | .dxdi-canvas .selection-mark[data-type="9"][data-value="6"] {
233 | cursor: e-resize; }
234 |
235 | .dxdi-canvas .selection-mark[data-type="9"][data-value="7"] {
236 | cursor: s-resize; }
237 |
238 | .dxdi-canvas .selection-mark[data-type="9"][data-value="8"] {
239 | cursor: w-resize; }
240 |
241 | .dxdi-canvas .selection-mark[data-type="4"],
242 | .dxdi-canvas .selection-mark[data-type="5"] {
243 | cursor: move; }
244 |
245 | .dxdi-canvas .locked-selection-mark {
246 | fill: white;
247 | stroke-width: 1;
248 | stroke: #666; }
249 |
250 | .dxdi-canvas .geometry-mark {
251 | cursor: pointer;
252 | stroke: goldenrod; }
253 |
254 | .dxdi-canvas .container-target,
255 | .dxdi-canvas .connection-target {
256 | fill: transparent;
257 | stroke: orchid;
258 | stroke-width: 2;
259 | pointer-events: none; }
260 |
261 | .dxdi-canvas .connection-point {
262 | cursor: crosshair;
263 | stroke: orchid; }
264 |
265 | .dxdi-canvas .connection-point.not-valid {
266 | stroke: grey;
267 | display: none; }
268 |
269 | .dxdi-canvas .connection-mark {
270 | cursor: crosshair;
271 | stroke: orchid; }
272 |
273 | .dxdi-canvas .connection-point.selector,
274 | .dxdi-canvas .connection-mark.selector {
275 | stroke-width: 10px;
276 | stroke: transparent;
277 | fill: transparent; }
278 |
279 | .dxdi-canvas .connection-point.active {
280 | fill: orchid; }
281 |
282 | .dxdi-canvas .connection-mark.active {
283 | fill: orchid; }
284 |
285 | .dxdi-canvas .connector-point-mark,
286 | .dxdi-canvas .connector-side-mark {
287 | cursor: move;
288 | stroke: dodgerblue; }
289 |
290 | .dxdi-canvas .connector-point-mark.disabled {
291 | cursor: default;
292 | display: none; }
293 |
294 | .dxdi-canvas .connector-side-mark {
295 | fill: dodgerblue; }
296 |
297 | .dxdi-canvas .connector-side-mark.vertical {
298 | cursor: col-resize; }
299 |
300 | .dxdi-canvas .connector-side-mark.horizontal {
301 | cursor: row-resize; }
302 |
303 | .dxdi-canvas .item-selection-rect,
304 | .dxdi-canvas .items-selection-rect {
305 | fill: transparent;
306 | stroke-width: 1;
307 | stroke: dodgerblue;
308 | stroke-dasharray: 2px;
309 | pointer-events: none; }
310 |
311 | .dxdi-canvas .items-selection-rect {
312 | fill: rgba(30, 144, 255, 0.02); }
313 |
314 | .dxdi-canvas .item-multi-selection-rect {
315 | fill: rgba(30, 144, 255, 0.02);
316 | stroke-width: 1;
317 | stroke: dodgerblue;
318 | pointer-events: none; }
319 |
320 | .dxdi-canvas .selection-rect {
321 | fill: rgba(30, 144, 255, 0.2);
322 | stroke-width: 1;
323 | stroke: dodgerblue;
324 | pointer-events: none; }
325 |
326 | .dxdi-canvas .connector-selection,
327 | .dxdi-canvas .connector-multi-selection {
328 | fill: transparent;
329 | stroke-width: 1;
330 | stroke: dodgerblue;
331 | pointer-events: none; }
332 |
333 | .dxdi-canvas .connector-selection.text,
334 | .dxdi-canvas .connector-multi-selection.text {
335 | fill: transparent;
336 | stroke-width: 1; }
337 |
338 | .dxdi-canvas .connector-selection {
339 | stroke-dasharray: 2px; }
340 |
341 | .dxdi-canvas .connector-selection-mask rect {
342 | fill: black; }
343 |
344 | .dxdi-canvas .connector-selection-mask rect.background {
345 | fill: white; }
346 |
347 | .dxdi-canvas .connector-selection-mask path,
348 | .dxdi-canvas .connector-selection-mask line {
349 | fill: white;
350 | stroke: black;
351 | stroke-width: 4; }
352 |
353 | .dxdi-canvas .connector-selection-mask text {
354 | text-anchor: middle; }
355 |
356 | .dxdi-canvas .extension-line path {
357 | stroke: dodgerblue;
358 | stroke-width: 1; }
359 |
360 | .dxdi-canvas .extension-line path.size-line {
361 | stroke-dasharray: 4px; }
362 |
363 | .dxdi-canvas .extension-line text {
364 | fill: dodgerblue;
365 | font-size: 0.8em;
366 | text-anchor: middle; }
367 |
368 | .dxdi-canvas .extension-line.center > path.size-line,
369 | .dxdi-canvas .extension-line.page > path.size-line {
370 | stroke-dasharray: 0; }
371 |
372 | .dxdi-canvas .extension-line:not(.center) > path:not(:first-child) {
373 | display: none; }
374 |
375 | .dxdi-canvas .resize-info text {
376 | fill: rgba(0, 0, 0, 0.8);
377 | font-size: 0.8em;
378 | text-anchor: middle; }
379 |
380 | .dxdi-canvas .resize-info rect {
381 | fill: white;
382 | stroke: rgba(0, 0, 0, 0.3);
383 | stroke-width: 1; }
384 |
385 | .dxdi-canvas .dxdi-active-selection .shape {
386 | cursor: default; }
387 |
388 | .dxdi-control:not(.focused) .dxdi-canvas .selection-mark {
389 | stroke: #666; }
390 |
391 | .dxdi-control:not(.focused) .dxdi-canvas .geometry-mark {
392 | stroke: #666; }
393 |
394 | .dxdi-control:not(.focused) .dxdi-canvas .item-selection-rect,
395 | .dxdi-control:not(.focused) .dxdi-canvas .items-selection-rect {
396 | fill: transparent;
397 | stroke: #666; }
398 |
399 | .dxdi-control:not(.focused) .dxdi-canvas .items-selection-rect {
400 | fill: rgba(144, 144, 144, 0.02); }
401 |
402 | .dxdi-control:not(.focused) .dxdi-canvas .item-multi-selection-rect {
403 | fill: rgba(144, 144, 144, 0.02);
404 | stroke: #666; }
405 |
406 | .dxdi-control:not(.focused) .dxdi-canvas .connection-point,
407 | .dxdi-control:not(.focused) .dxdi-canvas .connection-point.selector,
408 | .dxdi-control:not(.focused) .dxdi-canvas .connection-mark,
409 | .dxdi-control:not(.focused) .dxdi-canvas .connection-mark.selector {
410 | display: none; }
411 |
412 | .dxdi-control:not(.focused) .dxdi-canvas .connector-selection,
413 | .dxdi-control:not(.focused) .dxdi-canvas .connector-multi-selection {
414 | stroke: #666; }
415 |
416 | .dxdi-control:not(.focused) .dxdi-canvas .connector-point-mark,
417 | .dxdi-control:not(.focused) .dxdi-canvas .connector-side-mark {
418 | stroke: #666; }
419 |
420 | .dxdi-control:not(.focused) .dxdi-canvas .connector-side-mark {
421 | fill: #666; }
422 |
423 | .dxdi-dragging,
424 | .dxdi-dragging * {
425 | user-select: none; }
426 |
427 | .dxdi-canvas.export * {
428 | cursor: inherit !important;
429 | pointer-events: all !important; }
430 |
431 | .dxdi-toolbox,
432 | .dxdi-toolbox svg {
433 | user-select: none;
434 | outline: none; }
435 |
436 | .dxdi-toolbox,
437 | .dxdi-toolbox .dxdi-canvas,
438 | .dxdi-toolbox-drag-item .dxdi-canvas {
439 | width: 100%;
440 | height: 100%; }
441 |
442 | .dxdi-toolbox .dxdi-canvas .toolbox-item rect,
443 | .dxdi-toolbox .dxdi-canvas .toolbox-item path,
444 | .dxdi-toolbox .dxdi-canvas .toolbox-item line,
445 | .dxdi-toolbox .dxdi-canvas .toolbox-item ellipse {
446 | fill: transparent;
447 | stroke: currentColor; }
448 |
449 | .dxdi-toolbox .dxdi-canvas .toolbox-item .dxdi-image-placeholder {
450 | opacity: 0.75;
451 | fill: currentColor;
452 | stroke: none; }
453 |
454 | .dxdi-toolbox .dxdi-canvas .toolbox-item .dxdi-shape-text {
455 | opacity: 0.25; }
456 |
457 | .dxdi-toolbox .dxdi-canvas .toolbox-item text,
458 | .dxdi-toolbox-drag-item .dxdi-canvas text {
459 | font-weight: bold;
460 | font-family: "Segoe UI", "Helvetica Neue", Helvetica, arial, sans-serif;
461 | fill: currentColor; }
462 |
463 | .dxdi-toolbox-drag-item .dxdi-canvas .dxdi-image-placeholder {
464 | opacity: 0.75;
465 | fill: currentColor;
466 | stroke: none; }
467 |
468 | .dxdi-toolbox-drag-item .dxdi-canvas .dxdi-shape-text {
469 | display: none; }
470 |
471 | .dxdi-toolbox .toolbox-text-item {
472 | cursor: pointer;
473 | user-select: none;
474 | margin: 0 0 0.6em; }
475 |
476 | .dxdi-toolbox-drag-item,
477 | .dxdi-toolbox-drag-text-item {
478 | font-family: arial, helvetica, sans-serif;
479 | font-size: 10pt;
480 | color: black;
481 | position: absolute;
482 | z-index: 10000;
483 | pointer-events: none !important; }
484 | .dxdi-toolbox-drag-item *,
485 | .dxdi-toolbox-drag-text-item * {
486 | pointer-events: none !important; }
487 |
488 | .dxdi-toolbox-drag-item text {
489 | pointer-events: none; }
490 |
491 | .dxdi-toolbox-drag-text-item {
492 | background-color: white;
493 | border: 2px solid black;
494 | padding: 0.5em; }
495 |
496 | .dxdi-tb-drag-captured {
497 | display: none; }
498 |
499 | .dxdi-focus-input,
500 | .dxdi-text-input-container,
501 | .dxdi-text-input {
502 | padding: 0;
503 | outline: none;
504 | border: none;
505 | resize: none; }
506 |
507 | .dxdi-clipboard-input,
508 | .dxdi-focus-input {
509 | position: fixed;
510 | overflow: hidden;
511 | left: -1000px !important;
512 | top: -1000px !important; }
513 |
514 | .dxdi-text-input-container {
515 | display: none; }
516 |
517 | .dxdi-text-input-container.shape-text,
518 | .dxdi-text-input-container.connector-text {
519 | display: inherit;
520 | position: absolute;
521 | overflow: hidden;
522 | background-color: transparent;
523 | transform-origin: 0 0; }
524 |
525 | .dxdi-text-input-container.shape-text .dxdi-text-input {
526 | display: table-cell;
527 | overflow: hidden;
528 | padding: 1px 0 0;
529 | outline: none;
530 | background-color: transparent;
531 | font-family: arial, helvetica, sans-serif;
532 | font-size: 10pt;
533 | color: black;
534 | line-height: 1.1em;
535 | text-align: center;
536 | vertical-align: middle; }
537 |
538 | .dxdi-text-input-container.connector-text {
539 | overflow: visible; }
540 |
541 | .dxdi-text-input-container.connector-text .dxdi-text-input {
542 | padding: 2px;
543 | outline: none;
544 | height: calc(1.1em + 6px);
545 | width: calc(8em + 6px);
546 | margin-top: calc(-0.55em - 3px);
547 | margin-left: calc(-4em - 3px);
548 | background-color: white;
549 | border: 1px solid dodgerblue;
550 | font-family: arial, helvetica, sans-serif;
551 | font-size: 10pt;
552 | color: black;
553 | line-height: 1.1em;
554 | text-align: center;
555 | vertical-align: middle;
556 | overflow: hidden; }
557 |
558 | .dxdi-page-shadow {
559 | fill: #808080; }
560 |
561 |
--------------------------------------------------------------------------------
/src/assets/js/owl/syllabus.js:
--------------------------------------------------------------------------------
1 | var dragStartIndex;
2 | var editing = false;
3 | var editorIndex = 1;
4 | var bodiesLoaded = false;
5 |
6 | //https://gist.github.com/Reinmar/b9df3f30a05786511a42
7 | $.widget( 'ui.dialog', $.ui.dialog, {
8 | _allowInteraction: function( event ) {
9 | if ( this._super( event ) ) {
10 | return true;
11 | }
12 |
13 | // Address interaction issues with general iframes with the dialog.
14 | // Fixes errors thrown in IE when clicking CKEditor magicline's "Insert paragraph here" button.
15 | if ( event.target.ownerDocument != this.document[ 0 ] ) {
16 | return true;
17 | }
18 |
19 | // Address interaction issues with dialog window.
20 | if ( $( event.target ).closest( '.cke_dialog' ).length ) {
21 | return true;
22 | }
23 |
24 | // Address interaction issues with iframe based drop downs in IE.
25 | if ( $( event.target ).closest( '.cke' ).length ) {
26 | return true;
27 | }
28 | },
29 |
30 | // Uncomment this code when using jQuery UI 1.10.*.
31 | // Addresses http://dev.ckeditor.com/ticket/10269
32 | _moveToTop: function ( event, silent ) {
33 | if ( !event || !this.options.modal ) {
34 | this._super( event, silent );
35 | }
36 | }
37 | } );
38 |
39 | function setupAccordion(iframId, isInstructor, msgs, openDataId){
40 | var activeVar = false;
41 | if($( "#accordion .group" ).children("h3").size() <= 1){
42 | //since there is only 1 option, might was well keep it open instead of collapsed
43 | activeVar = 0;
44 | //only one to expand, might as well hide the expand all link:
45 | $("#expandLink").closest("li").hide();
46 | }
47 | $( "#accordion > span > div" ).accordion({
48 | header: "> div > h3",
49 | active: activeVar,
50 | autoHeight: false,
51 | collapsible: true,
52 | heightStyle: "content",
53 | });
54 | if(isInstructor){
55 | $( "#accordion span" ).sortable({
56 | axis: "y",
57 | handle: ".group",
58 | start: function(event, ui){
59 | dragStartIndex = ui.item.index();
60 | },
61 | stop: function( event, ui ) {
62 | // IE doesn't register the blur when sorting
63 | // so trigger focusout handlers to remove .ui-state-focus
64 | ui.item.children( "h3" ).triggerHandler( "focusout" );
65 |
66 | //find how much this item was dragged:
67 | var dragEndIndex = ui.item.index();
68 | var moved = dragStartIndex - dragEndIndex;
69 | if(moved !== 0){
70 | //update the position:
71 | postAjax($(ui.item).children(":first").attr("syllabusItem"), {"move": moved}, msgs);
72 | updatePositions();
73 | }
74 | }
75 | });
76 | var itemsOrder = [];
77 | function updatePositions() {
78 | itemsOrder = [];
79 | $('.reorder-element .group').each(function() {
80 | itemsOrder.push($(this).attr('syllabusitem'));
81 | });
82 | }
83 | updatePositions()
84 | var saveTimeout;
85 | $('#lastItemMoved').change(function() {
86 | // Clear the enqueued positions save
87 | clearTimeout(saveTimeout);
88 | syllabusId = $(this).text();
89 | syllabusItem = $('#' + syllabusId).parent().attr('syllabusitem');
90 | saveTimeout = setTimeout(function(){
91 | // Save the positions after 500ms with no more changes
92 | // First of all save the selected item
93 | var positionBefore = itemsOrder.indexOf(syllabusItem);
94 | var index = $('#' + syllabusId).parent().parent().index();
95 | var move = positionBefore - index;
96 | if (move !== 0) {
97 | postAjax(syllabusItem, {"move": move}, msgs);
98 | itemsOrder.move(positionBefore, index);
99 | }
100 | var index = 0;
101 | // After this, check if other elements also should be saved (mulitple changes)
102 | $('.reorder-element .group').each(function() {
103 | var syllabusItem = $(this).attr('syllabusitem');
104 | var positionBefore = itemsOrder.indexOf(syllabusItem);
105 | var move = positionBefore - index;
106 | if (move === 0) {
107 | index++;
108 | return;
109 | }
110 | // This request should send all the array of positions in order to make it asynchronous (this logic will need a change)
111 | postAjax(syllabusItem, {"move": move}, msgs);
112 | itemsOrder.move(positionBefore, index);
113 | index++;
114 | });
115 | }, 500);
116 | });
117 | }
118 | Array.prototype.move = function(from,to){
119 | this.splice(to,0,this.splice(from,1)[0]);
120 | return this;
121 | };
122 | if(activeVar === false && openDataId && openDataId !== ''){
123 | //instructor is working on this data item, keep it open and focused on when refreshing
124 | $( "#accordion div[syllabusItem=" + openDataId + "].group .ui-accordion-header").click().focus();
125 |
126 | }
127 |
128 | $( "#accordion div.group:first-child h3:first-child").focus();
129 |
130 | //set hover over text for collapse/expand arrow:
131 | $(".ui-accordion-header-icon").attr("title", msgs.clickToExpandAndCollapse);
132 | }
133 |
134 | function expandAccordion(iframId){
135 | $('#accordion > span > div.ui-accordion').each(function(){
136 | if(!$(this).find(".ui-accordion-content:first").is(":visible")){
137 | $(this).find(".ui-accordion-header:first").click();
138 | }
139 | });
140 | $("#collapseLink").show();
141 | $("#expandLink").hide();
142 | }
143 |
144 | function collapseAccordion(iframId){
145 | $('#accordion > span > div.ui-accordion').each(function(){
146 | if($(this).find(".ui-accordion-content:first").is(":visible")){
147 | $(this).find(".ui-accordion-header:first").click();
148 | }
149 | });
150 | $("#collapseLink").hide();
151 | $("#expandLink").show();
152 | }
153 |
154 | function editorClick(event){
155 | $("#textAreaWysiwyg" + (editorIndex - 1)).val($(event.target).closest(".control-group").find("iframe").contents().find('body').html()).change();
156 | }
157 |
158 | function showMessage(message, success){
159 | var spanItem;
160 | if(success){
161 | spanItem = $("#successInfo");
162 | }else{
163 | spanItem = $("#warningInfo");
164 | }
165 | $(spanItem).html(message);
166 | var topPos = 0;
167 | //set topPos to top of the scroll bar for this iFrame
168 | try{
169 | topPos = $(window.parent.$("html,body")).scrollTop();
170 | if(topPos === 0){
171 | //try a different method to be sure
172 | topPos = $(window.parent.$("body")).scrollTop();
173 | }
174 | }catch(e){}
175 | //if this is an iframe, adjust top by the offset of the iframe
176 | try{
177 | if(topPos !== 0){
178 | topPos = topPos - $(window.parent.$("iframe")).offset().top;
179 | }
180 | }catch(e){}
181 | //unless the users scrolls past the iframe, the position will be negative... just make it 0
182 | if(topPos < 0){
183 | topPos = 0;
184 | }
185 | $(spanItem).css("top", topPos);
186 | $(spanItem).show();
187 |
188 | setTimeout(function(){$(spanItem).fadeOut();}, 4000);
189 | }
190 |
191 | function postAjax(id, params, msgs){
192 | var d = $.Deferred;
193 | $.ajax({
194 | type: 'POST',
195 | url: "/direct/syllabus/" + id + ".json",
196 | data: params,
197 | async:false,
198 | error: function error(data){
199 | showMessage(msgs.error, false);
200 | d().reject();
201 | },
202 | failure: function failure(data){
203 | showMessage(msgs.error, false);
204 | d().reject();
205 | },
206 | success: function success(data){
207 | var successText = msgs.saved;
208 | if (params.delete !== null && params.delete) {
209 | successText = msgs.deleted;
210 | }
211 | showMessage(successText, true);
212 | d().resolve();
213 | }
214 | });
215 | return d().promise();
216 | }
217 |
218 | function getDateTime(dateTimeStr){
219 | var split = dateTimeStr.split(" ");
220 | if(split.length === 3){
221 | var dateStr = split[0];
222 | var timeStr = split[1] + " " + split[2];
223 | var date = new Date(Date.parse(dateStr));
224 | //TODO, internationalize the "P" match?
225 | var time = timeStr.match(/(\d+)(?::(\d\d))?\s*(P?)/);
226 | date.setHours( parseInt(time[1]) + (time[3] ? 12 : 0) );
227 | date.setMinutes( parseInt(time[2]) || 0 );
228 | return date;
229 | }else{
230 | return null;
231 | }
232 | }
233 |
234 | function setupToggleImages(action, imgClass, classOn, classOff, msgs){
235 | $("." + imgClass).click(function(event){
236 | var status;
237 | //custom action for calendar:
238 | if(action === "linkCalendar"){
239 | //make sure at least one date is set
240 | if(!$(this).hasClass(classOn)){
241 | //only warn user is they are turning on the calendar sync
242 | var startTime = $(this).parents('div.group').find(".startTimeInput").text();
243 | var endTime = $(this).parents('div.group').find(".endTimeInput").text();
244 | if((startTime === null || "" === $.trim(startTime) || $.trim(startTime) === $.trim(msgs.clickToAddStartDate))
245 | && (endTime === null || "" === $.trim(endTime) || $.trim(endTime) === $.trim(msgs.clickToAddEndDate))){
246 | showMessage(msgs.calendarDatesNeeded, false);
247 | event.stopPropagation();
248 | return;
249 | }
250 | }
251 | }
252 |
253 | if($(this).hasClass(classOn)){
254 | //need to toggle to false
255 | status = false;
256 | $(this).hide();
257 | $(this).parents('div.group').find("." + classOff).fadeIn();
258 | }else{
259 | //need to toggle to true
260 | status = true;
261 | $(this).hide();
262 | $(this).parents('div.group').find("." + classOn).fadeIn();
263 | }
264 | //custom action for publish and unpublish:
265 | if(action === "publish"){
266 | //toggle the draft class
267 | if(status){
268 | $(this).parent().find(".editItemTitle").parent().removeClass("draft");
269 | $(this).parent().find( ".draftTitlePrefix " ).remove();
270 | }else{
271 | $(this).parent().find(".editItemTitle").parent().addClass("draft");
272 | var span = "
" + msgs.draftTitlePrefix + " ";
273 | $(this).parent().find(".editItemTitle").parent().prepend( span );
274 | }
275 | }
276 |
277 | var id = $(this).parents('div.group').attr("syllabusItem");
278 | params = {"toggle" : action,
279 | "status": status};
280 | postAjax(id, params, msgs);
281 | event.stopPropagation();
282 | });
283 | }
284 | function showConfirmDeleteAttachment(deleteButton, msgs, event){
285 | var title = $(deleteButton).parent().find(".attachment").html();
286 | $('
').appendTo('body')
287 | .html('
' + msgs.noUndoWarning + '
' + msgs.confirmDelete + " '" + title + "'? ")
288 | .dialog({
289 | position: { my: 'left center', at: 'right center', of: $(deleteButton)},
290 | modal: true, title: msgs.deleteAttachmentTitle, zIndex: 10000, autoOpen: true,
291 | width: 'auto', resizable: true,
292 | buttons: [
293 | {
294 | text: msgs.bar_delete,
295 | click: function () {
296 | var id = $(deleteButton).parents('div.group').attr("syllabusItem");
297 | params = {"deleteAttachment" : true,
298 | "attachmentId" : $(deleteButton).attr("attachmentId")};
299 | postAjax(id, params, msgs);
300 | if($("#successInfo").is(":visible")){
301 | $(deleteButton).parents('tr').remove();
302 | }
303 | $(this).dialog("close");
304 | }
305 | },
306 | {
307 | text: msgs.bar_cancel,
308 | click: function () {
309 | $(this).dialog("close");
310 | }
311 | }
312 | ],
313 | close: function (event, ui) {
314 | $(this).remove();
315 | }
316 | });
317 | event.stopPropagation();
318 | }
319 |
320 | function showConfirmDelete(deleteButton, msgs, event){
321 | var title = $(deleteButton).parent().parent().find(".syllabusItemTitle").html();
322 | $('
').appendTo('body')
323 | .html('
' + msgs.noUndoWarning + '
' + msgs.confirmDelete + " '" + title + "'? ")
324 | .dialog({
325 | position: { my: 'left center', at: 'right center', of: $(deleteButton)},
326 | modal: true, title: msgs.deleteItemTitle, zIndex: 10000, autoOpen: true,
327 | width: 'auto', resizable: true,
328 | buttons: [
329 | {
330 | text: msgs.bar_delete,
331 | click: function () {
332 | var id = $(deleteButton).parents('div.group').attr("syllabusItem");
333 | params = {"delete" : true};
334 | postAjax(id, params, msgs);
335 | if($("#successInfo").is(":visible")){
336 | $(deleteButton).parents('div.group').remove();
337 | }
338 | $(this).dialog("close");
339 | }
340 | },
341 | {
342 | text: msgs.bar_cancel,
343 | click: function () {
344 | $(this).dialog("close");
345 | }
346 | }
347 | ],
348 | close: function (event, ui) {
349 | $(this).remove();
350 | return false;
351 | }
352 | });
353 | event.stopPropagation();
354 | }
355 |
356 | function doAddItemButtonClick( msgs, published )
357 | {
358 | var title = $( "#newTitle" ).val();
359 | if( !title || "" === title.trim() )
360 | {
361 | $( "#requiredTitle" ).show();
362 | setTimeout( function() { $( "#requiredTitle" ).fadeOut(); }, 5000 );
363 | }
364 | else
365 | {
366 | // Fetch the content from the new wysiwyg
367 | $("#newContentTextAreaWysiwyg").val($('#newContentDiv').find('iframe').contents().find('body').html()).change();
368 |
369 | // ID doesn't exist since we're adding a new one
370 | var id = "0";
371 | params =
372 | {
373 | "add" : true,
374 | "title": title,
375 | "siteId": $("#siteId").val(),
376 | "published": published,
377 | "content": $("#newContentTextAreaWysiwyg").val()
378 | };
379 |
380 | postAjax( id, params, msgs );
381 | if( $( "#successInfo" ).is( ":visible" ) )
382 | {
383 | location.reload();
384 | return true;
385 | }
386 | }
387 |
388 | return false;
389 | }
390 |
391 | function showConfirmAdd(msgs, mainframeId){
392 | $('#container', this.top.document).append("
");
393 | $('
').appendTo('body')
394 | .html("
* " + msgs.syllabus_title + "" + msgs.required + "
" +
395 | "
" + msgs.syllabus_content + "
")
396 | .dialog({
397 | position: {
398 | my: 'center',
399 | at: 'center',
400 | of: window
401 | },
402 | modal: true,
403 | title: msgs.addItemTitle,
404 | zIndex: 11100,
405 | autoOpen: true,
406 | width: 'auto',
407 | height: 'auto',
408 | resizable: true,
409 | buttons: [
410 | {
411 | text: msgs.bar_publish,
412 | click: function() { if (doAddItemButtonClick( msgs, true )) {$( this ).dialog( "close" );} }
413 | },
414 | {
415 | text: msgs.bar_new,
416 | click: function() { if (doAddItemButtonClick( msgs, false )) {$( this ).dialog( "close" );} }
417 | },
418 | {
419 | text: msgs.bar_cancel,
420 | click: function () {
421 | $(this).dialog("close");
422 | }
423 | }
424 | ],
425 | close: function (event, ui) {
426 | $(this).remove();
427 | return false;
428 | }
429 | });
430 | sakai.editor.launch("newContentTextAreaWysiwyg", {}, 900, 300);
431 | }
432 |
433 | if(typeof String.prototype.trim !== 'function') {
434 | String.prototype.trim = function() {
435 | return this.replace(/^\s+|\s+$/g, '');
436 | };
437 | }
438 |
--------------------------------------------------------------------------------
/src/assets/scss/bootstrap/variables.scss:
--------------------------------------------------------------------------------
1 | //
2 | // variables.scss
3 | // Extended from Bootstrap
4 | //
5 |
6 | //
7 | // Bootstrap Overrides ===================================
8 | //
9 |
10 |
11 | // Variables
12 | //
13 | // Variables should follow the `$component-state-property-size` formula for
14 | // consistent naming. Ex: $nav-link-disabled-color and $modal-content-box-shadow-xs.
15 |
16 | //
17 | // Color system
18 | //
19 |
20 | // stylelint-disable
21 | $white: #FFFFFF !default;
22 | $gray-100: #F9FBFD !default;
23 | $gray-200: #EDF2F9 !default;
24 | $gray-300: #E3EBF6 !default;
25 | $gray-400: #D2DDEC !default;
26 | $gray-500: #B1C2D9 !default;
27 | $gray-600: #95AAC9 !default;
28 | $gray-700: #6E84A3 !default;
29 | $gray-800: #3B506C !default;
30 | $gray-900: #283E59 !default;
31 | $black: #12263F !default;
32 |
33 | $gray-600-dark: #244166 !default;
34 | $gray-700-dark: #1E3A5C !default;
35 | $gray-800-dark: #152E4D !default;
36 | $gray-900-dark: #132A46 !default;
37 | $black-dark: #12263F !default;
38 |
39 | $blue: #2C7BE5 !default;
40 | $indigo: #727cf5 !default; // NOT USED
41 | $purple: #6b5eae !default;
42 | $pink: #ff679b !default; // NOT USED
43 | $red: #E63757 !default;
44 | $orange: #fd7e14 !default; // NOT USED
45 | $yellow: #F6C343 !default;
46 | $green: #00D97E !default;
47 | $teal: #02a8b5 !default; // NOT USED
48 | $cyan: #39afd1 !default; // NOT USED
49 |
50 | $primary: $blue !default;
51 | $secondary: $gray-700 !default;
52 | $success: $green !default;
53 | $info: $cyan !default;
54 | $warning: $yellow !default;
55 | $danger: $red !default;
56 | $light: $gray-200 !default;
57 | $dark: $black !default;
58 |
59 | $theme-colors: () !default;
60 | $theme-colors: map-merge((
61 | "primary": $primary,
62 | "secondary": $secondary,
63 | "success": $success,
64 | "info": $info,
65 | "warning": $warning,
66 | "danger": $danger,
67 | "light": $light,
68 | "dark": $dark,
69 | "white": $white
70 | ), $theme-colors);
71 | // stylelint-enable
72 |
73 | $lighter: $gray-100 !default;
74 |
75 | // Customize the light and dark text colors for use in our YIQ color contrast function.
76 | $yiq-text-dark: $gray-900 !default;
77 | $yiq-text-light: $white !default;
78 |
79 |
80 | // Options
81 | //
82 | // Quickly modify global styling by enabling or disabling optional features.
83 |
84 | $enable-validation-icons: false !default;
85 |
86 |
87 | // Spacing
88 | //
89 | // Control the default styling of most Bootstrap elements by modifying these
90 | // variables. Mostly focused on spacing.
91 | // You can add more entries to the $spacers map, should you need more variation.
92 |
93 | $spacer: 1.5rem !default;
94 | $spacers: () !default;
95 | $spacers: map-merge((
96 | 0: 0,
97 | 1: ($spacer * .125), // 3px
98 | 2: ($spacer * .25), // 6px
99 | 3: ($spacer * .5), // 12px
100 | 4: $spacer, // 24px
101 | 5: ($spacer * 1.5), // 36px
102 | 6: ($spacer * 3), // 72px
103 | 7: ($spacer * 4.5), // 108px
104 | 8: ($spacer * 9) // 216px
105 | ), $spacers);
106 |
107 | // This variable affects the `.h-*` and `.w-*` classes.
108 | $sizes: () !default;
109 | $sizes: map-merge((
110 | 15: 15%,
111 | 25: 25%,
112 | 50: 50%,
113 | 75: 75%,
114 | 100: 100%
115 | ), $sizes);
116 |
117 |
118 | // Body
119 | //
120 | // Settings for the `` element.
121 |
122 | $body-bg: $gray-100 !default;
123 | $body-color: $black !default;
124 |
125 |
126 | // Links
127 | //
128 | // Style anchor elements.
129 |
130 | $link-color: theme-color("primary") !default;
131 | $link-hover-color: darken($link-color, 15%) !default;
132 | $link-hover-decoration: none !default;
133 |
134 |
135 | // Grid columns
136 | //
137 | // Set the number of columns and specify the width of the gutters.
138 |
139 | $grid-gutter-width: 24px !default;
140 |
141 | // Components
142 | //
143 | // Define common padding and border radius sizes and more.
144 |
145 | $line-height-lg: 1.5 !default;
146 | $line-height-sm: 1.75 !default;
147 |
148 | $border-width: 1px !default;
149 | $border-color: $gray-300 !default;
150 |
151 | $border-radius: 0.375rem !default;
152 | $border-radius-lg: 0.5rem !default;
153 | $border-radius-sm: 0.25rem !default;
154 |
155 | $component-active-bg: $primary !default;
156 |
157 | $caret-width: .25em !default;
158 |
159 |
160 | // Fonts
161 | //
162 | // Font, line-height, and color for body text, headings, and more.
163 |
164 | // stylelint-disable value-keyword-case
165 | $font-family-sans-serif: 'Cerebri Sans', sans-serif !default;
166 | $font-family-base: $font-family-sans-serif !default;
167 | // stylelint-enable value-keyword-case
168 |
169 | $font-size-base: 0.9375rem !default; // 15px
170 | $font-size-lg: ($font-size-base * 1.133333333334) !default; // 17px
171 | $font-size-sm: ($font-size-base * .866666667) !default; // 13px
172 |
173 | $font-weight-light: 400 !default;
174 | $font-weight-normal: 400 !default;
175 | $font-weight-bold: 600 !default;
176 |
177 | $line-height-base: 1.5 !default;
178 |
179 | $headings-margin-bottom: $spacer * .75 !default;
180 | $headings-font-weight: 500 !default;
181 | $headings-line-height: 1.1 !default;
182 |
183 | $h1-font-size: 1.625rem !default;
184 | $h2-font-size: 1.25rem !default;
185 | $h3-font-size: 1.0625rem !default;
186 | $h4-font-size: 0.9375rem !default;
187 | $h5-font-size: 0.8125rem !default;
188 | $h6-font-size: 0.625rem !default;
189 |
190 | $display1-size: 4rem !default;
191 | $display2-size: 3.25rem !default;
192 | $display3-size: 2.625rem !default;
193 | $display4-size: 2rem !default;
194 |
195 | $display1-weight: 600 !default;
196 | $display2-weight: 600 !default;
197 | $display3-weight: 600 !default;
198 | $display4-weight: 600 !default;
199 | $display-line-height: $headings-line-height !default;
200 |
201 | $lead-font-size: ($font-size-base * 1.25) !default;
202 |
203 | $small-font-size: 0.8125rem !default;
204 |
205 | $text-muted: $gray-600 !default;
206 |
207 | $blockquote-font-size: ($font-size-base * 1.25) !default;
208 |
209 | $hr-border-color: $border-color !default;
210 | $hr-margin-y: 1rem !default;
211 |
212 | $list-inline-padding: 6px !default;
213 |
214 |
215 | // Tables
216 | //
217 | // Customizes the `.table` component with basic values, each used across all table variations.
218 |
219 | $table-cell-padding: .9375rem !default;
220 | $table-cell-padding-sm: .9375rem !default;
221 |
222 | $table-accent-bg: $gray-100 !default;
223 | $table-hover-bg: $gray-100 !default;
224 |
225 | $table-border-color: $gray-200 !default;
226 |
227 | $table-head-bg: $gray-100 !default;
228 | $table-head-color: $text-muted !default;
229 |
230 |
231 | // Buttons + Forms
232 | //
233 | // Shared variables that are reassigned to `$input-` and `$btn-` specific variables.
234 |
235 | $input-btn-padding-y: .5rem !default;
236 | $input-btn-padding-x: .75rem !default;
237 | $input-btn-line-height: $line-height-base !default;
238 |
239 | $input-btn-focus-width: .15rem !default;
240 | $input-btn-focus-color: rgba($primary, .25) !default;
241 | $input-btn-focus-box-shadow: 0 0 0 $input-btn-focus-width $input-btn-focus-color !default;
242 |
243 | $input-btn-padding-y-sm: .125rem !default;
244 | $input-btn-padding-x-sm: .5rem !default;
245 | $input-btn-line-height-sm: $line-height-sm !default;
246 |
247 | $input-btn-padding-y-lg: .5rem !default;
248 | $input-btn-padding-x-lg: 1rem !default;
249 | $input-btn-line-height-lg: $line-height-lg !default;
250 |
251 |
252 | // Buttons
253 | //
254 | // For each of Bootstrap's buttons, define text, background, and border color.
255 |
256 | $btn-padding-y: $input-btn-padding-y !default;
257 | $btn-padding-x: $input-btn-padding-x !default;
258 | $btn-line-height: $input-btn-line-height !default;
259 |
260 | $btn-padding-y-sm: $input-btn-padding-y-sm !default;
261 | $btn-padding-x-sm: $input-btn-padding-x-sm !default;
262 | $btn-line-height-sm: $input-btn-line-height-sm !default;
263 |
264 | //Custom button color
265 | $btn-text-color: $white !default;
266 |
267 | $btn-padding-y-lg: $input-btn-padding-y-lg !default;
268 | $btn-padding-x-lg: $input-btn-padding-x-lg !default;
269 | $btn-line-height-lg: $input-btn-line-height-lg !default;
270 |
271 | $btn-font-weight: $font-weight-normal !default;
272 | $btn-focus-box-shadow: $input-btn-focus-box-shadow !default;
273 |
274 | $btn-link-disabled-color: $gray-500 !default;
275 |
276 |
277 | // Forms
278 |
279 | $input-padding-y: $input-btn-padding-y !default;
280 | $input-padding-x: $input-btn-padding-x !default;
281 | $input-line-height: $input-btn-line-height !default;
282 |
283 | $input-padding-y-sm: $input-btn-padding-y-sm !default;
284 | $input-padding-x-sm: $input-btn-padding-x-sm !default;
285 | $input-line-height-sm: $input-btn-line-height-sm !default;
286 |
287 | $input-padding-y-lg: $input-btn-padding-y-lg !default;
288 | $input-padding-x-lg: $input-btn-padding-x-lg !default;
289 | $input-line-height-lg: $input-btn-line-height-lg !default;
290 |
291 | $input-bg: $white !default;
292 | $input-disabled-bg: $input-bg !default;
293 |
294 | $input-color: $body-color !default;
295 | $input-border-color: $gray-400 !default;
296 |
297 | $input-focus-border-color: $primary !default;
298 | $input-focus-box-shadow: transparent !default;
299 |
300 | $input-placeholder-color: $gray-500 !default;
301 |
302 | $input-height-inner-sm: ($font-size-sm * $input-btn-line-height-sm) + ($input-btn-padding-y-sm * 2) !default;
303 |
304 | $form-group-margin-bottom: 1.375rem !default;
305 |
306 | $input-group-addon-bg: $input-bg !default;
307 | $input-group-addon-color: $text-muted !default;
308 |
309 | $custom-select-focus-border-color: $input-focus-border-color !default;
310 | $custom-select-focus-box-shadow: inset 0 1px 2px rgba($black, .075), 0 0 5px rgba($custom-select-focus-border-color, .5) !default;
311 |
312 | $custom-control-indicator-bg: $border-color !default;
313 | $custom-control-indicator-border-width: 0 !default;
314 |
315 | $custom-switch-width: 3rem !default;
316 | $custom-switch-indicator-size: 1.125rem !default;
317 | $custom-switch-indicator-border-radius: $custom-switch-indicator-size / 2 !default;
318 |
319 |
320 | // Dropdowns
321 | //
322 | // Dropdown menu container and contents.
323 |
324 | $dropdown-spacer: 0 !default;
325 | $dropdown-border-color: rgba($black, .1) !default;
326 |
327 | $dropdown-link-color: $gray-700 !default;
328 | $dropdown-link-hover-color: $black !default;
329 | $dropdown-link-hover-bg: transparent !default;
330 |
331 | $dropdown-link-active-color: $dropdown-link-hover-color !default;
332 | $dropdown-link-active-bg: $dropdown-link-hover-bg !default;
333 |
334 | $dropdown-item-padding-y: .375rem !default;
335 |
336 | $dropdown-header-color: inherit !default;
337 |
338 |
339 | // Navs
340 |
341 | $nav-tabs-border-color: $border-color !default;
342 | $nav-tabs-border-radius: 0 !default;
343 | $nav-tabs-link-hover-border-color: transparent transparent transparent !default;
344 | $nav-tabs-link-active-color: $body-color !default;
345 | $nav-tabs-link-active-bg: transparent !default;
346 | $nav-tabs-link-active-border-color: transparent transparent theme-color("primary") !default;
347 |
348 | $nav-pills-link-active-bg: $component-active-bg !default;
349 |
350 |
351 | // Navbar
352 |
353 | $navbar-padding-x: 1rem !default;
354 |
355 | $navbar-brand-font-size: $font-size-lg !default;
356 | $navbar-brand-padding-y: 0 !default;
357 |
358 | $navbar-toggler-padding-x: 0 !default;
359 |
360 | $navbar-dark-color: $gray-700 !default;
361 | $navbar-dark-hover-color: $white !default;
362 | $navbar-dark-active-color: $white !default;
363 | $navbar-dark-toggler-border-color: transparent !default;
364 |
365 | $navbar-light-color: $gray-700 !default;
366 | $navbar-light-hover-color: $black !default;
367 | $navbar-light-active-color: $black !default;
368 | $navbar-light-toggler-border-color: transparent !default;
369 |
370 |
371 | // Pagination
372 |
373 | $pagination-color: $black !default;
374 |
375 | $pagination-focus-box-shadow: $input-btn-focus-box-shadow !default;
376 |
377 | $pagination-hover-color: $dark !default;
378 | $pagination-hover-bg: $gray-100 !default;
379 | $pagination-hover-border-color: $gray-300 !default !default;
380 |
381 | $pagination-active-bg: $component-active-bg !default;
382 | $pagination-active-border-color: $pagination-active-bg !default;
383 |
384 |
385 | // Jumbotron
386 |
387 | $jumbotron-bg: $gray-200 !default;
388 |
389 |
390 | // Cards
391 |
392 | $card-spacer-y: 1rem !default;
393 | $card-spacer-x: $spacer !default;
394 | $card-border-width: $border-width !default;
395 | $card-border-radius: $border-radius-lg !default;
396 | $card-border-color: $gray-200 !default;
397 | $card-inner-border-radius: calc(#{$card-border-radius} - #{$card-border-width}) !default;
398 | $card-cap-bg: transparent !default;
399 |
400 |
401 | // Tooltips
402 |
403 | $tooltip-color: $black !default;
404 | $tooltip-bg: $gray-300 !default;
405 | $tooltip-opacity: 1 !default;
406 |
407 | $tooltip-arrow-color: $tooltip-bg !default;
408 |
409 |
410 | // Popovers
411 |
412 | $popover-bg: $white !default;
413 | $popover-max-width: 10rem !default;
414 | $popover-padding-x: .95rem !default;
415 | $popover-padding-y: .8rem !default;
416 | $popover-box-shadow: 0 0 1rem transparentize($black, .97) !default;
417 |
418 | $popover-header-bg: $popover-bg !default;
419 | $popover-header-padding-y: 0 !default;
420 | $popover-header-padding-x: 0 !default;
421 | $popover-header-margin-bottom: .25rem !default;
422 |
423 | $popover-body-color: $text-muted !default;
424 |
425 |
426 | // Toasts
427 |
428 | $toast-max-width: 300px !default;
429 | $toast-padding-x: 1rem !default;
430 | $toast-padding-y: 0.75rem !default;
431 | $toast-font-size: $font-size-base !default;
432 | $toast-background-color: $white !default;
433 | $toast-border-color: $border-color !default;
434 | $toast-border-radius: $border-radius !default;
435 | $toast-box-shadow: 0 0.75rem 1.5rem fade-out($black, .9) !default;
436 |
437 | $toast-header-color: $body-color !default;
438 | $toast-header-background-color: $toast-background-color !default;
439 | $toast-header-border-color: $border-color !default;
440 |
441 |
442 | // Badges
443 |
444 | $badge-font-weight: $font-weight-normal !default;
445 | $badge-padding-y: .33em !default;
446 |
447 |
448 | // Modals
449 |
450 | // Padding applied to the modal body
451 | $modal-inner-padding: 1.5rem !default;
452 |
453 | $modal-content-border-color: transparent !default;
454 |
455 | $modal-header-padding: 1.5rem !default;
456 | $modal-header-border-color: $border-color !default;
457 | $modal-footer-border-color: $border-color !default;
458 |
459 | $modal-md: 600px !default;
460 |
461 |
462 | // Alerts
463 | //
464 | // Define alert colors, border radius, and padding.
465 |
466 | $alert-link-font-weight: $font-weight-normal !default;
467 | $alert-margin-bottom: $spacer !default;
468 |
469 | $alert-bg-level: 0 !default;
470 | $alert-border-level: 0 !default;
471 | $alert-color-level: 6 !default;
472 |
473 |
474 | // Progress bars
475 |
476 | $progress-border-radius: 200px !default; // Always rounds even if height is manually set higher
477 |
478 |
479 | // List groups
480 |
481 | $list-group-bg: transparent;
482 | $list-group-border-color: $border-color !default;
483 |
484 |
485 | // Figures
486 |
487 | $figure-caption-font-size: $small-font-size !default;
488 |
489 |
490 | // Breadcrumbs
491 |
492 | $breadcrumb-padding-x: 0 !default;
493 |
494 | $breadcrumb-margin-bottom: 0 !default;
495 |
496 | $breadcrumb-bg: transparent !default;
497 | $breadcrumb-divider-color: $gray-400 !default;
498 | $breadcrumb-active-color: $gray-600 !default;
499 | $breadcrumb-divider: "" !default;
500 |
501 |
502 | // Close
503 |
504 | $close-color: $text-muted;
505 | $close-text-shadow: none !default;
506 |
507 |
508 | // Code
509 |
510 | $code-color: $blue !default;
511 |
512 |
513 | //
514 | // Dashkit =====================================
515 | //
516 |
517 | // Paths
518 |
519 | $path-to-fonts: '../fonts' !default;
520 | $path-to-img: '../img' !default;
521 |
522 |
523 | // Type
524 |
525 | $font-size-xs: ($font-size-base * .6666666667) !default; // 10px
526 |
527 | $headings-letter-spacing: -.02em !default;
528 |
529 | $display-letter-spacing: -.02em !default;
530 |
531 |
532 | // Alerts
533 |
534 | $alert-link-text-decoration: underline !default;
535 |
536 |
537 | // Auth
538 |
539 | $auth-bg: $white !default;
540 |
541 |
542 | // Avatar
543 |
544 | $avatar-size-base: 3rem !default;
545 | $avatar-size-xs: 1.625rem !default;
546 | $avatar-size-sm: 2.5rem !default;
547 | $avatar-size-lg: 4rem !default;
548 | $avatar-size-xl: 5.125rem !default;
549 | $avatar-size-xxl: 8rem !default;
550 |
551 | $avatar-title-bg: $gray-500 !default;
552 | $avatar-title-color: $white !default;
553 |
554 |
555 | // Badges
556 |
557 | $badge-soft-bg-level: -10 !default;
558 |
559 | $badge-padding-x: .5em !default;
560 |
561 |
562 | // Breadcrumb
563 |
564 | $breadcrumb-padding-y-sm: .5rem !default;
565 | $breadcrumb-padding-x-sm: .5rem !default;
566 | $breadcrumb-item-padding-sm: .25rem !default;
567 |
568 | $breadcrumb-margin-bottom-sm: .25rem !default;
569 | $breadcrumb-font-size-sm: $font-size-sm !default;
570 |
571 |
572 | // Cards
573 |
574 | $card-spacer-x-sm: 1rem !default;
575 |
576 | $card-outline-color: $card-border-color !default;
577 | $card-box-shadow: 0 .75rem 1.5rem transparentize($black, .97) !default;
578 |
579 | $card-header-min-height: 5rem !default;
580 |
581 |
582 | // Charts
583 |
584 | $chart-height: 300px !default;
585 | $chart-height-sm: 225px !default;
586 |
587 | $chart-sparkline-width: 75px !default;
588 | $chart-sparkline-height: 35px !default;
589 |
590 | $chart-legend-margin-top: 2.5rem !default;
591 | $chart-legend-font-size: $font-size-sm !default;
592 | $chart-legend-color: $text-muted !default;
593 | $chart-legend-height: $chart-legend-margin-top + $chart-legend-font-size * $line-height-base !default;
594 |
595 |
596 | // Comment
597 |
598 | $comment-margin-bottom: 1rem !default;
599 |
600 | $comment-body-padding-y: 1rem !default;
601 | $comment-body-padding-x: 1.25rem !default;
602 | $comment-body-bg: $body-bg !default;
603 | $comment-body-border-radius: $border-radius-lg !default;
604 | $comment-body-font-size: $font-size-sm !default;
605 |
606 | $comment-time-margin-bottom: .5625rem !default;
607 | $comment-time-font-size: $font-size-xs !default;
608 | $comment-time-color: $text-muted !default;
609 |
610 |
611 | // Dropdowns
612 |
613 | $dropdown-card-min-width: 350px !default;
614 | $dropdown-card-border-color: $dropdown-border-color !default;
615 | $dropdown-card-header-min-height: 3.125rem !default;
616 | $dropdown-card-body-max-height: 350px !default;
617 |
618 |
619 | // Header
620 |
621 | $header-margin-bottom: 2rem !default;
622 |
623 | $header-spacing-y: 1.5rem !default;
624 |
625 | $header-body-border-width: 1px !default;
626 | $header-body-border-color: $border-color !default;
627 |
628 | $header-body-border-color-dark: fade-out($header-body-border-color, .9) !default;
629 |
630 |
631 | // List groups
632 |
633 | $list-group-item-padding-y-lg: $spacer !default;
634 |
635 |
636 | // Main content
637 |
638 | $main-content-padding-y: 40px !default;
639 | $main-content-padding-x: 24px !default; // in px to combine with $grid-gutter-widthw
640 |
641 |
642 | // Modal
643 |
644 | $modal-dialog-vertical-width: 350px !default;
645 |
646 | $modal-card-body-max-height: 350px !default;
647 |
648 |
649 | // Navs
650 |
651 | $nav-link-padding-y: .5rem !default;
652 | $nav-link-padding-x: 1rem !default;
653 |
654 | $nav-tabs-link-active-border-width: 1px !default;
655 | $nav-tabs-link-margin-x: .75rem !default; // Margin used for X so active underline matches width of label
656 | $nav-tabs-link-padding-y: $card-spacer-y !default; // This keeps the height the same as the card header
657 |
658 | $nav-tabs-sm-font-size: .8125rem !default;
659 | $nav-tabs-sm-link-margin-x: .5rem !default;
660 |
661 |
662 | // Navbar
663 |
664 | $navbar-vertical-width: 250px !default;
665 | $navbar-vertical-width-sm: 66px !default;
666 |
667 | $navbar-vertical-padding-x: 1.5rem !default;
668 | $navbar-vertical-padding-x-sm: 0.75rem !default;
669 |
670 | $navbar-icon-min-width: 1.75rem !default;
671 |
672 | $navbar-breadcrumb-padding-y: $nav-link-padding-y !default;
673 | $navbar-breadcrumb-padding-x: 0 !default;
674 |
675 | $navbar-vibrant-border-color: transparent !default;
676 | $navbar-vibrant-heading-color: fade-out($white, .6) !default;
677 | $navbar-vibrant-divider-color: fade-out($white, .8) !default;
678 | $navbar-vibrant-color: fade-out($white, .3) !default;
679 | $navbar-vibrant-hover-color: $white !default;
680 | $navbar-vibrant-active-color: $white !default;
681 | $navbar-vibrant-brand-filter: brightness(0) invert(1) !default;
682 | $navbar-vibrant-toggler-icon-bg: str-replace(url("data:image/svg+xml,%3csvg viewBox='0 0 30 30' xmlns='http://www.w3.org/2000/svg'%3e%3cpath stroke='#{$navbar-vibrant-color}' stroke-width='2' stroke-linecap='round' stroke-miterlimit='10' d='M4 7h22M4 15h22M4 23h22'/%3e%3c/svg%3e"), "#", "%23") !default;
683 |
684 | $navbar-dark-bg: $gray-800-dark !default;
685 | $navbar-dark-border-color: $gray-800-dark !default;
686 | $navbar-dark-heading-color: $navbar-dark-color !default;
687 | $navbar-dark-divider-color: $gray-700-dark !default;
688 | $navbar-dark-brand-filter: none !default;
689 |
690 | $navbar-light-bg: $white !default;
691 | $navbar-light-border-color: $border-color !default;
692 | $navbar-light-heading-color: $text-muted !default;
693 | $navbar-light-divider-color: $border-color !default;
694 | $navbar-light-brand-filter: none;
695 |
696 | $navbar-dropdown-toggle-on-hover: true !default;
697 |
698 |
699 | // Progress bars
700 |
701 | $progress-height-sm: 0.25rem !default;
702 |
703 |
704 | // Forms
705 |
706 | $custom-switch-height: 1.5rem !default;
707 | $custom-switch-spacing: ($custom-switch-height - $custom-switch-indicator-size) / 2 !default;
708 |
709 | $custom-switch-indicator-bg: $white !default;
710 | $custom-switch-indicator-active-bg: $white !default;
711 |
712 |
713 | // Close
714 |
715 | $close-font-size-sm: $font-size-base !default;
716 |
717 |
718 | // Kanban
719 |
720 | $kanban-col-width: 375px !default;
721 |
722 |
723 | // Components
724 |
725 | $box-shadow-lift: 0 1rem 2.5rem fade-out($black, .9), 0 .5rem 1rem -.75rem fade-out($black, .9) !default;
726 | $box-shadow-lift-lg: 0 2rem 5rem fade-out($black, .9), 0 .5rem 1rem -.75rem fade-out($black, .95) !default;
727 | @import "../../../../node_modules/bootstrap/scss/variables";
728 |
729 |
--------------------------------------------------------------------------------
/src/assets/scss/shared.scss:
--------------------------------------------------------------------------------
1 | .btn-primary {
2 | background-color: $primary !important;
3 | border-color: $primary !important;
4 | }
5 |
6 | .badge {
7 | background: $nav-bg-color !important;
8 | }
9 |
10 | :root {
11 | --animate-duration: .3s !important;
12 | }
13 |
14 | .text-primary {
15 | color: $primary !important;
16 | }
17 |
18 | //hide announcements to start.. commented bc issue with announcement panel in home page
19 | //form[name="announcementListForm"] {
20 | // display: none;
21 | //}
22 |
23 | #favorite-settings-pane button[aria-checked=false] :first-child, #favorite-settings-pane button[aria-checked=true] :last-child {
24 | background-color: $nav-bg-color !important;
25 | }
26 |
27 | button:not(.btn-primary),
28 | a:not(.btn-primary).button,
29 | input[type="submit"]:not(.active),
30 | .Mrphs-toolTitleNav .Mrphs-toolTitleNav__link {
31 | background: $white !important;
32 | /*box-shadow: 0 2px 5px -5px black !important;*/
33 | /*border: 1px solid #d2d6da !important;*/
34 | }
35 |
36 | li.tab-btn.active,
37 | .navIntraTool li span.current {
38 | color: $primary !important;
39 | border-top: none !important;
40 | border-right: none !important;
41 | font-weight: 600;
42 | border-left: none !important;
43 | padding: 0 20px !important;
44 | border-bottom: 3px solid $primary !important;
45 | }
46 |
47 | li.tab-btn:not(.active):hover,
48 | .navIntraTool li span a:hover {
49 | border-bottom: 2px solid $tab-hover-color !important;
50 | }
51 |
52 | li.tab-btn,
53 | .navIntraTool li span a {
54 | border: none !important;
55 | padding: 0 20px !important;
56 | background: initial !important;
57 | }
58 |
59 | li.tab-btn:before,
60 | .navIntraTool li span a:before,
61 | .navIntraTool li span.current:before {
62 | display: none !important;
63 | }
64 |
65 | .textPanelHeader a[href] {
66 | color: $primary;
67 | }
68 |
69 | .textPanelHeader a[href]:hover {
70 | color: $nav-bg-color;
71 | }
72 |
73 |
74 | #selectSite .tab-bar .tab-btn.active:before, #selectQuickLink .tab-bar .tab-btn.active:before {
75 | border-color: $primary !important;
76 | }
77 |
78 | #selectSite .tab-bar .tab-btn.active, #selectQuickLink .tab-bar .tab-btn.active {
79 | color: $primary !important;
80 | font-weight: 500;
81 | }
82 |
83 | input[type=search]::-webkit-search-cancel-button {
84 | -webkit-appearance: searchfield-cancel-button;
85 | }
86 |
87 |
88 | .Mrphs-pagebody {
89 | padding: 20px 20px 0 20px !important;
90 | }
91 |
92 | .dark-mode-toggle:hover {
93 | color: white !important;
94 | text-shadow: 0 0 10px white;
95 | }
96 |
97 |
98 | .checklistLabel {
99 | font-weight: 500 !important;
100 | }
101 |
102 | .Mrphs-sitesNav__menuitem.view-all-sites-btn {
103 | cursor: pointer !important;
104 | }
105 |
106 | body, .itemclass, .link-div,
107 | h1, h2, h3, h4, h5, h6,
108 | #linkNav ul, a:not(.Mrphs-sitesNav__dropdown):not(.Mrphs-sitesNav__favbtn):not(.fa),
109 | input, button {
110 | font-family: "Inter", sans-serif !important;
111 | }
112 |
113 | .itemclass h1, h2, h3, h4, h5, h6 {
114 | font-family: "Inter", sans-serif !important;
115 | font-weight: 700 !important;
116 | }
117 |
118 | .itemclass h1 {
119 | color: $nav-bg-color !important;
120 | }
121 |
122 | .Mrphs-mainHeader .Mrphs-headerLogo {
123 | background-image: radial-gradient(circle farthest-corner at 10% 20%, rgb(21 0 37) 0%, rgba(32, 45, 58, 1) 81.3%) !important;
124 | }
125 |
126 | #toolMenu ul li .Mrphs-toolsNav__menuitem--link .Mrphs-toolsNav__menuitem--title, #subSites ul li .Mrphs-toolsNav__menuitem--link .Mrphs-toolsNav__menuitem--title {
127 | color: $sidebar-menu-active-text-color;
128 | }
129 |
130 | .modal-backdrop.fade.in, .modal-backdrop.fade {
131 | background-color: #000 !important;
132 | z-index: 11000 !important;
133 | }
134 |
135 | #toolMenu ul li .Mrphs-toolsNav__menuitem--link .Mrphs-toolsNav__menuitem--icon, #subSites ul li .Mrphs-toolsNav__menuitem--link .Mrphs-toolsNav__menuitem--icon {
136 | color: #0078ff !important;
137 | }
138 |
139 | /*Home panels*/
140 | .Mrphs-multipleTools .Mrphs-container.Mrphs-toolTitleNav.Mrphs-container.Mrphs-container--toolTitleNav {
141 | border-bottom-left-radius: 0 !important;
142 | border-bottom-right-radius: 0 !important;
143 |
144 | h2 {
145 | margin-left: 10px !important;
146 | }
147 | }
148 |
149 | .Mrphs-toolTitleNav.Mrphs-container--toolTitleNav {
150 | margin-left: 10px !important;
151 | }
152 |
153 | .Mrphs-toolTitleNav.Mrphs-container.Mrphs-container--toolTitleNav,
154 | .Mrphs-multipleTools .Mrphs-container .Mrphs-container--toolTitleNav {
155 | background-color: $white !important;
156 | border-bottom: 0 !important;
157 | }
158 |
159 |
160 | .Mrphs-multipleTools .Mrphs-container {
161 | border-radius: 10px !important;
162 | box-shadow: $box-shadow;
163 | }
164 |
165 | .Mrphs-toolTitleNav.Mrphs-container--toolTitleNav {
166 | border-top-left-radius: 10px !important;
167 | border-top-right-radius: 10px !important;
168 | }
169 |
170 | .Mrphs-multipleTools .Mrphs-container .Mrphs-toolBody {
171 | border-bottom-right-radius: 10px !important;
172 | border-bottom-left-radius: 10px !important;
173 | }
174 |
175 | .Mrphs-multipleTools .Mrphs-container .Mrphs-toolBody {
176 | border-top-left-radius: 0 !important;
177 | border-top-right-radius: 0 !important;
178 | }
179 |
180 | /* Override link colors */
181 | #toolMenu ul li.is-current .Mrphs-toolsNav__menuitem--link, #subSites ul li.is-current .Mrphs-toolsNav__menuitem--link,
182 | #toolMenu ul li.is-current .Mrphs-toolsNav__menuitem--link .Mrphs-toolsNav__menuitem--icon, #subSites ul li.is-current .Mrphs-toolsNav__menuitem--link .Mrphs-toolsNav__menuitem--icon,
183 | #toolMenu ul li .Mrphs-toolsNav__menuitem--link:hover .Mrphs-toolsNav__menuitem--icon, #toolMenu ul li .Mrphs-toolsNav__menuitem--link:focus .Mrphs-toolsNav__menuitem--icon, #subSites ul li .Mrphs-toolsNav__menuitem--link:hover .Mrphs-toolsNav__menuitem--icon, #subSites ul li .Mrphs-toolsNav__menuitem--link:focus .Mrphs-toolsNav__menuitem--icon,
184 | #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:hover .toolMenuIcon, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:active .toolMenuIcon, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:focus .toolMenuIcon, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:hover .toolMenuIcon, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:active .toolMenuIcon, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:focus .toolMenuIcon,
185 | .Mrphs-siteHierarchy a.Mrphs-hierarchy--toolName {
186 | color: $primary !important;
187 | }
188 |
189 | // minimized sidebar
190 | @media only screen and (min-width: 801px) {
191 | body.Mrphs-toolMenu-collapsed:not(.tool-maximised) #toolMenuWrap {
192 | min-width: 55px !important;
193 | }
194 |
195 | body.Mrphs-toolMenu-collapsed:not(.tool-maximised) #toolMenu ul li .Mrphs-toolsNav__menuitem--link:hover .Mrphs-toolsNav__menuitem--title, body.Mrphs-toolMenu-collapsed:not(.tool-maximised) #toolMenu ul li .Mrphs-toolsNav__menuitem--link:focus .Mrphs-toolsNav__menuitem--title, body.Mrphs-toolMenu-collapsed:not(.tool-maximised) #subSites:not(.floating) ul li .Mrphs-toolsNav__menuitem--link:hover .Mrphs-toolsNav__menuitem--title, body.Mrphs-toolMenu-collapsed:not(.tool-maximised) #subSites:not(.floating) ul li .Mrphs-toolsNav__menuitem--link:focus .Mrphs-toolsNav__menuitem--title {
196 | border-radius: 7px !important;
197 | margin-left: 0 !important;
198 | border: none !important;
199 | }
200 | body.Mrphs-toolMenu-collapsed:not(.tool-maximised) #toolMenu ul li.is-current .Mrphs-toolsNav__menuitem--link:hover .Mrphs-toolsNav__menuitem--title, body.Mrphs-toolMenu-collapsed:not(.tool-maximised) #subSites:not(.floating) ul li.is-current .Mrphs-toolsNav__menuitem--link:hover .Mrphs-toolsNav__menuitem--title {
201 | background: inherit !important;
202 | }
203 | }
204 |
205 | #linkNav ul li.Mrphs-sitesNav__menuitem .link-container {
206 | border-radius: 7px !important;
207 | padding-left: 20px !important;
208 | padding-right: 20px !important;
209 | }
210 |
211 | #toolMenu ul li .Mrphs-toolsNav__menuitem--link:hover, #toolMenu ul li .Mrphs-toolsNav__menuitem--link:focus, #subSites ul li .Mrphs-toolsNav__menuitem--link:hover, #subSites ul li .Mrphs-toolsNav__menuitem--link:focus {
212 | border-radius: 7px !important;
213 | }
214 |
215 | .Mrphs-sitesNav__dropdown, .Mrphs-sitesNav__favbtn {
216 | display: none !important;
217 | }
218 |
219 | #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:hover, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:active, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:focus, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:hover, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:active, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:focus {
220 | color: #6b0eff !important;
221 | font-weight: 600 !important;
222 | }
223 |
224 | a.btn-primary,
225 | button.btn-primary, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected, .act .active,
226 | #linkNav ul li.Mrphs-sitesNav__menuitem.is-selected .link-container, #linkNav ul li.Mrphs-sitesNav__menuitem.is-selected .Mrphs-sitesNav__dropdown, #linkNav ul li.Mrphs-sitesNav__menuitem.is-selected .Mrphs-sitesNav__favbtn {
227 | background: $nav-bg-color !important;
228 | //border-color: #5502db !important;
229 | border: none !important;
230 | border-radius: 7px !important;
231 | color: white !important;
232 | }
233 |
234 | a.btn-primary:hover,
235 | button.btn-primary:hover, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button:hover, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected:hover, button.btn-primary:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button:focus, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected:focus, .act .active:hover, .act .active:focus,
236 | #linkNav ul li.Mrphs-sitesNav__menuitem.is-selected .link-container:hover, #linkNav ul li.Mrphs-sitesNav__menuitem.is-selected .Mrphs-sitesNav__dropdown:hover, #linkNav ul li.Mrphs-sitesNav__menuitem.is-selected .Mrphs-sitesNav__favbtn:hover {
237 | background: #8025ff !important;
238 | color: white !important;
239 | }
240 |
241 | #linkNav ul li.Mrphs-sitesNav__menuitem.is-selected {
242 | background: none !important;
243 | }
244 |
245 | #toolMenu ul li.is-current .Mrphs-toolsNav__menuitem--link:before, #subSites ul li.is-current .Mrphs-toolsNav__menuitem--link:before,
246 | #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:hover:before, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:active:before, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:focus:before, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:hover:before, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:active:before, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:focus:before,
247 | .navIntraTool li span.current:before {
248 | /*border-color: $primary !important;*/
249 | border: none !important;
250 | }
251 |
252 |
253 | #toolMenu ul li.is-current .Mrphs-toolsNav__menuitem--link, #subSites ul li.is-current .Mrphs-toolsNav__menuitem--link {
254 | background-color: $sidebar-menu-active-bg-color !important;
255 | border-radius: 7px !important;
256 | border: none !important;
257 | }
258 |
259 | #toolMenu ul li.is-current, #subSites ul li.is-current {
260 | margin: 1px 0 !important;
261 | }
262 |
263 | .Mrphs-toolsNav__menuitem--link:not(.is-current) {
264 | margin: 0 7px !important;
265 | }
266 |
267 |
268 | /*Sidebar link (NON-ACTIVE) left tab bar */
269 | #toolMenu ul li .Mrphs-toolsNav__menuitem--link:hover:before, #toolMenu ul li .Mrphs-toolsNav__menuitem--link:focus:before, #subSites ul li .Mrphs-toolsNav__menuitem--link:hover:before, #subSites ul li .Mrphs-toolsNav__menuitem--link:focus:before {
270 | border-left: none !important;
271 | }
272 |
273 | a[href]:focus {
274 | outline: none !important;
275 | }
276 |
277 |
278 | table a[href]:not(.btn-primary),
279 | .attachList a[href],
280 | .subpage-breadcrumb-div a[href] {
281 | color: $primary !important;
282 | text-decoration: none !important;
283 | }
284 |
285 | table a[href]:not(.btn-primary):hover,
286 | .attachList a[href]:hover,
287 | .subpage-breadcrumb-div a[href]:hover {
288 | color: $link-hover-color !important;
289 | }
290 |
291 |
292 | /* Sidebar font weight active link */
293 | #toolMenu ul li.is-current .Mrphs-toolsNav__menuitem--link .Mrphs-toolsNav__menuitem--title, #subSites ul li.is-current .Mrphs-toolsNav__menuitem--link .Mrphs-toolsNav__menuitem--title {
294 | font-weight: 600 !important;
295 | border: none !important;
296 | }
297 |
298 |
299 | .Mrphs-mainHeader .Mrphs-headerLogo {
300 | width: 100% !important;
301 | padding: 0 10px !important;
302 | height: 52px !important;
303 | /*background: #515151 !important;*/
304 | }
305 |
306 | .sakai-table-toolBar .sakai-table-pagerControls label {
307 | display: none !important;
308 | }
309 |
310 | .Mrphs-mainHeader .Mrphs-headerLogo .Mrphs-headerLogo--institution {
311 | background: url(#{$logoUrl}) no-repeat center center !important;
312 | }
313 |
314 | .form-control::-ms-expand {
315 | background-color: transparent !important;
316 | border: 0 !important;
317 | }
318 |
319 | .tablesorter-filter.form-control {
320 | height: 27px !important;
321 | }
322 |
323 |
324 | a[href] {
325 | text-decoration: none !important;
326 | }
327 |
328 | .itemAction {
329 | top: 0 !important;
330 | }
331 |
332 | /* Custom Editing of Site Name*/
333 | ul.favoriteSiteList > li, #selectQuickLink > li {
334 | width: 365px !important;
335 | }
336 |
337 | /*active colour*/
338 | .button_color:focus, input:focus[type="submit"], .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate > a.paginate_button:focus, input:focus[type="button"], input:focus[type="reset"], button:not(.fc-button):focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .paginate_button:not(.fc-button):focus, .Mrphs-sakai-samigo #authorIndexForm\:remove-selected:not(.fc-button):focus, .button:focus, #mastLogin #loginForm .Mrphs-loginForm__button:focus, .Mrphs-siteStatus.is-unpublished button:focus, .Mrphs-siteStatus.is-unpublished .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .paginate_button:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .Mrphs-siteStatus.is-unpublished .paginate_button:focus, .Mrphs-siteStatus.is-unpublished .Mrphs-sakai-samigo #authorIndexForm\:remove-selected:focus, .Mrphs-sakai-samigo .Mrphs-siteStatus.is-unpublished #authorIndexForm\:remove-selected:focus, .lessonsToolButton:focus, .Mrphs-sakai-message-bundle-manager .dataTables_wrapper table a:focus[role="button"], ul#otherSitesMenu li:not(.otherSitesMenuClose) a:focus, #cookie-notice #cookie-notice-close:focus, a[href].button:focus, #mastLogin #loginForm a.Mrphs-loginForm__button[href]:focus, a.lessonsToolButton[href]:focus, .Mrphs-sakai-message-bundle-manager .dataTables_wrapper table a[href]:focus[role="button"], ul#otherSitesMenu li:not(.otherSitesMenuClose) a[href]:focus, #cookie-notice a#cookie-notice-close[href]:focus, button.ui-state-default:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .ui-state-default.paginate_button:focus, .Mrphs-sakai-samigo .ui-state-default#authorIndexForm\:remove-selected:focus, .btn-group .btn:focus, .btn.btn-default:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span a.btn.paginate_button:focus, .button.link:focus, #mastLogin #loginForm .link.Mrphs-loginForm__button:focus, .Mrphs-siteStatus.is-unpublished button.link:focus, .Mrphs-siteStatus.is-unpublished .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .link.paginate_button:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .Mrphs-siteStatus.is-unpublished .link.paginate_button:focus, .Mrphs-siteStatus.is-unpublished .Mrphs-sakai-samigo .link#authorIndexForm\:remove-selected:focus, .Mrphs-sakai-samigo .Mrphs-siteStatus.is-unpublished .link#authorIndexForm\:remove-selected:focus, .link.lessonsToolButton:focus, .Mrphs-sakai-message-bundle-manager .dataTables_wrapper table a.link:focus[role="button"], ul#otherSitesMenu li:not(.otherSitesMenuClose) a.link:focus, #cookie-notice .link#cookie-notice-close:focus, a.btn-link:focus, button.btn-link:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-link.paginate_button:focus, .Mrphs-sakai-samigo .btn-link#authorIndexForm\:remove-selected:focus {
339 | outline: none !important;
340 | }
341 |
342 | .tablesorter-icon.glyphicon.glyphicon-chevron-down,
343 | .tablesorter-icon.glyphicon.glyphicon-chevron-up,
344 | .tablesorter-icon.bootstrap-icon-unsorted {
345 | display: none !important;
346 | }
347 |
348 |
349 | .Mrphs-sakai-announcements .message-body {
350 | background-color: #f9fbfd !important;
351 | border: 1px solid #e3ebf6 !important;
352 | }
353 |
354 | /*#linkNav ul li.Mrphs-sitesNav__menuitem.is-selected .link-container:active {*/
355 | /* background: #5909d4 !important;*/
356 | /*}*/
357 |
358 | .subpage-breadcrumb-div {
359 | margin-bottom: 1.5rem !important;
360 | box-shadow: 0 0.75rem 1.5rem rgb(239 239 239) !important;
361 | padding: 10px 10px 10px 30px !important;
362 | border-radius: 3px !important;
363 | border: solid 1px #edf2f9 !important;
364 | }
365 |
366 | /* Disabled button */
367 | button.btn-primary[disabled="disabled"], .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled="disabled"], .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled="disabled"], button.btn-primary[disabled="disabled"]:hover, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled="disabled"]:hover, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled="disabled"]:hover, button.btn-primary[disabled="disabled"]:active, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled="disabled"]:active, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled="disabled"]:active, button.btn-primary[disabled="disabled"]:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled="disabled"]:focus, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled="disabled"]:focus, button.btn-primary[disabled], .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled], .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled], button.btn-primary[disabled]:hover, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled]:hover, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled]:hover, button.btn-primary[disabled]:active, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled]:active, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled]:active, button.btn-primary[disabled]:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled]:focus, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled]:focus, button.btn-primary[disabled="true"], .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled="true"], .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled="true"], button.btn-primary[disabled="true"]:hover, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled="true"]:hover, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled="true"]:hover, button.btn-primary[disabled="true"]:active, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled="true"]:active, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled="true"]:active, button.btn-primary[disabled="true"]:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[disabled="true"]:focus, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[disabled="true"]:focus, button.btn-primary[class="disabled"], .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[class="disabled"], .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[class="disabled"], button.btn-primary[class="disabled"]:hover, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[class="disabled"]:hover, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[class="disabled"]:hover, button.btn-primary[class="disabled"]:active, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[class="disabled"]:active, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[class="disabled"]:active, button.btn-primary[class="disabled"]:focus, .Mrphs-sakai-samigo .dataTables_wrapper .dataTables_paginate span .btn-primary.paginate_button[class="disabled"]:focus, .Mrphs-sakai-samigo .btn-primary#authorIndexForm\:remove-selected[class="disabled"]:focus, .act .active[disabled="disabled"], .act .active[disabled="disabled"]:hover, .act .active[disabled="disabled"]:active, .act .active[disabled="disabled"]:focus, .act .active[disabled], .act .active[disabled]:hover, .act .active[disabled]:active, .act .active[disabled]:focus, .act .active[disabled="true"], .act .active[disabled="true"]:hover, .act .active[disabled="true"]:active, .act .active[disabled="true"]:focus, .act .active[class="disabled"], .act .active[class="disabled"]:hover, .act .active[class="disabled"]:active, .act .active[class="disabled"]:focus {
368 | background: #f2f2f2 !important;
369 | color: #4c4b4b !important;
370 | border: solid 1px #edf2f9 !important;
371 | }
372 |
373 |
374 | .progress-bar.progress-bar-empty {
375 | background: rgb(238, 246, 254) !important;
376 | /*background-image: radial-gradient(circle 1224px at 10.6% 8.8%, rgba(255, 255, 255, 1) 0%, rgba(153, 202, 251, 1) 100.2%) !important;*/
377 | }
378 |
379 | .progress-bar.progress-bar-active.progress-bar-active {
380 | background-image: linear-gradient(90deg, rgba(147,15,255,1) 0%, rgba(123,24,255,1) 6%, rgba(59,49,255,1) 70%, rgba(147,15,255,1) 100%) !important;
381 | }
382 |
383 | .progress:nth-child(2) {
384 | color: blue !important;
385 | }
386 |
387 |
388 | .Mrphs-sakai-lessonbuildertool .portletBody .column {
389 | background-clip: border-box !important;
390 | border: 1px solid #edf2f9 !important;
391 | border-radius: .5rem !important;
392 | box-shadow: 0 .5rem 1rem rgba(18, 38, 63, .15) !important;
393 | }
394 |
395 | ///* hover link bg*/
396 | //#toolMenu ul li .Mrphs-toolsNav__menuitem--link:hover, #toolMenu ul li .Mrphs-toolsNav__menuitem--link:focus, #subSites ul li .Mrphs-toolsNav__menuitem--link:hover, #subSites ul li .Mrphs-toolsNav__menuitem--link:focus,
397 | //#linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:hover, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:active, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem .Mrphs-sitesNav__submenuitem-link:focus, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:hover, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:active, #linkNav ul li.Mrphs-sitesNav__menuitem .Mrphs-sitesNav__submenu .Mrphs-sitesNav__submenuitem a:focus {
398 | // background: #faf1fd !important;
399 | //}
400 |
401 |
402 | /** Forms */
403 | .form-control {
404 | display: block !important;
405 | width: 100% !important;
406 | padding: .375rem .75rem !important;
407 | font-weight: normal !important;
408 | line-height: 1.5 !important;
409 | color: #495057 !important;
410 | background-color: #fff !important;
411 | background-clip: padding-box !important;
412 | border: 2px solid #dde2ec !important;
413 | border-radius: 4px !important;
414 | -webkit-transition: border-color .15s ease-in-out, -webkit-box-shadow .15s ease-in-out !important;
415 | transition: border-color .15s ease-in-out, -webkit-box-shadow .15s ease-in-out !important;
416 | transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out !important;
417 | transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out, -webkit-box-shadow .15s ease-in-out
418 | }
419 |
420 |
421 | /*ghost white*/
422 | .table > thead > tr > th {
423 | background-color: #f9fbfd !important;
424 | }
425 |
426 | .form-control:focus {
427 | color: #495057 !important;
428 | background-color: #fff !important;
429 | border-color: $nav-bg-color !important;
430 | outline: 0 !important;
431 | -webkit-box-shadow: none !important;
432 | box-shadow: none !important;
433 | }
434 |
435 | .Mrphs-multipleTools .Mrphs-toolTitleNav .Mrphs-toolTitleNav__title {
436 | color: $text-color !important;
437 | font-size: 1.2em !important;
438 | }
439 |
440 | .form-control::-webkit-input-placeholder {
441 | color: #636c72 !important;
442 | opacity: 1 !important;
443 | }
444 |
445 | .form-control::-moz-placeholder {
446 | color: #636 !important;
447 | opacity: 1
448 | }
449 |
450 | .form-control::-ms-input-placeholder {
451 | color: #636c72 !important;
452 | opacity: 1 !important;
453 | }
454 |
455 | .form-control::placeholder {
456 | color: #636c72 !important;
457 | opacity: 1 !important;
458 | }
459 |
460 |
461 | .form-control:disabled, .form-control[readonly] {
462 | background-color: #e9ecef !important;
463 | opacity: 1 !important;
464 | }
465 |
466 | .tablesorter-header[role=columnheader] {
467 | background-color: initial !important;
468 | }
469 |
470 | .table>thead>tr>th, .table>thead>tr>td, .table>tbody>tr>th, .table>tbody>tr>td, .table>tfoot>tr>th, .table>tfoot>tr>td {
471 | border-top: none !important;
472 | }
473 |
474 | #mastLogin #loginForm {
475 | border-left: 1px solid #5f5f5f;
476 | padding-left: 15px !important;
477 | margin-left: 15px !important;
478 | }
479 |
480 | .Mrphs-container--toolTitleNav,
481 | .Mrphs-toolBody, .portletBody {
482 | padding-left: 10px !important;
483 | }
484 |
485 | .Mrphs-toolTitleNav.Mrphs-container.Mrphs-container--toolTitleNav {
486 | padding-left: 10px !important;
487 | }
488 |
489 | .Mrphs-toolTitleNav {
490 | padding-left: 10px !important;
491 | }
492 |
493 | #selectSiteModal {
494 | border-radius: 20px !important;
495 | }
496 |
--------------------------------------------------------------------------------