diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 564449be1717a97282b53b2d94f9f234b34261c2..cf02f39e36aa6fa715f8e3c73c8069433c44f497 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,21 +1,21 @@ include: - - project: "AlekSIS/official/AlekSIS" - file: /ci/general.yml - - project: "AlekSIS/official/AlekSIS" - file: /ci/prepare/lock.yml - - project: "AlekSIS/official/AlekSIS" - file: /ci/test/test.yml - - project: "AlekSIS/official/AlekSIS" - file: /ci/test/lint.yml - - project: "AlekSIS/official/AlekSIS" - file: /ci/test/security.yml - - project: "AlekSIS/official/AlekSIS" - file: /ci/build/dist.yml - - project: "AlekSIS/official/AlekSIS" - file: /ci/publish/pypi.yml - - project: "AlekSIS/official/AlekSIS" - file: /ci/docker/image.yml - - project: "AlekSIS/official/AlekSIS" - file: "/ci/deploy/review.yml" - - project: "AlekSIS/official/AlekSIS" - file: "/ci/deploy/trigger_dist.yml" + - project: "AlekSIS/official/AlekSIS" + file: /ci/general.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/prepare/lock.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/test/test.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/test/lint.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/test/security.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/build/dist.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/publish/pypi.yml + - project: "AlekSIS/official/AlekSIS" + file: /ci/docker/image.yml + - project: "AlekSIS/official/AlekSIS" + file: "/ci/deploy/review.yml" + - project: "AlekSIS/official/AlekSIS" + file: "/ci/deploy/trigger_dist.yml" diff --git a/aleksis/core/assets/app.js b/aleksis/core/assets/app.js index 32d4f1b0ed34fea9327b7b1c83257b15009eabd1..148612e2951728137b26e6a93cd98c0cf1112129 100644 --- a/aleksis/core/assets/app.js +++ b/aleksis/core/assets/app.js @@ -1,74 +1,82 @@ -import Vue from "vue" -import VueRouter from "vue-router" -import Vuetify from "vuetify" -import "vuetify/dist/vuetify.min.css" +import Vue from "vue"; +import VueRouter from "vue-router"; +import Vuetify from "vuetify"; +import "vuetify/dist/vuetify.min.css"; -import ApolloClient from 'apollo-boost' -import VueApollo from 'vue-apollo' -import gql from 'graphql-tag' +import ApolloClient from "apollo-boost"; +import VueApollo from "vue-apollo"; -import "./css/global.scss" -import VueI18n from 'vue-i18n' +import "./css/global.scss"; +import VueI18n from "vue-i18n"; -import messages from "./messages.json" +import messages from "./messages.json"; -Vue.use(VueI18n) +Vue.use(VueI18n); const i18n = new VueI18n({ - locale: "en", - fallbackLocale: "en", - messages + locale: "en", + fallbackLocale: "en", + messages, }); // Using this function, apps can register their locale files i18n.registerLocale = function (messages) { - for (let locale in messages) { - i18n.mergeLocaleMessage(locale, messages[locale]); - } + for (let locale in messages) { + i18n.mergeLocaleMessage(locale, messages[locale]); + } }; -Vue.use(Vuetify) -Vue.use(VueRouter) +Vue.use(Vuetify); +Vue.use(VueRouter); const vuetify = new Vuetify({ - // TODO: load theme data dynamically - // - find a way to load template context data - // - include all site preferences - // - load menu stuff to render the sidenav - icons: { - iconfont: 'mdi', // default - only for display purposes - values: { - cancel: 'mdi-close-circle-outline', - delete: 'mdi-close-circle-outline', - success: 'mdi-check-circle-outline', - info: 'mdi-information-outline', - warning: 'mdi-alert-outline', - error: 'mdi-alert-octagon-outline', - prev: 'mdi-chevron-left', - next: 'mdi-chevron-right', - checkboxOn: 'mdi-checkbox-marked-outline', - checkboxIndeterminate: 'mdi-minus-box-outline', - edit: 'mdi-pencil-outline', - }, + // TODO: load theme data dynamically + // - find a way to load template context data + // - include all site preferences + // - load menu stuff to render the sidenav + icons: { + iconfont: "mdi", // default - only for display purposes + values: { + cancel: "mdi-close-circle-outline", + delete: "mdi-close-circle-outline", + success: "mdi-check-circle-outline", + info: "mdi-information-outline", + warning: "mdi-alert-outline", + error: "mdi-alert-octagon-outline", + prev: "mdi-chevron-left", + next: "mdi-chevron-right", + checkboxOn: "mdi-checkbox-marked-outline", + checkboxIndeterminate: "mdi-minus-box-outline", + edit: "mdi-pencil-outline", }, - theme: { - dark: JSON.parse(document.getElementById("design-mode").textContent) === "dark", - themes: { - light: { - primary: JSON.parse(document.getElementById("primary-color").textContent), - secondary: JSON.parse(document.getElementById("secondary-color").textContent), - }, - dark: { - primary: JSON.parse(document.getElementById("primary-color").textContent), - secondary: JSON.parse(document.getElementById("secondary-color").textContent), - }, - }, + }, + theme: { + dark: + JSON.parse(document.getElementById("design-mode").textContent) === "dark", + themes: { + light: { + primary: JSON.parse( + document.getElementById("primary-color").textContent + ), + secondary: JSON.parse( + document.getElementById("secondary-color").textContent + ), + }, + dark: { + primary: JSON.parse( + document.getElementById("primary-color").textContent + ), + secondary: JSON.parse( + document.getElementById("secondary-color").textContent + ), + }, }, -}) + }, +}); const apolloClient = new ApolloClient({ - uri: JSON.parse(document.getElementById("graphql-url").textContent) -}) + uri: JSON.parse(document.getElementById("graphql-url").textContent), +}); import CacheNotification from "./components/CacheNotification.vue"; import LanguageForm from "./components/LanguageForm.vue"; @@ -78,54 +86,54 @@ import SidenavSearch from "./components/SidenavSearch.vue"; Vue.component(MessageBox.name, MessageBox); // Load MessageBox globally as other components depend on it -Vue.use(VueApollo) +Vue.use(VueApollo); const apolloProvider = new VueApollo({ defaultClient: apolloClient, -}) +}); const router = new VueRouter({ mode: "history", -// routes: [ -// { path: "/", component: "TheApp" }, -// } + // routes: [ + // { path: "/", component: "TheApp" }, + // } }); const app = new Vue({ - el: '#app', - apolloProvider, - vuetify: vuetify, - // delimiters: ["<%","%>"] // FIXME: discuss new delimiters, [[ <% [{ {[ <[ (( … - data: () => ({ - drawer: vuetify.framework.breakpoint.lgAndUp, - group: null, // what does this mean? - urls: window.Urls, - django: window.django, - // FIXME: maybe just use window.django in every component or find a suitable way to access this property everywhere - showCacheAlert: false, - systemProperties: { - currentLanguage: "en", - availableLanguages: [], - }, - }), - apollo: { - systemProperties: require("./systemProperties.graphql"), + el: "#app", + apolloProvider, + vuetify: vuetify, + // delimiters: ["<%","%>"] // FIXME: discuss new delimiters, [[ <% [{ {[ <[ (( … + data: () => ({ + drawer: vuetify.framework.breakpoint.lgAndUp, + group: null, // what does this mean? + urls: window.Urls, + django: window.django, + // FIXME: maybe just use window.django in every component or find a suitable way to access this property everywhere + showCacheAlert: false, + systemProperties: { + currentLanguage: "en", + availableLanguages: [], }, - watch: { - systemProperties: function (newProperties) { - this.$i18n.locale = newProperties.currentLanguage; - this.$vuetify.lang.current = newProperties.currentLanguage; - } + }), + apollo: { + systemProperties: require("./systemProperties.graphql"), + }, + watch: { + systemProperties: function (newProperties) { + this.$i18n.locale = newProperties.currentLanguage; + this.$vuetify.lang.current = newProperties.currentLanguage; }, - components: { - "cache-notification": CacheNotification, - "language-form": LanguageForm, - "notification-list": NotificationList, - "sidenav-search": SidenavSearch, - }, - router, - i18n -}) + }, + components: { + "cache-notification": CacheNotification, + "language-form": LanguageForm, + "notification-list": NotificationList, + "sidenav-search": SidenavSearch, + }, + router, + i18n, +}); window.app = app; window.router = router; diff --git a/aleksis/core/assets/components/CacheNotification.vue b/aleksis/core/assets/components/CacheNotification.vue index d636a056cab92f3464a602d9a02af923197c2a35..f30adbd0bf8f02016216d9285382f7e68e30649c 100644 --- a/aleksis/core/assets/components/CacheNotification.vue +++ b/aleksis/core/assets/components/CacheNotification.vue @@ -1,25 +1,25 @@ <template> <message-box :value="cache" type="warning"> - {{ $t('alerts.page_cached') }} + {{ $t("alerts.page_cached") }} </message-box> </template> <script> - export default { - name: "cache-notification", - data () { - return { - cache: false, - } - }, - created() { - this.channel = new BroadcastChannel("cache-or-not"); - this.channel.onmessage = (event) => { - this.cache = event.data === true; - } - }, - destroyed(){ - this.channel.close() - }, - } +export default { + name: "CacheNotification", + data() { + return { + cache: false, + }; + }, + created() { + this.channel = new BroadcastChannel("cache-or-not"); + this.channel.onmessage = (event) => { + this.cache = event.data === true; + }; + }, + destroyed() { + this.channel.close(); + }, +}; </script> diff --git a/aleksis/core/assets/components/LanguageForm.vue b/aleksis/core/assets/components/LanguageForm.vue index 2897d3a3057c8e11211bc16149b137aa573e1021..d9b0d0b707e279500701350affb843388161e1ba 100644 --- a/aleksis/core/assets/components/LanguageForm.vue +++ b/aleksis/core/assets/components/LanguageForm.vue @@ -1,31 +1,31 @@ <template> <v-menu offset-y> - <template v-slot:activator="{ on, attrs }"> - <v-btn - depressed - v-bind="attrs" - v-on="on" - color="primary" - > + <template #activator="{ on, attrs }"> + <v-btn depressed v-bind="attrs" v-on="on" color="primary"> <v-icon icon color="white">mdi-translate</v-icon> {{ $i18n.locale }} </v-btn> </template> <v-list id="language-dropdown" class="dropdown-content" min-width="150"> <v-skeleton-loader - v-if="!$root.systemProperties.availableLanguages" - class="mx-auto" - type="list-item, list-item, list-item" + v-if="!$root.systemProperties.availableLanguages" + class="mx-auto" + type="list-item, list-item, list-item" ></v-skeleton-loader> <v-list-item-group - v-if="$root.systemProperties.availableLanguages" - v-model="$i18n.locale" - color="primary" + v-if="$root.systemProperties.availableLanguages" + v-model="$i18n.locale" + color="primary" > - <v-list-item v-for="languageOption in $root.systemProperties.availableLanguages" :key="languageOption.code" - :value="languageOption.code" - @click="setLanguage(languageOption)"> - <v-list-item-title>{{ languageOption.nameTranslated }}</v-list-item-title> + <v-list-item + v-for="languageOption in $root.systemProperties.availableLanguages" + :key="languageOption.code" + :value="languageOption.code" + @click="setLanguage(languageOption)" + > + <v-list-item-title>{{ + languageOption.nameTranslated + }}</v-list-item-title> </v-list-item> </v-list-item-group> </v-list> @@ -36,8 +36,8 @@ export default { data: function () { return { - language: this.$i18n.locale - } + language: this.$i18n.locale, + }; }, methods: { setLanguage: function (languageOption) { @@ -46,6 +46,6 @@ export default { this.$vuetify.lang.current = languageOption.code; }, }, - name: "language-form", -} + name: "LanguageForm", +}; </script> diff --git a/aleksis/core/assets/components/MessageBox.vue b/aleksis/core/assets/components/MessageBox.vue index 2a4cb17295835f5d3d1eb6f310a935eb4c2789be..4c79f4d51a36123f4e91f4e187e594d83387e1d3 100644 --- a/aleksis/core/assets/components/MessageBox.vue +++ b/aleksis/core/assets/components/MessageBox.vue @@ -1,15 +1,15 @@ <script> - export default { - name: "message-box", - // Due to this component being a wrapper to a v-alert, all props of this can be used (and overridden). - } +export default { + name: "MessageBox", + // Due to this component being a wrapper to a v-alert, all props of this can be used (and overridden). +}; </script> <template> - <v-alert border="left" text v-bind="$attrs"> - <slot> - Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. - </slot> - </v-alert> + <v-alert border="left" text v-bind="$attrs"> + <slot> + Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod + tempor incididunt ut labore et dolore magna aliqua. + </slot> + </v-alert> </template> - diff --git a/aleksis/core/assets/components/SidenavSearch.vue b/aleksis/core/assets/components/SidenavSearch.vue index 30fdbe9596487061d962c82af968f659fa524e5f..1c94ce9ef82ef7c0005bceab7d3280383a641f73 100644 --- a/aleksis/core/assets/components/SidenavSearch.vue +++ b/aleksis/core/assets/components/SidenavSearch.vue @@ -1,21 +1,36 @@ <script> - export default { - methods: { - submit: function () { - this.$refs.form.submit() - }, +export default { + methods: { + submit: function () { + this.$refs.form.submit(); }, - props: ["action", "placeholder"], - name: "sidenav-search", - } - // FIXME: implement suggestions etc, use "loading" attribute + }, + props: { + action: { + type: String, + required: true, + }, + placeholder: { + type: String, + required: true, + }, + }, + name: "SidenavSearch", +}; +// FIXME: implement suggestions etc, use "loading" attribute </script> <template> <form method="get" ref="form" :action="action" id="search-form"> <v-text-field - :append-icon="'mdi-magnify'" @click:append="submit" single-line - id="search" name="q" type="search" enterkeyhint="search" :placeholder="placeholder" + :append-icon="'mdi-magnify'" + @click:append="submit" + single-line + id="search" + name="q" + type="search" + enterkeyhint="search" + :placeholder="placeholder" ></v-text-field> </form> </template> diff --git a/aleksis/core/assets/components/notifications/NotificationItem.vue b/aleksis/core/assets/components/notifications/NotificationItem.vue index 2035cbd69d664c59d63ab95cd39571b27842d74e..3659f1f2794382722b9e7671edd831c9bc4a0911 100644 --- a/aleksis/core/assets/components/notifications/NotificationItem.vue +++ b/aleksis/core/assets/components/notifications/NotificationItem.vue @@ -3,10 +3,8 @@ :mutation="require('./markNotificationRead.graphql')" :variables="{ id: this.notification.id }" > - <template v-slot="{ mutate, loading, error }"> - <v-list-item - v-intersect="mutate" - > + <template #default="{ mutate, loading, error }"> + <v-list-item v-intersect="mutate"> <v-list-item-content> <v-list-item-title>{{ notification.title }}</v-list-item-title> @@ -22,7 +20,7 @@ <v-list-item-action v-if="notification.link"> <v-btn text :href="notification.link"> - {{ $t('notifications.more_information') }} → + {{ $t("notifications.more_information") }} → </v-btn> </v-list-item-action> @@ -35,9 +33,12 @@ </template> <script> - export default { - props: { - notification: Object, +export default { + props: { + notification: { + type: Object, + required: true, }, - } + }, +}; </script> diff --git a/aleksis/core/assets/components/notifications/NotificationList.vue b/aleksis/core/assets/components/notifications/NotificationList.vue index cb42dc17af31525d437594e268139401a2186a00..9e057ef7f4093f01d072bb88b6e99f2cb13841f8 100644 --- a/aleksis/core/assets/components/notifications/NotificationList.vue +++ b/aleksis/core/assets/components/notifications/NotificationList.vue @@ -1,9 +1,9 @@ <template> <ApolloQuery :query="require('./myNotifications.graphql')" - :pollInterval="1000" + :poll-interval="1000" > - <template v-slot="{ result: { error, data }, isLoading }"> + <template #default="{ result: { error, data }, isLoading }"> <v-list two-line v-if="data && data.myNotifications.notifications.length"> <NotificationItem v-for="notification in data.myNotifications.notifications" @@ -11,17 +11,19 @@ :notification="notification" /> </v-list> - <p v-else>{{ $root.django.gettext('No notifications available yet.') }}</p> + <p v-else> + {{ $root.django.gettext("No notifications available yet.") }} + </p> </template> </ApolloQuery> </template> <script> - import NotificationItem from "./NotificationItem.vue"; +import NotificationItem from "./NotificationItem.vue"; - export default { - components: { - NotificationItem, - }, - } +export default { + components: { + NotificationItem, + }, +}; </script> diff --git a/aleksis/core/assets/css/global.scss b/aleksis/core/assets/css/global.scss index 9c91c57ddf7fb4e56e69daa40c142bc2ed4b589b..a0bcf72b5c28d72916dec80436395b476e7d3d5f 100644 --- a/aleksis/core/assets/css/global.scss +++ b/aleksis/core/assets/css/global.scss @@ -2,7 +2,14 @@ // HEADINGS // ////////////// -p, h1, h2, h3, h4, h5, h6, .card-title { +p, +h1, +h2, +h3, +h4, +h5, +h6, +.card-title { overflow-wrap: break-word; hyphens: auto; } diff --git a/aleksis/core/assets/index.js b/aleksis/core/assets/index.js index 94f4131baf7181ea2a299c518f5fe942b850926d..47ec91d13c6f1f19adcbd174fef114dcc352b9d8 100644 --- a/aleksis/core/assets/index.js +++ b/aleksis/core/assets/index.js @@ -1,4 +1,4 @@ -import '@mdi/font/css/materialdesignicons.css' +import "@mdi/font/css/materialdesignicons.css"; -import "./util" -import "./app" +import "./util"; +import "./app"; diff --git a/aleksis/core/assets/messages.json b/aleksis/core/assets/messages.json index 34c7dab8773a125d28657391f9e75d33d271e2b3..32108b2be305238aceed554534f9232504d43045 100644 --- a/aleksis/core/assets/messages.json +++ b/aleksis/core/assets/messages.json @@ -1,6 +1,6 @@ { "en": { - "notifications": { + "notifications": { "more_information": "More information", "no_notifications": "No notifications available yet." }, @@ -18,4 +18,3 @@ } } } - diff --git a/aleksis/core/assets/util.js b/aleksis/core/assets/util.js index 1b5041b216cdae06868440b14b88f3d69acee914..a16f92bed1fc90e1930b89055278616419cf9c3b 100644 --- a/aleksis/core/assets/util.js +++ b/aleksis/core/assets/util.js @@ -1,153 +1,16 @@ -/* -commented out to see if something breaks -// Define maps between Python's strftime and Luxon's and Materialize's proprietary formats -const pythonToMomentJs = { - "%a": "EEE", - "%A": "EEEE", - "%w": "E", - "%d": "dd", - "%b": "MMM", - "%B": "MMMM", - "%m": "MM", - "%y": "yy", - "%Y": "yyyy", - "%H": "HH", - "%I": "hh", - "%p": "a", - "%M": "mm", - "%s": "ss", - "%f": "SSSSSS", - "%z": "ZZZ", - "%Z": "z", - "%U": "WW", - "%j": "ooo", - "%W": "WW", - "%u": "E", - "%G": "kkkk", - "%V": "WW", -}; - -const pythonToMaterialize = { - "%d": "dd", - "%a": "ddd", - "%A": "dddd", - "%m": "mm", - "%b": "mmm", - "%B": "mmmm", - "%y": "yy", - "%Y": "yyyy", -} - -function buildDateFormat(formatString, map) { - // Convert a Python strftime format string to another format string - for (const key in map) { - formatString = formatString.replace(key, map[key]); - } - return formatString; -} - -function initDatePicker(sel) { - // Initialize datepicker [MAT] - - // Get the date format from Django - const dateInputFormat = get_format('DATE_INPUT_FORMATS')[0] - const inputFormat = buildDateFormat(dateInputFormat, pythonToMomentJs); - const outputFormat = buildDateFormat(dateInputFormat, pythonToMaterialize); - - const el = $(sel).datepicker({ - format: outputFormat, - // Pull translations from Django helpers - i18n: { - months: calendarweek_i18n.month_names, - monthsShort: calendarweek_i18n.month_abbrs, - weekdays: calendarweek_i18n.day_names, - weekdaysShort: calendarweek_i18n.day_abbrs, - weekdaysAbbrev: calendarweek_i18n.day_abbrs.map(([v]) => v), - - // Buttons - today: gettext('Today'), - cancel: gettext('Cancel'), - done: gettext('OK'), - }, - - // Set monday as first day of week - firstDay: get_format('FIRST_DAY_OF_WEEK'), - autoClose: true, - yearRange: [new Date().getFullYear() - 100, new Date().getFullYear() + 100], - }); - - // Set initial values of datepickers - $(sel).each(function () { - const currentValue = $(this).val(); - if (currentValue) { - const currentDate = luxon.DateTime.fromFormat(currentValue, inputFormat).toJSDate(); - $(this).datepicker('setDate', currentDate); - } - }); - - return el; -} - -function initTimePicker(sel) { - // Initialize timepicker [MAT] - return $(sel).timepicker({ - twelveHour: false, - autoClose: true, - i18n: { - cancel: 'Abbrechen', - clear: 'Löschen', - done: 'OK' - }, - }); -} -*/ - - -$(document).ready(function () { - - // If JS is activated, the language form will be auto-submitted - $('.language-field select').change(function () { - $(this).parents(".language-form").submit(); - }); - - // If auto-submit is activated (see above), the language submit must not be visible - $(".language-submit-p").hide(); - - // Initalize print button - $("#print").click(function () { - window.print(); - }); - - // Sync color picker - $(".jscolor").change(function () { - $("#" + $(this).data("preview")).css("color", $(this).val()); - }); - - // Initialise auto-completion for search bar - window.autocomplete = new Autocomplete({minimum_length: 2}); - window.autocomplete.setup(); - - // Initialize text collapsibles [MAT, own work] - $(".text-collapsible").addClass("closed").removeClass("opened"); - - $(".text-collapsible .open-icon").click(function (e) { - var el = $(e.target).parent(); - el.addClass("opened").removeClass("closed"); - }); - $(".text-collapsible .close-icon").click(function (e) { - var el = $(e.target).parent(); - el.addClass("closed").removeClass("opened"); - }); - - // Initialize the service worker - if ('serviceWorker' in navigator) { - console.debug("Start registration of service worker."); - navigator.serviceWorker.register('/serviceworker.js', { - scope: '/' - }).then(function () { - console.debug("Service worker has been registered."); - }).catch(function () { - console.debug("Service worker registration has failed.") - }); - } +window.addEventListener("DOMContentLoaded", function () { + // Initialize the service worker + if ("serviceWorker" in navigator) { + console.debug("Start registration of service worker."); + navigator.serviceWorker + .register("/serviceworker.js", { + scope: "/", + }) + .then(function () { + console.debug("Service worker has been registered."); + }) + .catch(function () { + console.debug("Service worker registration has failed."); + }); + } }); diff --git a/aleksis/core/static/js/copy_button.js b/aleksis/core/static/js/copy_button.js index 554f6230e4f9c8b9bb012875e31da25c4f61c2c6..c7f53e61bf5fa91a13fd24be0b01832755e955d4 100644 --- a/aleksis/core/static/js/copy_button.js +++ b/aleksis/core/static/js/copy_button.js @@ -1,16 +1,16 @@ $(".copy-button").click((e) => { - const target = $(e.currentTarget); - const input = $("#" + target.data("target")); - const copy_icon = target.children(".copy-icon-copy").first(); - const check_icon = target.children(".copy-icon-success").first(); + const target = $(e.currentTarget); + const input = $("#" + target.data("target")); + const copy_icon = target.children(".copy-icon-copy").first(); + const check_icon = target.children(".copy-icon-success").first(); - console.log("Copying to clipboard"); - navigator.clipboard.writeText(input.val()).then(r => { - check_icon.show(); - copy_icon.hide(); - setTimeout(() => { - check_icon.hide(); - copy_icon.show(); - }, 1000); - }); + console.log("Copying to clipboard"); + navigator.clipboard.writeText(input.val()).then((r) => { + check_icon.show(); + copy_icon.hide(); + setTimeout(() => { + check_icon.hide(); + copy_icon.show(); + }, 1000); + }); }); diff --git a/aleksis/core/static/js/edit_dashboard.js b/aleksis/core/static/js/edit_dashboard.js index 0cc90de60305497a682d219b121e77550d273d1d..b6e441191c118b4956e3f54cab919d9caa8fde25 100644 --- a/aleksis/core/static/js/edit_dashboard.js +++ b/aleksis/core/static/js/edit_dashboard.js @@ -1,22 +1,22 @@ function refreshOrder() { - $(".order-input").val(0); - $("#widgets > .col").each(function (index) { - const order = (index + 1) * 10; - let pk = $(this).attr("data-pk"); - let sel = $("#order-form input[value=" + pk + "].pk-input").next(); - sel.val(order); - }) + $(".order-input").val(0); + $("#widgets > .col").each(function (index) { + const order = (index + 1) * 10; + let pk = $(this).attr("data-pk"); + let sel = $("#order-form input[value=" + pk + "].pk-input").next(); + sel.val(order); + }); } $(document).ready(function () { - $('#not-used-widgets').sortable({ - group: 'widgets', - animation: 150, - onEnd: refreshOrder - }); - $('#widgets').sortable({ - group: 'widgets', - animation: 150, - onEnd: refreshOrder - }); + $("#not-used-widgets").sortable({ + group: "widgets", + animation: 150, + onEnd: refreshOrder, + }); + $("#widgets").sortable({ + group: "widgets", + animation: 150, + onEnd: refreshOrder, + }); }); diff --git a/aleksis/core/static/js/helper.js b/aleksis/core/static/js/helper.js index 844496346e451a89814ae90194db57fb67a72434..48dab95651703837a071ee39bcc3f9682d071c9b 100644 --- a/aleksis/core/static/js/helper.js +++ b/aleksis/core/static/js/helper.js @@ -1,30 +1,37 @@ function formatDate(date) { - return date.getDate() + "." + (date.getMonth() + 1) + "." + date.getFullYear(); + return ( + date.getDate() + "." + (date.getMonth() + 1) + "." + date.getFullYear() + ); } - function addZeros(i) { - if (i < 10) { - return "0" + i; - } else { - return "" + i; - } + if (i < 10) { + return "0" + i; + } else { + return "" + i; + } } function formatDateForDjango(date) { - return "" + date.getFullYear() + "/" + addZeros(date.getMonth() + 1) + "/" + addZeros(date.getDate()) + "/"; - + return ( + "" + + date.getFullYear() + + "/" + + addZeros(date.getMonth() + 1) + + "/" + + addZeros(date.getDate()) + + "/" + ); } function getNow() { - return new Date(); + return new Date(); } function getNowFormatted() { - return formatDate(getNow()); + return formatDate(getNow()); } function getJSONScript(elementId) { - return JSON.parse(document.getElementById(elementId).textContent); + return JSON.parse(document.getElementById(elementId).textContent); } - diff --git a/aleksis/core/static/js/include_ajax_live.js b/aleksis/core/static/js/include_ajax_live.js index 3a4794bad9881ebe502ea7786b8c0d2a740e65f0..0d23769c1c68114c638a8daf7217b2bc72d8948e 100644 --- a/aleksis/core/static/js/include_ajax_live.js +++ b/aleksis/core/static/js/include_ajax_live.js @@ -14,7 +14,7 @@ const setAsyncInterval = (cb, interval) => { runAsyncInterval(cb, interval, intervalIndex); return intervalIndex; } else { - throw new Error('Callback must be a function'); + throw new Error("Callback must be a function"); } }; @@ -25,11 +25,11 @@ const clearAsyncInterval = (intervalIndex) => { }; let live_load_interval = setAsyncInterval(async () => { - console.log('fetching new data'); + console.log("fetching new data"); const promise = new Promise((resolve) => { - $('#live_load').load(window.location.pathname + " #live_load"); + $("#live_load").load(window.location.pathname + " #live_load"); resolve(1); }); await promise; - console.log('data fetched successfully'); + console.log("data fetched successfully"); }, 15000); diff --git a/aleksis/core/static/js/main.js b/aleksis/core/static/js/main.js index b735e2bb53d4a3c6a8f5b1edc9a9bb307214e1b4..c8ebd1383f4e80f5ea93d4b59671974a5fdf3dac 100644 --- a/aleksis/core/static/js/main.js +++ b/aleksis/core/static/js/main.js @@ -1,197 +1,209 @@ // Define maps between Python's strftime and Luxon's and Materialize's proprietary formats const pythonToMomentJs = { - "%a": "EEE", - "%A": "EEEE", - "%w": "E", - "%d": "dd", - "%b": "MMM", - "%B": "MMMM", - "%m": "MM", - "%y": "yy", - "%Y": "yyyy", - "%H": "HH", - "%I": "hh", - "%p": "a", - "%M": "mm", - "%s": "ss", - "%f": "SSSSSS", - "%z": "ZZZ", - "%Z": "z", - "%U": "WW", - "%j": "ooo", - "%W": "WW", - "%u": "E", - "%G": "kkkk", - "%V": "WW", + "%a": "EEE", + "%A": "EEEE", + "%w": "E", + "%d": "dd", + "%b": "MMM", + "%B": "MMMM", + "%m": "MM", + "%y": "yy", + "%Y": "yyyy", + "%H": "HH", + "%I": "hh", + "%p": "a", + "%M": "mm", + "%s": "ss", + "%f": "SSSSSS", + "%z": "ZZZ", + "%Z": "z", + "%U": "WW", + "%j": "ooo", + "%W": "WW", + "%u": "E", + "%G": "kkkk", + "%V": "WW", }; const pythonToMaterialize = { - "%d": "dd", - "%a": "ddd", - "%A": "dddd", - "%m": "mm", - "%b": "mmm", - "%B": "mmmm", - "%y": "yy", - "%Y": "yyyy", -} + "%d": "dd", + "%a": "ddd", + "%A": "dddd", + "%m": "mm", + "%b": "mmm", + "%B": "mmmm", + "%y": "yy", + "%Y": "yyyy", +}; function buildDateFormat(formatString, map) { - // Convert a Python strftime format string to another format string - for (const key in map) { - formatString = formatString.replace(key, map[key]); - } - return formatString; + // Convert a Python strftime format string to another format string + for (const key in map) { + formatString = formatString.replace(key, map[key]); + } + return formatString; } function initDatePicker(sel) { - // Initialize datepicker [MAT] - - // Get the date format from Django - const dateInputFormat = get_format('DATE_INPUT_FORMATS')[0] - const inputFormat = buildDateFormat(dateInputFormat, pythonToMomentJs); - const outputFormat = buildDateFormat(dateInputFormat, pythonToMaterialize); - - const el = $(sel).datepicker({ - format: outputFormat, - // Pull translations from Django helpers - i18n: { - months: calendarweek_i18n.month_names, - monthsShort: calendarweek_i18n.month_abbrs, - weekdays: calendarweek_i18n.day_names, - weekdaysShort: calendarweek_i18n.day_abbrs, - weekdaysAbbrev: calendarweek_i18n.day_abbrs.map(([v]) => v), - - // Buttons - today: gettext('Today'), - cancel: gettext('Cancel'), - done: gettext('OK'), - }, - - // Set monday as first day of week - firstDay: get_format('FIRST_DAY_OF_WEEK'), - autoClose: true, - yearRange: [new Date().getFullYear() - 100, new Date().getFullYear() + 100], - }); - - // Set initial values of datepickers - $(sel).each(function () { - const currentValue = $(this).val(); - if (currentValue) { - const currentDate = luxon.DateTime.fromFormat(currentValue, inputFormat).toJSDate(); - $(this).datepicker('setDate', currentDate); - } - }); - - return el; + // Initialize datepicker [MAT] + + // Get the date format from Django + const dateInputFormat = get_format("DATE_INPUT_FORMATS")[0]; + const inputFormat = buildDateFormat(dateInputFormat, pythonToMomentJs); + const outputFormat = buildDateFormat(dateInputFormat, pythonToMaterialize); + + const el = $(sel).datepicker({ + format: outputFormat, + // Pull translations from Django helpers + i18n: { + months: calendarweek_i18n.month_names, + monthsShort: calendarweek_i18n.month_abbrs, + weekdays: calendarweek_i18n.day_names, + weekdaysShort: calendarweek_i18n.day_abbrs, + weekdaysAbbrev: calendarweek_i18n.day_abbrs.map(([v]) => v), + + // Buttons + today: gettext("Today"), + cancel: gettext("Cancel"), + done: gettext("OK"), + }, + + // Set monday as first day of week + firstDay: get_format("FIRST_DAY_OF_WEEK"), + autoClose: true, + yearRange: [new Date().getFullYear() - 100, new Date().getFullYear() + 100], + }); + + // Set initial values of datepickers + $(sel).each(function () { + const currentValue = $(this).val(); + if (currentValue) { + const currentDate = luxon.DateTime.fromFormat( + currentValue, + inputFormat + ).toJSDate(); + $(this).datepicker("setDate", currentDate); + } + }); + + return el; } function initTimePicker(sel) { - // Initialize timepicker [MAT] - return $(sel).timepicker({ - twelveHour: false, - autoClose: true, - i18n: { - cancel: 'Abbrechen', - clear: 'Löschen', - done: 'OK' - }, - }); + // Initialize timepicker [MAT] + return $(sel).timepicker({ + twelveHour: false, + autoClose: true, + i18n: { + cancel: "Abbrechen", + clear: "Löschen", + done: "OK", + }, + }); } $(document).ready(function () { - $("dmc-datetime input").addClass("datepicker"); - $("[data-form-control='date']").addClass("datepicker"); - $("[data-form-control='time']").addClass("timepicker"); - - // Initialize sidenav [MAT] - $(".sidenav").sidenav(); - - // Initialize datepicker [MAT] - initDatePicker(".datepicker"); - - // Initialize timepicker [MAT] - initTimePicker(".timepicker"); - - // Initialize tooltip [MAT] - $('.tooltipped').tooltip(); - - // Initialize select [MAT] - $('select').formSelect(); - - // Initialize dropdown [MAT] - $('.dropdown-trigger').dropdown(); - $('.navbar-dropdown-trigger').dropdown({ - "coverTrigger": false, - "constrainWidth": false, - }); - - // If JS is activated, the language form will be auto-submitted - $('.language-field select').change(function () { - $(this).parents(".language-form").submit(); - }); - - // If auto-submit is activated (see above), the language submit must not be visible - $(".language-submit-p").hide(); - - // Initalize print button - $("#print").click(function () { - window.print(); - }); - - // Initialize Collapsible [MAT] - $('.collapsible').collapsible(); - - // Initialize FABs [MAT] - $('.fixed-action-btn').floatingActionButton(); - - // Initialize Modals [MAT] - $('.modal').modal(); - - // Initialize image boxes [Materialize] - $('.materialboxed').materialbox(); - - // Intialize Tabs [Materialize] - $('.tabs').tabs(); - - // Sync color picker - $(".jscolor").change(function () { - $("#" + $(this).data("preview")).css("color", $(this).val()); - }); - - // Initialise auto-completion for search bar - window.autocomplete = new Autocomplete({minimum_length: 2}); - window.autocomplete.setup(); - - // Initialize text collapsibles [MAT, own work] - $(".text-collapsible").addClass("closed").removeClass("opened"); - - $(".text-collapsible .open-icon").click(function (e) { - var el = $(e.target).parent(); - el.addClass("opened").removeClass("closed"); - }); - $(".text-collapsible .close-icon").click(function (e) { - var el = $(e.target).parent(); - el.addClass("closed").removeClass("opened"); - }); - - // Initialize the service worker - if ('serviceWorker' in navigator) { - console.debug("Start registration of service worker."); - navigator.serviceWorker.register('/serviceworker.js', { - scope: '/' - }).then(function() { - console.debug("Service worker has been registered."); - }).catch(function() { - console.debug("Service worker registration has failed.") - }); - } + $("dmc-datetime input").addClass("datepicker"); + $("[data-form-control='date']").addClass("datepicker"); + $("[data-form-control='time']").addClass("timepicker"); + + // Initialize sidenav [MAT] + $(".sidenav").sidenav(); + + // Initialize datepicker [MAT] + initDatePicker(".datepicker"); + + // Initialize timepicker [MAT] + initTimePicker(".timepicker"); + + // Initialize tooltip [MAT] + $(".tooltipped").tooltip(); + + // Initialize select [MAT] + $("select").formSelect(); + + // Initialize dropdown [MAT] + $(".dropdown-trigger").dropdown(); + $(".navbar-dropdown-trigger").dropdown({ + coverTrigger: false, + constrainWidth: false, + }); + + // If JS is activated, the language form will be auto-submitted + $(".language-field select").change(function () { + $(this).parents(".language-form").submit(); + }); + + // If auto-submit is activated (see above), the language submit must not be visible + $(".language-submit-p").hide(); + + // Initalize print button + $("#print").click(function () { + window.print(); + }); + + // Initialize Collapsible [MAT] + $(".collapsible").collapsible(); + + // Initialize FABs [MAT] + $(".fixed-action-btn").floatingActionButton(); + + // Initialize Modals [MAT] + $(".modal").modal(); + + // Initialize image boxes [Materialize] + $(".materialboxed").materialbox(); + + // Intialize Tabs [Materialize] + $(".tabs").tabs(); + + // Sync color picker + $(".jscolor").change(function () { + $("#" + $(this).data("preview")).css("color", $(this).val()); + }); + + // Initialise auto-completion for search bar + window.autocomplete = new Autocomplete({ minimum_length: 2 }); + window.autocomplete.setup(); + + // Initialize text collapsibles [MAT, own work] + $(".text-collapsible").addClass("closed").removeClass("opened"); + + $(".text-collapsible .open-icon").click(function (e) { + var el = $(e.target).parent(); + el.addClass("opened").removeClass("closed"); + }); + $(".text-collapsible .close-icon").click(function (e) { + var el = $(e.target).parent(); + el.addClass("closed").removeClass("opened"); + }); + + // Initialize the service worker + if ("serviceWorker" in navigator) { + console.debug("Start registration of service worker."); + navigator.serviceWorker + .register("/serviceworker.js", { + scope: "/", + }) + .then(function () { + console.debug("Service worker has been registered."); + }) + .catch(function () { + console.debug("Service worker registration has failed."); + }); + } }); // Show notice if serviceworker broadcasts that the current page comes from its cache const channel = new BroadcastChannel("cache-or-not"); -channel.addEventListener("message", event => { - if ((event.data) && !($("#cache-alert").length)) { - $("main").prepend('<div id="cache-alert" class="alert warning"><p><i class="material-icons iconify left" data-icon="mdi:alert-outline"></i>' + gettext("This page may contain outdated information since there is no internet connection.") + '</p> </div>') - } +channel.addEventListener("message", (event) => { + if (event.data && !$("#cache-alert").length) { + $("main").prepend( + '<div id="cache-alert" class="alert warning"><p><i class="material-icons iconify left" data-icon="mdi:alert-outline"></i>' + + gettext( + "This page may contain outdated information since there is no internet connection." + ) + + "</p> </div>" + ); + } }); diff --git a/aleksis/core/static/js/multi_select.js b/aleksis/core/static/js/multi_select.js index cddf911b5f50be2217075d2c0f34191adab6f72e..105f4c13d6632224a6a88ba2a1d4047255171439 100644 --- a/aleksis/core/static/js/multi_select.js +++ b/aleksis/core/static/js/multi_select.js @@ -1,48 +1,48 @@ $(document).ready(function () { - $(".select--header-box").change(function () { - /* + $(".select--header-box").change(function () { + /* If the top checkbox is checked, all sub checkboxes should be checked, if it gets unchecked, all other ones should get unchecked. */ - if ($(this).is(":checked")) { - $(this).closest("table").find('input[name="selected_objects"]').prop({ - indeterminate: false, - checked: true, - }); - } else { - $(this).closest("table").find('input[name="selected_objects"]').prop({ - indeterminate: false, - checked: false, - }); - } - }); + if ($(this).is(":checked")) { + $(this).closest("table").find('input[name="selected_objects"]').prop({ + indeterminate: false, + checked: true, + }); + } else { + $(this).closest("table").find('input[name="selected_objects"]').prop({ + indeterminate: false, + checked: false, + }); + } + }); - $('input[name="selected_objects"]').change(function () { - /* + $('input[name="selected_objects"]').change(function () { + /* If a table checkbox changes, check the state of the other ones. If all boxes are checked the box in the header should be checked, if all boxes are unchecked the header box should be unchecked. If only some boxes are checked the top one should be inderteminate. */ - let checked = $(this).is(":checked"); - let indeterminate = false; - let table = $(this).closest("table"); - table.find('input[name="selected_objects"]').each(function () { - if ($(this).is(":checked") !== checked) { - /* Set the header box to indeterminate if the boxes are not the same */ - table.find(".select--header-box").prop({ - indeterminate: true, - }) - indeterminate = true; - return false; - } + let checked = $(this).is(":checked"); + let indeterminate = false; + let table = $(this).closest("table"); + table.find('input[name="selected_objects"]').each(function () { + if ($(this).is(":checked") !== checked) { + /* Set the header box to indeterminate if the boxes are not the same */ + table.find(".select--header-box").prop({ + indeterminate: true, }); - if (!(indeterminate)) { - /* All boxes are the same, set the header box to the same value */ - table.find(".select--header-box").prop({ - indeterminate: false, - checked: checked, - }); - } + indeterminate = true; + return false; + } }); + if (!indeterminate) { + /* All boxes are the same, set the header box to the same value */ + table.find(".select--header-box").prop({ + indeterminate: false, + checked: checked, + }); + } + }); }); diff --git a/aleksis/core/static/js/progress.js b/aleksis/core/static/js/progress.js index 8a97577e93d276cd62c69ead4c65b448a7631d49..dc554ec8f37cd6c8e649f5b1d72d503ad93a887f 100644 --- a/aleksis/core/static/js/progress.js +++ b/aleksis/core/static/js/progress.js @@ -1,84 +1,100 @@ const OPTIONS = getJSONScript("progress_options"); const STYLE_CLASSES = { - 10: 'info', - 20: 'info', - 25: 'success', - 30: 'warning', - 40: 'error', + 10: "info", + 20: "info", + 25: "success", + 30: "warning", + 40: "error", }; const ICONS = { - 10: 'mdi:information', - 20: 'mdi:information', - 25: 'mdi:check-circle', - 30: 'mdi:alert-outline', - 40: 'mdi:alert-octagon-outline', + 10: "mdi:information", + 20: "mdi:information", + 25: "mdi:check-circle", + 30: "mdi:alert-outline", + 40: "mdi:alert-octagon-outline", }; function setProgress(progress) { - $("#progress-bar").css("width", progress + "%"); + $("#progress-bar").css("width", progress + "%"); } function renderMessageBox(level, text) { - return '<div class="alert ' + STYLE_CLASSES[level] + '"><p><i class="material-icons iconify left" data-icon="' + ICONS[level] + '"></i>' + text + '</p></div>'; + return ( + '<div class="alert ' + + STYLE_CLASSES[level] + + '"><p><i class="material-icons iconify left" data-icon="' + + ICONS[level] + + '"></i>' + + text + + "</p></div>" + ); } function updateMessages(messages) { - const messagesBox = $("#messages"); + const messagesBox = $("#messages"); - // Clear container - messagesBox.html(""); + // Clear container + messagesBox.html(""); - // Render message boxes - $.each(messages, function (i, message) { - messagesBox.append(renderMessageBox(message[0], message[1])); - }); + // Render message boxes + $.each(messages, function (i, message) { + messagesBox.append(renderMessageBox(message[0], message[1])); + }); } -function customProgress(progressBarElement, progressBarMessageElement, progress) { - setProgress(progress.percent); +function customProgress( + progressBarElement, + progressBarMessageElement, + progress +) { + setProgress(progress.percent); - if (progress.hasOwnProperty("messages")) { - updateMessages(progress.messages); - } + if (progress.hasOwnProperty("messages")) { + updateMessages(progress.messages); + } } - function customSuccess(progressBarElement, progressBarMessageElement, result) { - setProgress(100); - if (result) { - updateMessages(result); - } - $("#result-alert").addClass("success"); - $("#result-icon").attr("data-icon", "mdi:check-circle-outline"); - $("#result-text").text(OPTIONS.success); - $("#result-box").show(); - $("#result-button").show(); - const redirect = "redirect_on_success" in OPTIONS && OPTIONS.redirect_on_success; - if (redirect) { - window.location.replace(OPTIONS.redirect_on_success); - } + setProgress(100); + if (result) { + updateMessages(result); + } + $("#result-alert").addClass("success"); + $("#result-icon").attr("data-icon", "mdi:check-circle-outline"); + $("#result-text").text(OPTIONS.success); + $("#result-box").show(); + $("#result-button").show(); + const redirect = + "redirect_on_success" in OPTIONS && OPTIONS.redirect_on_success; + if (redirect) { + window.location.replace(OPTIONS.redirect_on_success); + } } -function customError(progressBarElement, progressBarMessageElement, excMessage) { - setProgress(100); - if (excMessage) { - updateMessages([40, excMessage]); - } - $("#result-alert").addClass("error"); - $("#result-icon").attr("data-icon", "mdi:alert-octagon-outline"); - $("#result-text").text(OPTIONS.error); - $("#result-box").show(); +function customError( + progressBarElement, + progressBarMessageElement, + excMessage +) { + setProgress(100); + if (excMessage) { + updateMessages([40, excMessage]); + } + $("#result-alert").addClass("error"); + $("#result-icon").attr("data-icon", "mdi:alert-octagon-outline"); + $("#result-text").text(OPTIONS.error); + $("#result-box").show(); } $(document).ready(function () { - $("#progress-bar").removeClass("indeterminate").addClass("determinate"); + $("#progress-bar").removeClass("indeterminate").addClass("determinate"); - var progressUrl = Urls["taskStatus"](OPTIONS.task_id); - CeleryProgressBar.initProgressBar(progressUrl, { - onProgress: customProgress, - onSuccess: customSuccess, - onError: customError, - }); + var progressUrl = Urls["taskStatus"](OPTIONS.task_id); + CeleryProgressBar.initProgressBar(progressUrl, { + onProgress: customProgress, + onSuccess: customSuccess, + onError: customError, + }); }); diff --git a/aleksis/core/static/js/search.js b/aleksis/core/static/js/search.js index fd121dbdfafe20c1c60ef2c793cd1f13b2a7573e..1841829ecca8de19f51aa154732e90d309ec9aa4 100644 --- a/aleksis/core/static/js/search.js +++ b/aleksis/core/static/js/search.js @@ -6,129 +6,129 @@ */ var Autocomplete = function (options) { - this.form_selector = options.form_selector || '.autocomplete'; - this.url = options.url || Urls.searchbarSnippets(); - this.delay = parseInt(options.delay || 300); - this.minimum_length = parseInt(options.minimum_length || 3); - this.form_elem = null; - this.query_box = null; - this.selected_element = null; + this.form_selector = options.form_selector || ".autocomplete"; + this.url = options.url || Urls.searchbarSnippets(); + this.delay = parseInt(options.delay || 300); + this.minimum_length = parseInt(options.minimum_length || 3); + this.form_elem = null; + this.query_box = null; + this.selected_element = null; }; Autocomplete.prototype.setup = function () { - var self = this; - - this.form_elem = $(this.form_selector); - this.query_box = this.form_elem.find('input[name=q]'); - - - $("#search-form").focusout(function (e) { - if (!$(e.relatedTarget).hasClass("search-item")) { - e.preventDefault(); - $("#search-results").remove(); - } - }); - - // Trigger the "keyup" event if input gets focused - - this.query_box.focus(function () { - self.query_box.trigger("input"); - }); - - this.query_box.on("input", () => { - console.log("Input changed, fetching again...") - var query = self.query_box.val(); - - if (query.length < self.minimum_length) { - $("#search-results").remove(); - return true; - } - - self.fetch(query); - return true; - }); - - // Watch the input box. - this.query_box.keydown(function (e) { - - if (e.which === 38) { // Keypress Up - if (!self.selected_element) { - self.setSelectedResult($("#search-collection").children().last()); - return false; - } - - let prev = self.selected_element.prev(); - if (prev.length > 0) { - self.setSelectedResult(prev); - } - return false; - } - - if (e.which === 40) { // Keypress Down - if (!self.selected_element) { - self.setSelectedResult($("#search-collection").children().first()); - return false; - } - - let next = self.selected_element.next(); - if (next.length > 0) { - self.setSelectedResult(next); - } - return false; - } - - if (self.selected_element && e.which === 13) { - e.preventDefault(); - window.location.href = self.selected_element.attr("href"); - } - }); - - // // On selecting a result, remove result box - // this.form_elem.on('click', '#search-results', function (ev) { - // $('#search-results').remove(); - // return true; - // }); - - // Disable browser's own autocomplete - // We do this here so users without JavaScript can keep it enabled - this.query_box.attr('autocomplete', 'off'); + var self = this; + + this.form_elem = $(this.form_selector); + this.query_box = this.form_elem.find("input[name=q]"); + + $("#search-form").focusout(function (e) { + if (!$(e.relatedTarget).hasClass("search-item")) { + e.preventDefault(); + $("#search-results").remove(); + } + }); + + // Trigger the "keyup" event if input gets focused + + this.query_box.focus(function () { + self.query_box.trigger("input"); + }); + + this.query_box.on("input", () => { + console.log("Input changed, fetching again..."); + var query = self.query_box.val(); + + if (query.length < self.minimum_length) { + $("#search-results").remove(); + return true; + } + + self.fetch(query); + return true; + }); + + // Watch the input box. + this.query_box.keydown(function (e) { + if (e.which === 38) { + // Keypress Up + if (!self.selected_element) { + self.setSelectedResult($("#search-collection").children().last()); + return false; + } + + let prev = self.selected_element.prev(); + if (prev.length > 0) { + self.setSelectedResult(prev); + } + return false; + } + + if (e.which === 40) { + // Keypress Down + if (!self.selected_element) { + self.setSelectedResult($("#search-collection").children().first()); + return false; + } + + let next = self.selected_element.next(); + if (next.length > 0) { + self.setSelectedResult(next); + } + return false; + } + + if (self.selected_element && e.which === 13) { + e.preventDefault(); + window.location.href = self.selected_element.attr("href"); + } + }); + + // // On selecting a result, remove result box + // this.form_elem.on('click', '#search-results', function (ev) { + // $('#search-results').remove(); + // return true; + // }); + + // Disable browser's own autocomplete + // We do this here so users without JavaScript can keep it enabled + this.query_box.attr("autocomplete", "off"); }; Autocomplete.prototype.fetch = function (query) { - var self = this; - - $.ajax({ - url: this.url, - data: { - 'q': query - }, - beforeSend: (request, settings) => { - $('#search-results').remove(); - self.setLoader(true); - }, - success: function (data) { - self.setLoader(false); - self.show_results(data); - } - }) + var self = this; + + $.ajax({ + url: this.url, + data: { + q: query, + }, + beforeSend: (request, settings) => { + $("#search-results").remove(); + self.setLoader(true); + }, + success: function (data) { + self.setLoader(false); + self.show_results(data); + }, + }); }; Autocomplete.prototype.show_results = function (data) { - $('#search-results').remove(); - var results_wrapper = $('<div id="search-results">' + data + '</div>'); - this.query_box.after(results_wrapper); - this.selected_element = null; + $("#search-results").remove(); + var results_wrapper = $('<div id="search-results">' + data + "</div>"); + this.query_box.after(results_wrapper); + this.selected_element = null; }; Autocomplete.prototype.setSelectedResult = function (element) { - if (this.selected_element) { - this.selected_element.removeClass("active"); - } - element.addClass("active"); - this.selected_element = element; - console.log("New element: ", element); + if (this.selected_element) { + this.selected_element.removeClass("active"); + } + element.addClass("active"); + this.selected_element = element; + console.log("New element: ", element); }; Autocomplete.prototype.setLoader = function (value) { - $("#search-loader").css("display", (value === true ? "block" : "none")) -} + $("#search-loader").css("display", value === true ? "block" : "none"); +}; diff --git a/aleksis/core/static/js/serviceworker.js b/aleksis/core/static/js/serviceworker.js index 16382ec00c5dadb22c63060a227451377202d363..8fa870824dd46202731afd8dd439b15aad1da4c5 100644 --- a/aleksis/core/static/js/serviceworker.js +++ b/aleksis/core/static/js/serviceworker.js @@ -1,83 +1,89 @@ - // This is the AlekSIS service worker -const CACHE = 'aleksis-cache'; +const CACHE = "aleksis-cache"; -const offlineFallbackPage = 'offline/'; +const offlineFallbackPage = "offline/"; -const channel = new BroadcastChannel('cache-or-not'); +const channel = new BroadcastChannel("cache-or-not"); var comesFromCache = false; self.addEventListener("install", function (event) { - console.log("[AlekSIS PWA] Install Event processing."); + console.log("[AlekSIS PWA] Install Event processing."); - console.log("[AlekSIS PWA] Skipping waiting on install."); - self.skipWaiting(); + console.log("[AlekSIS PWA] Skipping waiting on install."); + self.skipWaiting(); - event.waitUntil( - caches.open(CACHE).then(function (cache) { - console.log("[AlekSIS PWA] Caching pages during install."); - return cache.add(offlineFallbackPage); - }) - ); + event.waitUntil( + caches.open(CACHE).then(function (cache) { + console.log("[AlekSIS PWA] Caching pages during install."); + return cache.add(offlineFallbackPage); + }) + ); }); // Allow sw to control of current page self.addEventListener("activate", function (event) { - console.log("[AlekSIS PWA] Claiming clients for current page."); - event.waitUntil(self.clients.claim()); + console.log("[AlekSIS PWA] Claiming clients for current page."); + event.waitUntil(self.clients.claim()); }); // If any fetch fails, it will look for the request in the cache and serve it from there first self.addEventListener("fetch", function (event) { - if (event.request.method !== "GET") return; - networkFirstFetch(event); - if (comesFromCache) channel.postMessage(true); + if (event.request.method !== "GET") return; + networkFirstFetch(event); + if (comesFromCache) channel.postMessage(true); }); function networkFirstFetch(event) { - event.respondWith( - fetch(event.request) - .then(function (response) { - // If request was successful, add or update it in the cache - console.log("[AlekSIS PWA] Network request successful."); - event.waitUntil(updateCache(event.request, response.clone())); - comesFromCache = false; - return response; - }) - .catch(function (error) { - console.log("[AlekSIS PWA] Network request failed. Serving content from cache: " + error); - return fromCache(event); - }) - ); + event.respondWith( + fetch(event.request) + .then(function (response) { + // If request was successful, add or update it in the cache + console.log("[AlekSIS PWA] Network request successful."); + event.waitUntil(updateCache(event.request, response.clone())); + comesFromCache = false; + return response; + }) + .catch(function (error) { + console.log( + "[AlekSIS PWA] Network request failed. Serving content from cache: " + + error + ); + return fromCache(event); + }) + ); } function fromCache(event) { - // Check to see if you have it in the cache - // Return response - // If not in the cache, then return offline fallback page - return caches.open(CACHE).then(function (cache) { - return cache.match(event.request) - .then(function (matching) { - if (!matching || matching.status === 404) { - console.log("[AlekSIS PWA] Cache request failed. Serving offline fallback page."); - comesFromCache = false; - // Use the precached offline page as fallback - return caches.match(offlineFallbackPage); - } - comesFromCache = true; - return matching; - }); + // Check to see if you have it in the cache + // Return response + // If not in the cache, then return offline fallback page + return caches.open(CACHE).then(function (cache) { + return cache.match(event.request).then(function (matching) { + if (!matching || matching.status === 404) { + console.log( + "[AlekSIS PWA] Cache request failed. Serving offline fallback page." + ); + comesFromCache = false; + // Use the precached offline page as fallback + return caches.match(offlineFallbackPage); + } + comesFromCache = true; + return matching; }); + }); } function updateCache(request, response) { - if (response.headers.get('cache-control') && response.headers.get('cache-control').includes('no-cache')) { - return Promise.resolve(); - } else { - return caches.open(CACHE).then(function (cache) { - return cache.put(request, response); - }); - } + if ( + response.headers.get("cache-control") && + response.headers.get("cache-control").includes("no-cache") + ) { + return Promise.resolve(); + } else { + return caches.open(CACHE).then(function (cache) { + return cache.put(request, response); + }); + } } diff --git a/aleksis/core/static/print-simple.css b/aleksis/core/static/print-simple.css index f0e6536b4d835b67ab0d519de13c561953be4ea5..dfde8908dbe44e0bfa21039364455ed4b9154906 100644 --- a/aleksis/core/static/print-simple.css +++ b/aleksis/core/static/print-simple.css @@ -1,21 +1,25 @@ @page { - padding: 0; - margin: 0; + padding: 0; + margin: 0; } -table.small-print, td.small-print, th.small-print { - font-size: 10pt; +table.small-print, +td.small-print, +th.small-print { + font-size: 10pt; } tr { - border-bottom: 1px solid rgba(0, 0, 0, 0.3); + border-bottom: 1px solid rgba(0, 0, 0, 0.3); } -td, th { - padding: 1px; +td, +th { + padding: 1px; } -td.rotate, th.rotate { - text-align: center; - transform: rotate(-90deg); +td.rotate, +th.rotate { + text-align: center; + transform: rotate(-90deg); } diff --git a/aleksis/core/static/print.css b/aleksis/core/static/print.css index dad3abb5967e84b014769240ce000d33ced9f014..1c3e9d486a27e913671a453219c60b70b8778462 100644 --- a/aleksis/core/static/print.css +++ b/aleksis/core/static/print.css @@ -1,133 +1,139 @@ .sheet.infinite { - height: auto !important; + height: auto !important; } @page { - size: A4; - padding: 30mm; - margin: 0; + size: A4; + padding: 30mm; + margin: 0; } header { - display: block; - width: 190mm; + display: block; + width: 190mm; } - #print-header { - display: block !important; - border-bottom: 1px solid; - margin-bottom: 0; - height: 22mm; - background: white; + display: block !important; + border-bottom: 1px solid; + margin-bottom: 0; + height: 22mm; + background: white; } -header, main, footer { - margin: 0; +header, +main, +footer { + margin: 0; } #print-header .col.right-align { - padding: 15px; + padding: 15px; } .sheet { - padding: 10mm; + padding: 10mm; } - -.header-space, .footer-space { - height: 0; +.header-space, +.footer-space { + height: 0; } -.print-layout-table, .print-layout-td { - width: 190mm; - max-width: 190mm; - min-width: 190mm; +.print-layout-table, +.print-layout-td { + width: 190mm; + max-width: 190mm; + min-width: 190mm; } .print-layout-td { - padding: 0; + padding: 0; } .print-layout-table .no-border { - border: 0; + border: 0; } - footer { - margin-top: 5mm; - text-align: center; - width: 190mm; - + margin-top: 5mm; + text-align: center; + width: 190mm; } -header .row, header .col { - padding: 0 !important; - margin: 0 !important; +header .row, +header .col { + padding: 0 !important; + margin: 0 !important; } #print-logo { - height: 22mm; - width: auto; - margin-block: 0; - padding: 2mm 2mm 2mm 0; + height: 22mm; + width: auto; + margin-block: 0; + padding: 2mm 2mm 2mm 0; } .page-break { - display: block; - text-align: center; - margin: auto; - margin-top: 20px; - margin-bottom: 20px; - width: 200px; - border-top: 1px dashed; - color: darkgrey; - page-break-after: always; + display: block; + text-align: center; + margin: auto; + margin-top: 20px; + margin-bottom: 20px; + width: 200px; + border-top: 1px dashed; + color: darkgrey; + page-break-after: always; } @media print { - .header-space { - height: 35mm; - } + .header-space { + height: 35mm; + } - .footer-space { - height: 20mm - } + .footer-space { + height: 20mm; + } - header, footer { - height: 22mm; - } + header, + footer { + height: 22mm; + } - header { - position: fixed; - top: 10mm; - } + header { + position: fixed; + top: 10mm; + } - footer { - position: fixed; - bottom: 0; - } + footer { + position: fixed; + bottom: 0; + } - .page-break { - border: white; - } + .page-break { + border: white; + } } /* Some stuff for tables */ -table.small-print, td.small-print, th.small-print { - font-size: 10pt; +table.small-print, +td.small-print, +th.small-print { + font-size: 10pt; } tr { - border-bottom: 1px solid rgba(0, 0, 0, 0.3); + border-bottom: 1px solid rgba(0, 0, 0, 0.3); } -td, th { - padding: 1px; +td, +th { + padding: 1px; } -td.rotate, th.rotate { - text-align: center; - transform: rotate(-90deg); +td.rotate, +th.rotate { + text-align: center; + transform: rotate(-90deg); } diff --git a/aleksis/core/static/print_landscape.css b/aleksis/core/static/print_landscape.css index a348ddff6268f56a1f4fa82eac240d6c9823e14c..746968664ee7ac8e04643e97e6964cfc57796eca 100644 --- a/aleksis/core/static/print_landscape.css +++ b/aleksis/core/static/print_landscape.css @@ -1,19 +1,18 @@ @page { - size: A4 landscape; + size: A4 landscape; } header { - width: 277mm; + width: 277mm; } - -.print-layout-table, .print-layout-td { - width: 277mm; - max-width: 277mm; - min-width: 277mm; +.print-layout-table, +.print-layout-td { + width: 277mm; + max-width: 277mm; + min-width: 277mm; } - footer { - width: 277mm; + width: 277mm; } diff --git a/aleksis/core/static/public/style.scss b/aleksis/core/static/public/style.scss index 07f1881216448b3c82fb605af72b214004bf2f03..998da7726f3758310068225b7d929be51975eb14 100644 --- a/aleksis/core/static/public/style.scss +++ b/aleksis/core/static/public/style.scss @@ -4,7 +4,8 @@ background-color: $primary-color !important; } -.primary-color-text, .primary-color-text a { +.primary-color-text, +.primary-color-text a { color: $primary-color !important; } @@ -12,7 +13,8 @@ background-color: $secondary-color !important; } -.secondary-color-text, .secondary-color-text a { +.secondary-color-text, +.secondary-color-text a { color: $secondary-color !important; } @@ -29,7 +31,7 @@ rect#background { } .success { - @extend .light-green, .lighten-3 + @extend .light-green, .lighten-3; } .success-text { @@ -64,16 +66,22 @@ body { flex-direction: column; } -header, main, footer { +header, +main, +footer { margin-left: 300px; } -.without-menu header, .without-menu main, .without-menu footer { +.without-menu header, +.without-menu main, +.without-menu footer { margin-left: 0; } @media only screen and (max-width: 992px) { - header, main, footer { + header, + main, + footer { margin-left: 0; } } @@ -81,7 +89,10 @@ header, main, footer { .materialize-circle { @extend .circle; } -.collection .collection-item.avatar > .materialize-circle > .materialize-circle { +.collection + .collection-item.avatar + > .materialize-circle + > .materialize-circle { left: 0; } @@ -98,7 +109,6 @@ header, main, footer { width: auto; } - /********/ /* MAIN */ /********/ @@ -134,11 +144,18 @@ ul.sidenav li.logo > a:hover { background: none !important; } -.sidenav .collapsible-body > ul:not(.collapsible) > li.active a > i, .sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active a > i { +.sidenav .collapsible-body > ul:not(.collapsible) > li.active a > i, +.sidenav.sidenav-fixed + .collapsible-body + > ul:not(.collapsible) + > li.active + a + > i { color: #fff; } -.sidenav .collapsible-body > ul:not(.collapsible) > li.active, .sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active { +.sidenav .collapsible-body > ul:not(.collapsible) > li.active, +.sidenav.sidenav-fixed .collapsible-body > ul:not(.collapsible) > li.active { background-color: lighten($primary-color, 5%); } @@ -161,8 +178,8 @@ ul.sidenav li.logo > a:hover { border-top: 1px solid rgba(0, 0, 0, 0.14); border-bottom: 1px solid rgba(0, 0, 0, 0.14); - -webkit-transition: margin .25s ease; - transition: margin .25s ease; + -webkit-transition: margin 0.25s ease; + transition: margin 0.25s ease; } .sidenav li.search .search-wrapper input#search { @@ -215,7 +232,6 @@ div#search-results { right: 10px; } - // Footer .footer-icon { @@ -223,7 +239,6 @@ div#search-results { vertical-align: middle; } - @media only screen and (min-width: 1384px) { .footer-row-large { display: flex; @@ -280,10 +295,17 @@ h1 { h2 { font-weight: 300; - font-size: 3.0rem; + font-size: 3rem; } -p, h1, h2, h3, h4, h5, h6, .card-title { +p, +h1, +h2, +h3, +h4, +h5, +h6, +.card-title { overflow-wrap: break-word; hyphens: auto; } @@ -294,7 +316,6 @@ ul.collection .collection-item .title { font-weight: bold; } - // Forms form .row { @@ -317,7 +338,7 @@ label.chips-checkbox { height: 32px; font-size: 13px; font-weight: 500; - color: rgba(0, 0, 0, .6); + color: rgba(0, 0, 0, 0.6); line-height: 32px; padding: 0 12px; border-radius: 16px; @@ -403,24 +424,29 @@ span.badge .material-icons { font-size: 2rem; } -.btn.primary, .btn-large.primary, .btn-small.primary { +.btn.primary, +.btn-large.primary, +.btn-small.primary { background-color: rgba(0, 0, 0, 0.05) !important; color: black !important; } -.btn.primary:hover, .btn-large.primary:hover, .btn-small.primary { +.btn.primary:hover, +.btn-large.primary:hover, +.btn-small.primary { background-color: $primary-color !important; color: whitesmoke !important; } - /* Table*/ .table-container { overflow-x: auto; } -table.striped > tbody > tr:nth-child(odd), table tr.striped, table tbody.striped tr { +table.striped > tbody > tr:nth-child(odd), +table tr.striped, +table tbody.striped tr { background-color: rgba(208, 208, 208, 0.5); } @@ -461,7 +487,9 @@ th.orderable.desc { font-size: 15px; } - header, main, footer { + header, + main, + footer { margin-left: 0; } @@ -488,11 +516,14 @@ th.orderable.desc { padding: 15px; } - main, header { + main, + header { padding: 0; } - footer, footer .footer-copyright, footer .container { + footer, + footer .footer-copyright, + footer .container { background-color: white !important; color: black !important; } @@ -501,7 +532,8 @@ th.orderable.desc { display: none; } - .footer-copyright, .footer-copyright .container { + .footer-copyright, + .footer-copyright .container { padding: 0 !important; margin: 0 !important; } @@ -513,7 +545,8 @@ th.orderable.desc { // Alerts -.alert ul, .alert p { +.alert ul, +.alert p { margin: 0; } @@ -637,7 +670,6 @@ main figure.alert { margin-bottom: 5px; } - /* Dashboard */ .card-action-badge { @@ -719,7 +751,6 @@ main figure.alert { } } - .dashboard-cards .card { display: inline-block; overflow: visible; @@ -755,14 +786,15 @@ main figure.alert { } /* Tabs with icons */ -.tabs-icons, .tabs-icons .tab, .tabs-icons a { +.tabs-icons, +.tabs-icons .tab, +.tabs-icons a { height: 72px; } .tabs-icons .tab { display: inline-flex; flex-direction: column; - } .tabs-icons .tab a { @@ -798,7 +830,8 @@ $person-logo-size: 20vh; } } -.clip-circle.no-image, .clip-circle.no-image > i.material-icons { +.clip-circle.no-image, +.clip-circle.no-image > i.material-icons { font-size: calc(#{$person-logo-size} * 0.5); color: #6f6f6f; background: #f2f2f2; @@ -817,8 +850,8 @@ $person-logo-size: 20vh; justify-content: space-between; padding: 0 1rem; > a { - position: static!important; - transform: none!important; + position: static !important; + transform: none !important; } & .nav-spacer { width: 60px; @@ -840,16 +873,17 @@ $person-logo-size: 20vh; .navbar-dropdown-trigger .clip-circle { margin: auto; - width: $navbar-height*0.75; - height: $navbar-height*0.75; + width: $navbar-height * 0.75; + height: $navbar-height * 0.75; cursor: pointer; - &.no-image, &.no-image > i.material-icons { + &.no-image, + &.no-image > i.material-icons { font-size: calc(#{$navbar-height} * 0.75 * 0.5); color: #6f6f6f; background: #f2f2f2; - line-height: $navbar-height*0.75; - width: $navbar-height*0.75; + line-height: $navbar-height * 0.75; + width: $navbar-height * 0.75; cursor: pointer; } } @@ -878,8 +912,8 @@ a.new-notification { background-color: lighten($primary-color, 30%); z-index: -1; box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14) inset, - 0 1px 10px 0 rgba(0, 0, 0, 0.12) inset, - 0 2px 4px -1px rgba(0, 0, 0, 0.3) inset; + 0 1px 10px 0 rgba(0, 0, 0, 0.12) inset, + 0 2px 4px -1px rgba(0, 0, 0, 0.3) inset; } .person-buttons { @@ -954,7 +988,6 @@ a.new-notification { height: 20vh; } - .application-circle img { @extend .application-circle; object-fit: cover; @@ -964,7 +997,8 @@ svg.iconify { @extend i; } -.btn .iconify.material-icons, .btn-flat .iconify.material-icons{ +.btn .iconify.material-icons, +.btn-flat .iconify.material-icons { height: $button-height; } @@ -992,7 +1026,8 @@ p.ical-description { font-weight: 300; } -.table-circle, .table-circle .materialize-circle { +.table-circle, +.table-circle .materialize-circle { height: 4em; width: 4em; } diff --git a/aleksis/core/static/public/theme.scss b/aleksis/core/static/public/theme.scss index 1b38e9bda22c7b63601a4a227d58981e2e3a8d45..3850e4c17da80967b7729bd5feebf937ee3cee5e 100644 --- a/aleksis/core/static/public/theme.scss +++ b/aleksis/core/static/public/theme.scss @@ -29,28 +29,30 @@ // 23. Collections // 24. Progress Bar - - // 1. Colors // ========================================================================== -$primary-color: adjust-color(get-colour(get-preference(theme, primary)), $alpha: 1); +$primary-color: adjust-color( + get-colour(get-preference(theme, primary)), + $alpha: 1 +); $primary-color-light: lighten($primary-color, 15%) !default; $primary-color-dark: darken($primary-color, 15%) !default; -$secondary-color: adjust-color(get-colour(get-preference(theme, secondary)), $alpha: 1); +$secondary-color: adjust-color( + get-colour(get-preference(theme, secondary)), + $alpha: 1 +); $success-color: color("green", "base") !default; $error-color: color("red", "base") !default; $link-color: color("light-blue", "darken-1") !default; - // 2. Badges // ========================================================================== $badge-bg-color: $secondary-color !default; $badge-height: 22px !default; - // 3. Buttons // ========================================================================== @@ -64,12 +66,15 @@ $button-padding: 0 16px !default; $button-radius: 2px !default; // Disabled styles -$button-disabled-background: #DFDFDF !default; -$button-disabled-color: #9F9F9F !default; +$button-disabled-background: #dfdfdf !default; +$button-disabled-color: #9f9f9f !default; // Raised buttons $button-raised-background: $secondary-color !default; -$button-raised-background-hover: lighten($button-raised-background, 5%) !default; +$button-raised-background-hover: lighten( + $button-raised-background, + 5% +) !default; $button-raised-color: #fff !default; // Large buttons @@ -81,8 +86,8 @@ $button-floating-large-size: 56px !default; // Small buttons $button-small-font-size: 13px !default; $button-small-icon-font-size: 1.2rem !default; -$button-small-height: $button-height * .9 !default; -$button-floating-small-size: $button-height * .9 !default; +$button-small-height: $button-height * 0.9 !default; +$button-floating-small-size: $button-height * 0.9 !default; // Flat buttons $button-flat-color: #343434 !default; @@ -95,7 +100,6 @@ $button-floating-color: #fff !default; $button-floating-size: 40px !default; $button-floating-radius: 50% !default; - // 4. Cards // ========================================================================== @@ -104,7 +108,6 @@ $card-bg-color: #fff !default; $card-link-color: $primary-color !default; $card-link-color-light: lighten($card-link-color, 20%) !default; - // 5. Carousel // ========================================================================== @@ -112,7 +115,6 @@ $carousel-height: 400px !default; $carousel-item-height: $carousel-height / 2 !default; $carousel-item-width: $carousel-item-height !default; - // 6. Collapsible // ========================================================================== @@ -121,7 +123,6 @@ $collapsible-line-height: $collapsible-height !default; $collapsible-header-color: #fff !default; $collapsible-border-color: #ddd !default; - // 7. Chips // ========================================================================== @@ -130,26 +131,30 @@ $chip-border-color: #9e9e9e !default; $chip-selected-color: $primary-color !default; $chip-margin: 5px !default; - // 8. Date + Time Picker // ========================================================================== $datepicker-display-font-size: 2.8rem; $datepicker-calendar-header-color: #999; -$datepicker-weekday-color: rgba(0, 0, 0, .87) !default; +$datepicker-weekday-color: rgba(0, 0, 0, 0.87) !default; $datepicker-weekday-bg: darken($secondary-color, 7%) !default; $datepicker-date-bg: $secondary-color !default; -$datepicker-year: rgba(255, 255, 255, .7) !default; -$datepicker-focus: rgba(0,0,0, .05) !default; +$datepicker-year: rgba(255, 255, 255, 0.7) !default; +$datepicker-focus: rgba(0, 0, 0, 0.05) !default; $datepicker-selected: $secondary-color !default; -$datepicker-selected-outfocus: desaturate(lighten($secondary-color, 35%), 15%) !default; -$datepicker-day-focus: transparentize(desaturate($secondary-color, 5%), .75) !default; -$datepicker-disabled-day-color: rgba(0, 0, 0, .3) !default; - -$timepicker-clock-color: rgba(0, 0, 0, .87) !default; +$datepicker-selected-outfocus: desaturate( + lighten($secondary-color, 35%), + 15% +) !default; +$datepicker-day-focus: transparentize( + desaturate($secondary-color, 5%), + 0.75 +) !default; +$datepicker-disabled-day-color: rgba(0, 0, 0, 0.3) !default; + +$timepicker-clock-color: rgba(0, 0, 0, 0.87) !default; $timepicker-clock-plate-bg: #eee !default; - // 9. Dropdown // ========================================================================== @@ -158,7 +163,6 @@ $dropdown-hover-bg-color: #eee !default; $dropdown-color: $secondary-color !default; $dropdown-item-height: 50px !default; - // 10. Forms // ========================================================================== @@ -174,8 +178,8 @@ $input-font-size: 16px !default; $input-margin-bottom: 8px; $input-margin: 0 0 $input-margin-bottom 0 !default; $input-padding: 0 !default; -$label-font-size: .8rem !default; -$input-disabled-color: rgba(0,0,0, .42) !default; +$label-font-size: 0.8rem !default; +$input-disabled-color: rgba(0, 0, 0, 0.42) !default; $input-disabled-solid-color: #949494 !default; $input-disabled-border: 1px dotted $input-disabled-color !default; $input-invalid-border: 1px solid $input-error-color !default; @@ -194,23 +198,25 @@ $track-height: 3px !default; // Select $select-border: 1px solid #f2f2f2 !default; -$select-background: rgba(255, 255, 255, 0.90) !default; +$select-background: rgba(255, 255, 255, 0.9) !default; $select-focus: 1px solid lighten($secondary-color, 47%) !default; -$select-option-hover: rgba(0,0,0,.08) !default; -$select-option-focus: rgba(0,0,0,.08) !default; -$select-option-selected: rgba(0,0,0,.03) !default; +$select-option-hover: rgba(0, 0, 0, 0.08) !default; +$select-option-focus: rgba(0, 0, 0, 0.08) !default; +$select-option-selected: rgba(0, 0, 0, 0.03) !default; $select-padding: 5px !default; $select-radius: 2px !default; -$select-disabled-color: rgba(0,0,0,.3) !default; +$select-disabled-color: rgba(0, 0, 0, 0.3) !default; // Switches $switch-bg-color: $secondary-color !default; -$switch-checked-lever-bg: desaturate(lighten($switch-bg-color, 25%), 25%) !default; -$switch-unchecked-bg: #F1F1F1 !default; -$switch-unchecked-lever-bg: rgba(0,0,0,.38) !default; +$switch-checked-lever-bg: desaturate( + lighten($switch-bg-color, 25%), + 25% +) !default; +$switch-unchecked-bg: #f1f1f1 !default; +$switch-unchecked-lever-bg: rgba(0, 0, 0, 0.38) !default; $switch-radius: 15px !default; - // 11. Global // ========================================================================== @@ -229,15 +235,13 @@ $small-and-down: "only screen and (max-width : #{$small-screen})" !default; $medium-and-down: "only screen and (max-width : #{$medium-screen})" !default; $medium-only: "only screen and (min-width : #{$small-screen-up}) and (max-width : #{$medium-screen})" !default; - // 12. Grid // ========================================================================== $num-cols: 12 !default; $gutter-width: 1.5rem !default; $element-top-margin: $gutter-width/3 !default; -$element-bottom-margin: ($gutter-width*2)/3 !default; - +$element-bottom-margin: ($gutter-width * 2)/3 !default; // 13. Navigation Bar // ========================================================================== @@ -255,27 +259,24 @@ $navbar-brand-font-size: 2.1rem !default; $sidenav-width: 300px !default; $sidenav-font-size: 14px !default; -$sidenav-font-color: rgba(0,0,0,.87) !default; +$sidenav-font-color: rgba(0, 0, 0, 0.87) !default; $sidenav-bg-color: #fff !default; $sidenav-padding: 16px !default; $sidenav-item-height: 48px !default; $sidenav-line-height: $sidenav-item-height !default; - // 15. Photo Slider // ========================================================================== -$slider-bg-color: color('grey', 'base') !default; -$slider-bg-color-light: color('grey', 'lighten-2') !default; -$slider-indicator-color: color('green', 'base') !default; - +$slider-bg-color: color("grey", "base") !default; +$slider-bg-color-light: color("grey", "lighten-2") !default; +$slider-indicator-color: color("green", "base") !default; // 16. Spinners | Loaders // ========================================================================== $spinner-default-color: $secondary-color !default; - // 17. Tabs // ========================================================================== @@ -283,14 +284,12 @@ $tabs-underline-color: $primary-color-light !default; $tabs-text-color: $primary-color !default; $tabs-bg-color: #fff !default; - // 18. Tables // ========================================================================== -$table-border-color: rgba(0,0,0,.12) !default; +$table-border-color: rgba(0, 0, 0, 0.12) !default; $table-striped-color: rgba(242, 242, 242, 0.5) !default; - // 19. Toasts // ========================================================================== @@ -299,11 +298,11 @@ $toast-color: #323232 !default; $toast-text-color: #fff !default; $toast-action-color: #eeff41; - // 20. Typography // ========================================================================== -$font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif !default; +$font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, + Ubuntu, Cantarell, "Helvetica Neue", sans-serif !default; $off-black: rgba(0, 0, 0, 0.87) !default; // Header Styles $h1-fontsize: 4.2rem !default; @@ -313,24 +312,21 @@ $h4-fontsize: 2.28rem !default; $h5-fontsize: 1.64rem !default; $h6-fontsize: 1.15rem !default; - // 21. Footer // ========================================================================== $footer-font-color: #fff !default; $footer-bg-color: $primary-color !default; -$footer-copyright-font-color: rgba(255,255,255,.8) !default; -$footer-copyright-bg-color: rgba(51,51,51,.08) !default; - +$footer-copyright-font-color: rgba(255, 255, 255, 0.8) !default; +$footer-copyright-bg-color: rgba(51, 51, 51, 0.08) !default; // 22. Flow Text // ========================================================================== -$range : $large-screen - $small-screen !default; +$range: $large-screen - $small-screen !default; $intervals: 20 !default; $interval-size: $range / $intervals !default; - // 23. Collections // ========================================================================== @@ -342,7 +338,6 @@ $collection-hover-bg-color: #ddd !default; $collection-link-color: $secondary-color !default; $collection-line-height: 1.5rem !default; - // 24. Progress Bar // ========================================================================== diff --git a/aleksis/core/templates/core/vue_base.html b/aleksis/core/templates/core/vue_base.html index 3d8f6a7bf10553c6aed4d2dde2fbe1740b7651fc..07b06277856d27283a8612882c0d287f40590f1f 100644 --- a/aleksis/core/templates/core/vue_base.html +++ b/aleksis/core/templates/core/vue_base.html @@ -19,17 +19,12 @@ </title> {# CSS #} - {# FIXME ↓ #} - {# {% include_css "material-design-icons" %}#} {% include_css "Roboto100" %} {% include_css "Roboto300" %} {% include_css "Roboto400" %} {% include_css "Roboto500" %} {% include_css "Roboto700" %} {% include_css "Roboto900" %} - {# <link rel="stylesheet" href="{% sass_src 'public/style.scss' %}">#} - - <!-- FIXME: Find a way to use SCSS!!! --> {# Add JS URL resolver #} <script src="{% url "js_reverse" %}" type="text/javascript"></script> @@ -61,9 +56,6 @@ <script type="text/javascript" src="{% url 'config.js' %}"></script> {% include_js "iconify" %} - {# Include jQuery early to provide $(document).ready #} - {% include_js "jQuery" %} - {% block extra_head %}{% endblock %} </head> <body {% if no_menu %}class="without-menu"{% endif %}> diff --git a/aleksis/core/templates/templated_email/email.css b/aleksis/core/templates/templated_email/email.css index 8cd112624c0c0b78f663027841895f4e07ce608b..465da3dd073bf681eb3146a077ea17d46f643fca 100644 --- a/aleksis/core/templates/templated_email/email.css +++ b/aleksis/core/templates/templated_email/email.css @@ -1,41 +1,45 @@ body { - line-height: 1.5; - font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; - font-weight: normal; - color: rgba(0, 0, 0, 0.87); - display: flex; - justify-content: center; - align-items: center; + line-height: 1.5; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, + Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif; + font-weight: normal; + color: rgba(0, 0, 0, 0.87); + display: flex; + justify-content: center; + align-items: center; } -table, tr { - width: 100%; +table, +tr { + width: 100%; } .main { - max-width: 700px; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); - -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); - -webkit-transition: -webkit-box-shadow .25s; - transition: -webkit-box-shadow .25s; - transition: box-shadow .25s; - transition: box-shadow .25s, -webkit-box-shadow .25s; - border-radius: 2px; - background-color: #fff; - margin: 30px; - padding: 20px; + max-width: 700px; + box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), + 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); + -webkit-box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), + 0 3px 1px -2px rgba(0, 0, 0, 0.12), 0 1px 5px 0 rgba(0, 0, 0, 0.2); + -webkit-transition: -webkit-box-shadow 0.25s; + transition: -webkit-box-shadow 0.25s; + transition: box-shadow 0.25s; + transition: box-shadow 0.25s, -webkit-box-shadow 0.25s; + border-radius: 2px; + background-color: #fff; + margin: 30px; + padding: 20px; } .first th { - border-bottom: 1px solid; + border-bottom: 1px solid; } - -td, th { - padding-left: 5px; - padding-right: 5px; +td, +th { + padding-left: 5px; + padding-right: 5px; } .align-center { - text-align: center; + text-align: center; } diff --git a/aleksis/core/webpack.config.js b/aleksis/core/webpack.config.js index f33cc60252c0c11bfeacb4c304db7c396a9530ad..8f327cbe55a6dba6b7ae5f104a89f4da46ddf711 100644 --- a/aleksis/core/webpack.config.js +++ b/aleksis/core/webpack.config.js @@ -1,50 +1,58 @@ -const fs = require('fs'); -const path = require('path'); -const webpack = require('webpack'); -const BundleTracker = require('webpack-bundle-tracker'); -const { VueLoaderPlugin } = require('vue-loader'); +const fs = require("fs"); +const path = require("path"); +const webpack = require("webpack"); +const BundleTracker = require("webpack-bundle-tracker"); +const { VueLoaderPlugin } = require("vue-loader"); +const ESLintPlugin = require("eslint-webpack-plugin"); +const StyleLintPlugin = require("stylelint-webpack-plugin"); module.exports = { context: __dirname, - entry: JSON.parse(fs.readFileSync('./webpack-entrypoints.json')), + entry: JSON.parse(fs.readFileSync("./webpack-entrypoints.json")), output: { - path: path.resolve('./webpack_bundles/'), + path: path.resolve("./webpack_bundles/"), filename: "[name]-[hash].js", chunkFilename: "[id]-[chunkhash].js", }, plugins: [ - new BundleTracker({filename: './webpack-stats.json'}), + new BundleTracker({ filename: "./webpack-stats.json" }), new VueLoaderPlugin(), + new ESLintPlugin({ + extensions: ["js", "vue"], + }), + new StyleLintPlugin({ + files: ["assets/**/*.{vue,htm,html,css,sss,less,scss,sass}"], + }), ], module: { rules: [ { test: /\.vue$/, use: { - loader: 'vue-loader', + loader: "vue-loader", options: { transpileOptions: { transforms: { - dangerousTaggedTemplateString: true - } - } - } + dangerousTaggedTemplateString: true, + }, + }, + }, }, }, { test: /\.(css)$/, - use: ['vue-style-loader', 'css-loader'], + use: ["vue-style-loader", "css-loader"], }, { test: /\.scss$/, use: [ - 'vue-style-loader', - 'css-loader', + "vue-style-loader", + "css-loader", { - loader: 'sass-loader', + loader: "sass-loader", options: { sassOptions: { - indentedSyntax: false + indentedSyntax: false, }, }, }, @@ -53,7 +61,7 @@ module.exports = { { test: /\.(graphql|gql)$/, exclude: /node_modules/, - loader: 'graphql-tag/loader', + loader: "graphql-tag/loader", }, ], }, @@ -75,15 +83,15 @@ module.exports = { // npm package names are URL-safe, but some servers don't like @ symbols return `npm.${packageName.replace("@", "")}`; - } - } - } - } + }, + }, + }, + }, }, resolve: { - modules: [path.resolve('./node_modules')], + modules: [path.resolve("./node_modules")], alias: { - 'vue$': 'vue/dist/vue.esm.js' - } + vue$: "vue/dist/vue.esm.js", + }, }, -} +};