diff --git a/controllers/BaseController.php b/controllers/BaseController.php
index 4219e7be..8a84b68c 100644
--- a/controllers/BaseController.php
+++ b/controllers/BaseController.php
@@ -197,7 +197,7 @@ class BaseController
return $this->View->render($response, $page, $data);
}
- protected function renderPage($response, $page, $data = [])
+ protected function renderPage($request, $response, $page, $data = [])
{
$this->View->set('userentitiesForSidebar', $this->getDatabase()->userentities()->where('show_in_sidebar_menu = 1')->orderBy('name'));
try
@@ -217,7 +217,7 @@ class BaseController
// Happens when database is not initialised or migrated...
}
- return $this->render($response, $page, $data);
+ return $this->render($request, $response, $page, $data);
}
private static $htmlPurifierInstance = null;
diff --git a/controllers/OpenApiController.php b/controllers/OpenApiController.php
index e3c35159..cd4d19e2 100644
--- a/controllers/OpenApiController.php
+++ b/controllers/OpenApiController.php
@@ -68,7 +68,7 @@ class OpenApiController extends BaseApiController
public function DocumentationUi(\Psr\Http\Message\ServerRequestInterface $request, \Psr\Http\Message\ResponseInterface $response, array $args)
{
- return $this->render($response, 'openapiui');
+ return $this->render($request, $response, 'openapiui');
}
public function __construct(\DI\Container $container)
diff --git a/gulpfile.babel.js b/gulpfile.babel.js
index b35b6b65..3ce7d0cd 100644
--- a/gulpfile.babel.js
+++ b/gulpfile.babel.js
@@ -88,7 +88,6 @@ view_eslint_config.globals = eslint_config.globals.concat([
// viewjs handling
var files = glob.sync('./js/viewjs/*.js');
-var components = glob.sync('./js/viewjs/components/*.js');
var viewJStasks = [];
@@ -111,32 +110,10 @@ files.forEach(function(target)
.pipe(gulpif(minify, uglify()))
.pipe(buffer())
.pipe(sourcemaps.init({ loadMaps: true }))
- .pipe(sourcemaps.write('.'))
+ .pipe(sourcemaps.write('.', { sourceMappingURLPrefix: '/viewjs' }))
.pipe(dest('./public/viewjs')));
viewJStasks.push(target);
});
-components.forEach(function(target)
-{
- task(target, cb => rollup({
- input: target,
- output: {
- format: 'umd',
- name: path.basename(target),
- sourcemap: 'inline',
- },
- plugins: [resolve(), rollupCss({
- dest: path.resolve('./public/css/viewcss/' + path.basename(target).replace(".js", ".css")),
- }), commonjs(), eslint(view_eslint_config)],
- })
- .pipe(source(path.basename(target), "./js/viewjs/components"))
- .pipe(buffer())
- .pipe(gulpif(minify, uglify()))
- .pipe(buffer())
- .pipe(sourcemaps.init({ loadMaps: true }))
- .pipe(sourcemaps.write('.'))
- .pipe(dest('./public/viewjs/components')));
- viewJStasks.push(target);
-});
// The `clean` function is not exported so it can be considered a private task.
// It can still be used within the `series()` composition.
diff --git a/js/grocy.js b/js/grocy.js
index 6f272818..fe11f001 100644
--- a/js/grocy.js
+++ b/js/grocy.js
@@ -107,6 +107,21 @@ class GrocyClass
}
});
+ window.addEventListener('load', function()
+ {
+ if (self.documentReady) return;
+
+ // preload views
+ self.documentReady = true;
+ var element = self.preloadViews.pop();
+ while (element !== undefined)
+ {
+ self.PreloadView(element.viewName, element.loadCss, element.cb);
+
+ element = self.preloadViews.pop();
+ }
+ });
+
// save the config
this.config = config;
@@ -118,18 +133,6 @@ 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)
@@ -280,7 +283,7 @@ class GrocyClass
{
if (!this.documentReady)
{
- this.preloadViews.push({ viewName: viewName, loadCss: loadCss, cb: cb });
+ this.preloadViews.push({ viewName: viewName, loadCss: loadCSS, cb: cb });
return;
}
@@ -297,7 +300,7 @@ class GrocyClass
$("", {
rel: "stylesheet",
type: "text/css",
- href: this.FormatUrl('/css/viewcss/' + viewName + '.cs')
+ href: this.FormatUrl('/css/viewcss/' + viewName + '.css')
}).appendTo("head");
}
}
@@ -310,16 +313,51 @@ class GrocyClass
OpenSubView(link)
{
var self = this;
+ console.log("loading subview " + link);
$.ajax({
dataType: "json",
- link,
+ url: link,
success: (data) =>
{
let scopeId = uuid.v4()
- var proxy = new GrocyProxy(this, "#" + scopeId, data.config, link);
+ var grocyProxy = new GrocyProxy(this, "#" + scopeId, data.config, link);
+ var proxy = new Proxy(grocyProxy, {
+ get: function(target, prop, receiver)
+ {
+ if (prop in grocyProxy)
+ {
+ return grocyProxy[prop];
+ }
+ else
+ {
+ return self[prop];
+ }
+ },
+ apply: function(target, thisArg, args)
+ {
+ if (target in grocyProxy)
+ {
+ return grocyProxy[target](...args);
+ }
+ else
+ {
+ return self[target](...args);
+ }
+ },
+ ownKeys: function(oTarget, sKey)
+ {
+ let root = Reflect.ownKeys(self);
+ Array.concat(root, Reflect.ownKeys(grocyProxy));
+ return root;
+ },
+ has: function(oTarget, sKey)
+ {
+ return sKey in self || sKey in grocyProxy;
+ },
+ });
bootbox.dialog({
- message: '
' + data.template + '
',
+ message: '' + data.template + '
',
size: 'large',
backdrop: true,
closeButton: false,
@@ -329,7 +367,6 @@ class GrocyClass
className: 'btn-secondary responsive-button',
callback: function()
{
- proxy.Unload();
bootbox.hideAll();
}
}
@@ -338,10 +375,12 @@ class GrocyClass
{
// dialog div is alive, init view.
// this occurs before the view is shown.
+ grocyProxy.Initialize(proxy);
self.LoadView(data.viewJsName, "#" + scopeId, proxy);
}
});
- }
+ },
+ error: (xhr, text, data) => { console.error(text); }
})
diff --git a/js/helpers/frontend.js b/js/helpers/frontend.js
index e1c20378..d6037b06 100644
--- a/js/helpers/frontend.js
+++ b/js/helpers/frontend.js
@@ -5,11 +5,11 @@ class GrocyFrontendHelpers
{
this.Grocy = Grocy;
this.Api = Api;
- var self = this;
if (scope != null)
{
this.scope = $(scope);
- this.$scope = (selector) => self.scope.find(selector);
+ var jScope = this.scope;
+ this.$scope = (selector) => jScope.find(selector);
this.scopeSelector = scope;
}
else
diff --git a/js/lib/proxy.js b/js/lib/proxy.js
index ddc5600b..820bef69 100644
--- a/js/lib/proxy.js
+++ b/js/lib/proxy.js
@@ -4,14 +4,13 @@ import * as components from '../components';
class GrocyProxy
{
-
constructor(RootGrocy, scopeSelector, config, url)
{
this.RootGrocy = RootGrocy;
// proxy-local members, because they might not be set globally.
this.QuantityUnits = config.QuantityUnits;
- this.QuantityUnitConversionsResolved = config.QuantityUnitConversionsResolved || [];
+ this.QuantityUnitConversionsResolved = config.QuantityUnitConversionsResolved;
this.QuantityUnitEditFormRedirectUri = config.QuantityUnitEditFormRedirectUri;
this.MealPlanFirstDayOfWeek = config.MealPlanFirstDayOfWeek;
this.EditMode = config.EditMode;
@@ -31,9 +30,9 @@ class GrocyProxy
// scoping
this.scopeSelector = scopeSelector;
- this.scope = $(scopeSelector);
- var jScope = this.scope;
- this.$scope = (selector) => jScope.find(selector);
+ this.scope = null;
+ this.$scope = null;
+
var queryString = url.split('?', 2);
this.virtualUrl = queryString.length == 2 ? queryString[1] : ""; // maximum two parts
@@ -45,52 +44,19 @@ class GrocyProxy
Object.assign(this.config.UserSettings, RootGrocy.UserSettings);
this.UserSettings = config.UserSettings;
}
-
- this.configProxy = Proxy.revocable(this.config, {
- get: function(target, prop, receiver)
- {
- if (Object.prototype.hasOwnProperty.call(target, prop))
- {
- return Reflect.get(...arguments);
- }
- else
- {
- return Reflect.get(RootGrocy.config, prop, target);
- }
- }
- })
-
- // This is where the magic happens!
- // basically, this Proxy object checks if a member is defined in this proxy class,
- // and returns it if so.
- // If not, the prop is handed over to the root grocy instance.
- this.grocyProxy = Proxy.revocable(this, {
- get: function(target, prop, receiver)
- {
- if (Object.prototype.hasOwnProperty.call(target, prop))
- {
- return Reflect.get(...arguments)
- }
- else
- {
- return Reflect.get(RootGrocy, prop, receiver);
- }
- }
- });
-
- // scoped variants of some helpers
- this.FrontendHelpers = new GrocyFrontendHelpers(this, RootGrocy.Api, this.scopeSelector);
}
- Unload()
+ Initialize(proxy)
{
- this.grocyProxy.revoke();
- this.configProxy.revoke();
+ this.scope = $(this.scopeSelector);
+ var jScope = this.scope;
+ this.$scope = (selector) => jScope.find(selector);
+ this.FrontendHelpers = new GrocyFrontendHelpers(proxy, this.RootGrocy.Api, this.scopeSelector);
}
Use(componentName, scope = null)
{
- let scopeName = scope || "";
+ let scopeName = scope || this.scopeSelector;
// initialize Components only once per scope
if (this.initComponents.find(elem => elem == componentName + scopeName))
return this.Components[componentName + scopeName];
@@ -109,14 +75,6 @@ class GrocyProxy
}
}
- LoadView(viewName)
- {
- if (Object.prototype.hasOwnProperty.call(window, viewName + "View"))
- {
- window[viewName + "View"](this, this.scopeSelector);
- }
- }
-
// URI params on integrated components don't work because they
// don't have an URL. So let's fake it.
GetUriParam(key)
diff --git a/js/viewjs/batteries.js b/js/viewjs/batteries.js
index 48e104a9..9ba4be21 100644
--- a/js/viewjs/batteries.js
+++ b/js/viewjs/batteries.js
@@ -7,10 +7,8 @@
}
// preload some views.
- top.on('load', () =>
- {
- Grocy.PreloadView("batteryform");
- });
+ Grocy.PreloadView("batteryform");
+
var batteriesTable = $scope('#batteries-table').DataTable({
'order': [[1, 'asc']],
diff --git a/js/viewjs/batteriesoverview.js b/js/viewjs/batteriesoverview.js
index ad7641c5..d7bd8b4a 100644
--- a/js/viewjs/batteriesoverview.js
+++ b/js/viewjs/batteriesoverview.js
@@ -9,11 +9,9 @@
var batterycard = Grocy.Use("batterycard");
// preload some views.
- top.on('load', () =>
- {
- Grocy.PreloadView("batteriesjournal");
- Grocy.PreloadView("batteryform");
- });
+ Grocy.PreloadView("batteriesjournal");
+ Grocy.PreloadView("batteryform");
+
var batteriesOverviewTable = $scope('#batteries-overview-table').DataTable({
'order': [[4, 'asc']],
diff --git a/js/viewjs/choresoverview.js b/js/viewjs/choresoverview.js
index 345ab438..7f492a39 100644
--- a/js/viewjs/choresoverview.js
+++ b/js/viewjs/choresoverview.js
@@ -11,10 +11,8 @@
var chorecard = Grocy.Use("chorecard");
// preload some views.
- top.on('load', () =>
- {
- Grocy.PreloadView("choresjournal");
- });
+ Grocy.PreloadView("choresjournal");
+
var choresOverviewTable = $scope('#chores-overview-table').DataTable({
'order': [[2, 'asc']],
diff --git a/js/viewjs/locations.js b/js/viewjs/locations.js
index 552d3d3b..bd893656 100644
--- a/js/viewjs/locations.js
+++ b/js/viewjs/locations.js
@@ -7,10 +7,7 @@
}
// preload some views.
- top.on('load', () =>
- {
- Grocy.PreloadView("locationform");
- });
+ Grocy.PreloadView("locationform");
var locationsTable = $scope('#locations-table').DataTable({
'order': [[1, 'asc']],
diff --git a/js/viewjs/productform.js b/js/viewjs/productform.js
index 2c0149cd..b7e8bc8d 100644
--- a/js/viewjs/productform.js
+++ b/js/viewjs/productform.js
@@ -13,10 +13,7 @@ function productformView(Grocy, scope = null)
Grocy.Use("numberpicker");
// preload some views.
- top.on('load', () =>
- {
- Grocy.PreloadView("productgroupform");
- });
+ Grocy.PreloadView("productgroupform");
var shoppinglocationpicker = Grocy.Use("shoppinglocationpicker");
var userfields = Grocy.Use("userfieldsform");
diff --git a/js/viewjs/stockentries.js b/js/viewjs/stockentries.js
index ede85e9b..d42054bc 100644
--- a/js/viewjs/stockentries.js
+++ b/js/viewjs/stockentries.js
@@ -15,7 +15,7 @@
Grocy.PreloadView("stockentryform");
Grocy.PreloadView("shoppinglistitemform");
Grocy.PreloadView("purchase");
- Grocy.PreloadView("conusme");
+ Grocy.PreloadView("consume");
Grocy.PreloadView("inventory");
Grocy.PreloadView("stockjournal");
Grocy.PreloadView("stockjournalsummary");
diff --git a/js/viewjs/stockoverview.js b/js/viewjs/stockoverview.js
index 250bbfd7..42f00b9f 100755
--- a/js/viewjs/stockoverview.js
+++ b/js/viewjs/stockoverview.js
@@ -14,7 +14,7 @@
Grocy.PreloadView("stockentries");
Grocy.PreloadView("shoppinglistitemform");
Grocy.PreloadView("purchase");
- Grocy.PreloadView("conusme");
+ Grocy.PreloadView("consume");
Grocy.PreloadView("inventory");
Grocy.PreloadView("stockjournal");
Grocy.PreloadView("stockjournalsummary");
diff --git a/views/layout/json.blade.php b/views/layout/json.blade.php
index c006ea1f..abde07a1 100644
--- a/views/layout/json.blade.php
+++ b/views/layout/json.blade.php
@@ -1,5 +1,28 @@
@php
// this is a shoe-horned method to generate a "proper" subview as JSON.
+$content = $__env->yieldContent('content');
+// Javascript is not JSON, so we need to do some trickery
+// to reencode stuff like additional , at the end or
+// ' instead of " as field delimter.
+$config = "{\n" . $__env->yieldContent('grocyConfigProps') . '}';
+$config = preg_replace('/(\n[\t ]*)([a-zA-Z0-9]+):/','${1}"${2}":', $config);
+$config = preg_replace('/: *\'(.*?)\',?\n/', ':"${1}",', $config);
+$config = preg_replace('/,}$/', '}', $config);
+$grocy_options = json_decode($config, true);
+
+$usersettings = $__env->yieldContent('forceUserSettings');
+$usersettings = json_decode('{' . $usersettings . '}');
+if($usersettings != null)
+ $grocy_options["UserSettings"] = $usersettings;
+
+// worst case this burns on the front end.
+$viewname = trim($__env->yieldContent('viewJsName'));
+
+echo json_encode([
+ 'template' => $content,
+ 'config' => $grocy_options,
+ 'viewJsName' => $viewname,
+ ]);
@endphp
\ No newline at end of file
diff --git a/views/purchase.blade.php b/views/purchase.blade.php
index 2820ce8e..e66cd69c 100644
--- a/views/purchase.blade.php
+++ b/views/purchase.blade.php
@@ -17,8 +17,12 @@
@endsection
@section('content')
+@php
+$classes = $embedded ? '' : 'col-md-6 col-xl-4';
+@endphp
+