diff --git a/controllers/FilesApiController.php b/controllers/FilesApiController.php index c9aec10b..7577b58c 100644 --- a/controllers/FilesApiController.php +++ b/controllers/FilesApiController.php @@ -72,6 +72,7 @@ class FilesApiController extends BaseApiController if (file_exists($filePath)) { + // TODO: ACCEPT JSON $response->write(file_get_contents($filePath)); $response = $response->withHeader('Cache-Control', 'max-age=2592000'); $response = $response->withHeader('Content-Type', mime_content_type($filePath)); diff --git a/js/components/batterycard.js b/js/components/batterycard.js index 1419b59c..7ca7cb31 100644 --- a/js/components/batterycard.js +++ b/js/components/batterycard.js @@ -11,6 +11,8 @@ class batterycard this.scope = scopeSelector != null ? $(scopeSelector) : $(document); var jScope = this.scope; this.$ = scopeSelector != null ? (selector) => jScope.find(selector) : $; + + this.Grocy.PreloadView("batteriesjournal"); } Refresh(batteryId) diff --git a/js/components/chorecard.js b/js/components/chorecard.js index 441c5ff0..2c3be41a 100644 --- a/js/components/chorecard.js +++ b/js/components/chorecard.js @@ -11,6 +11,8 @@ class chorecard this.scope = scopeSelector != null ? $(scopeSelector) : $(document); var jScope = this.scope; this.$ = scopeSelector != null ? (selector) => jScope.find(selector) : $; + + this.Grocy.PreloadView("choresjournal"); } Refresh(choreId) diff --git a/js/components/productcard.js b/js/components/productcard.js index e0b2532a..e9f6942a 100644 --- a/js/components/productcard.js +++ b/js/components/productcard.js @@ -28,6 +28,10 @@ class productcard .find("a[data-toggle='collapse']") .text(self.Grocy.translate("Show more")); }) + + // preload some views. + this.Grocy.PreloadView("stockentries"); + this.Grocy.PreloadView("stockjournal"); } Refresh(productId) diff --git a/js/configs/globalstate.js b/js/configs/globalstate.js index e3f272a1..6b034827 100644 --- a/js/configs/globalstate.js +++ b/js/configs/globalstate.js @@ -190,22 +190,7 @@ function setInitialGlobalState(Grocy) var link = $(e.currentTarget).attr("href"); - bootbox.dialog({ - message: '', - size: 'large', - backdrop: true, - closeButton: false, - buttons: { - cancel: { - label: __t('Close'), - className: 'btn-secondary responsive-button', - callback: function() - { - bootbox.hideAll(); - } - } - } - }); + Grocy.OpenSubView(link); }); // serializeJSON defaults diff --git a/js/grocy.js b/js/grocy.js index 5970881f..6f272818 100644 --- a/js/grocy.js +++ b/js/grocy.js @@ -13,6 +13,8 @@ import { animateCSS, BoolVal, EmptyElementWhenMatches } from "./helpers/extensio import Translator from "gettext-translator"; import { WindowMessageBag } from './helpers/messagebag'; import * as components from './components'; +import * as uuid from 'uuid'; +import { GrocyProxy } from "./lib/proxy"; import "./helpers/string"; @@ -54,6 +56,8 @@ class GrocyClass this.initComponents = []; this.RootGrocy = null; + this.documentReady = false; + this.preloadViews = []; // Init some classes this.Api = new GrocyApi(this); @@ -114,6 +118,18 @@ class GrocyClass } }); } + + $(document).on('ready', () => + { + this.documentReady = true; + var element = self.preloadViews.pop(); + while (element !== undefined) + { + self.preloadViews(element.viewName, element.loadCss, element.cb); + + element = self.preloadViews.pop(); + } + }) } static createSingleton(config, view) @@ -240,11 +256,19 @@ class GrocyClass } } - LoadView(viewName, scope = null) + LoadView(viewName, scope = null, grocy = null) { if (Object.prototype.hasOwnProperty.call(window, viewName + "View")) { - window[viewName + "View"](this, scope); + if (scope != null && grocy == null) + { + console.warn("scoped view set but non-scoped grocy is used. Results are undefined!"); + } + if (scope == null) + { + grocy = this; + } + window[viewName + "View"](grocy, scope); } else { @@ -254,6 +278,12 @@ class GrocyClass PreloadView(viewName, loadCSS = false, cb = () => { }) { + if (!this.documentReady) + { + this.preloadViews.push({ viewName: viewName, loadCss: loadCss, cb: cb }); + return; + } + if (!Object.prototype.hasOwnProperty.call(window, viewName + "View")) { $.ajax({ @@ -277,6 +307,46 @@ class GrocyClass } } + OpenSubView(link) + { + var self = this; + $.ajax({ + dataType: "json", + link, + success: (data) => + { + let scopeId = uuid.v4() + var proxy = new GrocyProxy(this, "#" + scopeId, data.config, link); + + bootbox.dialog({ + message: '
' + data.template + '
', + size: 'large', + backdrop: true, + closeButton: false, + buttons: { + cancel: { + label: self.translate('Close'), + className: 'btn-secondary responsive-button', + callback: function() + { + proxy.Unload(); + bootbox.hideAll(); + } + } + }, + onShow: () => + { + // dialog div is alive, init view. + // this occurs before the view is shown. + self.LoadView(data.viewJsName, "#" + scopeId, proxy); + } + }); + } + }) + + + } + UndoStockBooking(bookingId) { var self = this; diff --git a/js/lib/proxy.js b/js/lib/proxy.js index 511ae436..ddc5600b 100644 --- a/js/lib/proxy.js +++ b/js/lib/proxy.js @@ -31,12 +31,20 @@ class GrocyProxy // scoping this.scopeSelector = scopeSelector; - this.scope = $(scope); - this.$scope = this.scope.find; + this.scope = $(scopeSelector); + var jScope = this.scope; + this.$scope = (selector) => jScope.find(selector); var queryString = url.split('?', 2); this.virtualUrl = queryString.length == 2 ? queryString[1] : ""; // maximum two parts this.config = config; + if (Object.prototype.hasOwnProperty.call(this.config, "UserSettings")) + { + // if we need to override UserSettings, we need to copy the object. + // not great, but eh. + Object.assign(this.config.UserSettings, RootGrocy.UserSettings); + this.UserSettings = config.UserSettings; + } this.configProxy = Proxy.revocable(this.config, { get: function(target, prop, receiver) @@ -47,7 +55,7 @@ class GrocyProxy } else { - return Reflect.get(rootGrocy.config, prop, target); + return Reflect.get(RootGrocy.config, prop, target); } } }) @@ -130,10 +138,10 @@ class GrocyProxy UpdateUriParam(key, value) { - params = {} + var params = {} var vars = this.virtualUrl.split("&"); - for (part of vars) + for (let part of vars) { var lkey, lvalue; [lkey, lvalue = null] = part.split('='); @@ -144,6 +152,7 @@ class GrocyProxy params[key] = value; var vurl = "" + for ([key, value] of params) { vurl += "&" + key @@ -157,10 +166,10 @@ class GrocyProxy RemoveUriParam(key) { - params = {} + var params = {} var vars = this.virtualUrl.split("&"); - for (part of vars) + for (let part of vars) { var lkey, lvalue; [lkey, lvalue = null] = part.split('='); @@ -172,6 +181,7 @@ class GrocyProxy } var vurl = "" + let value; for ([key, value] of params) { vurl += "&" + key diff --git a/js/viewjs/batteries.js b/js/viewjs/batteries.js index 5c99e0ed..48e104a9 100644 --- a/js/viewjs/batteries.js +++ b/js/viewjs/batteries.js @@ -6,6 +6,12 @@ $scope = (scope) => $(scope).find(scope); } + // preload some views. + top.on('load', () => + { + Grocy.PreloadView("batteryform"); + }); + var batteriesTable = $scope('#batteries-table').DataTable({ 'order': [[1, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/batteriesoverview.js b/js/viewjs/batteriesoverview.js index 59b59eba..ad7641c5 100644 --- a/js/viewjs/batteriesoverview.js +++ b/js/viewjs/batteriesoverview.js @@ -8,6 +8,13 @@ var batterycard = Grocy.Use("batterycard"); + // preload some views. + top.on('load', () => + { + Grocy.PreloadView("batteriesjournal"); + Grocy.PreloadView("batteryform"); + }); + var batteriesOverviewTable = $scope('#batteries-overview-table').DataTable({ 'order': [[4, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/choresoverview.js b/js/viewjs/choresoverview.js index ae821435..345ab438 100644 --- a/js/viewjs/choresoverview.js +++ b/js/viewjs/choresoverview.js @@ -10,6 +10,12 @@ var chorecard = Grocy.Use("chorecard"); + // preload some views. + top.on('load', () => + { + Grocy.PreloadView("choresjournal"); + }); + var choresOverviewTable = $scope('#chores-overview-table').DataTable({ 'order': [[2, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/locations.js b/js/viewjs/locations.js index fb48d790..552d3d3b 100644 --- a/js/viewjs/locations.js +++ b/js/viewjs/locations.js @@ -6,6 +6,12 @@ $scope = (scope) => $(scope).find(scope); } + // preload some views. + top.on('load', () => + { + Grocy.PreloadView("locationform"); + }); + var locationsTable = $scope('#locations-table').DataTable({ 'order': [[1, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/productform.js b/js/viewjs/productform.js index 7cecef37..2c0149cd 100644 --- a/js/viewjs/productform.js +++ b/js/viewjs/productform.js @@ -11,6 +11,13 @@ function productformView(Grocy, scope = null) } Grocy.Use("numberpicker"); + + // preload some views. + top.on('load', () => + { + Grocy.PreloadView("productgroupform"); + }); + var shoppinglocationpicker = Grocy.Use("shoppinglocationpicker"); var userfields = Grocy.Use("userfieldsform"); var productpicker = Grocy.Use("productpicker"); diff --git a/js/viewjs/productgroups.js b/js/viewjs/productgroups.js index b618cc3e..9b60d5a8 100644 --- a/js/viewjs/productgroups.js +++ b/js/viewjs/productgroups.js @@ -6,6 +6,10 @@ $scope = (scope) => $(scope).find(scope); } + // preload some views. + Grocy.PreloadView("productgroupform"); + + var groupsTable = $scope('#productgroups-table').DataTable({ 'order': [[1, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/quantityunitform.js b/js/viewjs/quantityunitform.js index 7db364ca..840c3025 100644 --- a/js/viewjs/quantityunitform.js +++ b/js/viewjs/quantityunitform.js @@ -10,6 +10,11 @@ function quantityunitformView(Grocy, scope = null) var userfields = Grocy.Use("userfieldsform"); + // preload some views. + + Grocy.PreloadView("quantityunitconversionform"); + + $scope('.save-quantityunit-button').on('click', function(e) { e.preventDefault(); diff --git a/js/viewjs/shoppinglist.js b/js/viewjs/shoppinglist.js index 866f43b2..5596c004 100644 --- a/js/viewjs/shoppinglist.js +++ b/js/viewjs/shoppinglist.js @@ -15,6 +15,12 @@ function shoppinglistView(Grocy, scope = null) $scope = (scope) => $(scope).find(scope); } + // preload some views. + + Grocy.PreloadView("shoppinglistform"); + Grocy.PreloadView("shoppinglistitemform"); + + Grocy.Use("calendarcard"); var productcard = Grocy.Use("productcard"); diff --git a/js/viewjs/shoppinglocations.js b/js/viewjs/shoppinglocations.js index 7b866aeb..d165b08b 100644 --- a/js/viewjs/shoppinglocations.js +++ b/js/viewjs/shoppinglocations.js @@ -6,6 +6,11 @@ $scope = (scope) => $(scope).find(scope); } + // preload some views. + + Grocy.PreloadView("shoppinglocationform"); + + var locationsTable = $scope('#shoppinglocations-table').DataTable({ 'order': [[1, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/stockentries.js b/js/viewjs/stockentries.js index 667fb77c..ede85e9b 100644 --- a/js/viewjs/stockentries.js +++ b/js/viewjs/stockentries.js @@ -11,6 +11,19 @@ var productcard = Grocy.Use("productcard"); var productpicker = Grocy.Use("productpicker"); + // preload some views. + Grocy.PreloadView("stockentryform"); + Grocy.PreloadView("shoppinglistitemform"); + Grocy.PreloadView("purchase"); + Grocy.PreloadView("conusme"); + Grocy.PreloadView("inventory"); + Grocy.PreloadView("stockjournal"); + Grocy.PreloadView("stockjournalsummary"); + + if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) + Grocy.PreloadView("transfer"); + + var stockEntriesTable = $scope('#stockentries-table').DataTable({ 'order': [[2, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/stockoverview.js b/js/viewjs/stockoverview.js index 0d036db1..250bbfd7 100755 --- a/js/viewjs/stockoverview.js +++ b/js/viewjs/stockoverview.js @@ -9,6 +9,19 @@ var productcard = Grocy.Use("productcard"); + // preload some views. + + Grocy.PreloadView("stockentries"); + Grocy.PreloadView("shoppinglistitemform"); + Grocy.PreloadView("purchase"); + Grocy.PreloadView("conusme"); + Grocy.PreloadView("inventory"); + Grocy.PreloadView("stockjournal"); + Grocy.PreloadView("stockjournalsummary"); + + if (Grocy.FeatureFlags.GROCY_FEATURE_FLAG_STOCK_LOCATION_TRACKING) + Grocy.PreloadView("transfer"); + var stockOverviewTable = $scope('#stock-overview-table').DataTable({ 'order': [[5, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/taskcategories.js b/js/viewjs/taskcategories.js index f45af240..e0fc8aef 100644 --- a/js/viewjs/taskcategories.js +++ b/js/viewjs/taskcategories.js @@ -6,6 +6,11 @@ $scope = (scope) => $(scope).find(scope); } + // preload some views. + + Grocy.PreloadView("taskcategoryform"); + + var categoriesTable = $scope('#taskcategories-table').DataTable({ 'order': [[1, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/tasks.js b/js/viewjs/tasks.js index 9c13597d..52c1674b 100644 --- a/js/viewjs/tasks.js +++ b/js/viewjs/tasks.js @@ -8,6 +8,10 @@ $scope = (scope) => $(scope).find(scope); } + // preload some views. + Grocy.PreloadView("taskform"); + + var tasksTable = $scope('#tasks-table').DataTable({ 'order': [[2, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/userentities.js b/js/viewjs/userentities.js index 8920222b..e0ce6202 100644 --- a/js/viewjs/userentities.js +++ b/js/viewjs/userentities.js @@ -5,6 +5,9 @@ { $scope = (scope) => $(scope).find(scope); } + // preload some views. + Grocy.PreloadView("userentityform") + var userentitiesTable = $scope('#userentities-table').DataTable({ 'order': [[1, 'asc']], diff --git a/js/viewjs/userfields.js b/js/viewjs/userfields.js index bd944152..8a7b7570 100644 --- a/js/viewjs/userfields.js +++ b/js/viewjs/userfields.js @@ -6,6 +6,10 @@ $scope = (scope) => $(scope).find(scope); } + // preload some views. + Grocy.PreloadView("userfieldform"); + + var userfieldsTable = $scope('#userfields-table').DataTable({ 'order': [[1, 'asc']], 'columnDefs': [ diff --git a/js/viewjs/userobjects.js b/js/viewjs/userobjects.js index f4d6f65b..f5a0dc80 100644 --- a/js/viewjs/userobjects.js +++ b/js/viewjs/userobjects.js @@ -6,6 +6,10 @@ $scope = (scope) => $(scope).find(scope); } + // preload some views. + Grocy.PreloadView("userobjectform"); + + var userobjectsTable = $scope('#userobjects-table').DataTable({ 'order': [[1, 'asc']], 'columnDefs': [ diff --git a/package.json b/package.json index 6485aa69..d6997858 100644 --- a/package.json +++ b/package.json @@ -13,7 +13,7 @@ "@fullcalendar/timegrid": "4.4.2", "@rollup/plugin-eslint": "^8.0.1", "animate.css": "^3.7.2", - "bootbox": "^5.3.2", + "bootbox": "^5.5.2", "bootstrap": "^4.5.2", "bootstrap-select": "^1.13.18", "bwip-js": "^3.0.1", diff --git a/yarn.lock b/yarn.lock index fb668165..1d704cb3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1847,7 +1847,7 @@ __metadata: languageName: node linkType: hard -"bootbox@npm:^5.3.2": +"bootbox@npm:^5.5.2": version: 5.5.2 resolution: "bootbox@npm:5.5.2" dependencies: @@ -4709,7 +4709,7 @@ fsevents@~2.3.2: autoprefixer: ^10.2.6 babel-core: ^6.26.3 babel-preset-es2015: ^6.24.1 - bootbox: ^5.3.2 + bootbox: ^5.5.2 bootstrap: ^4.5.2 bootstrap-select: ^1.13.18 browserslist: ^4.16.6