mirror of
https://github.com/grocy/grocy.git
synced 2026-04-05 12:26:15 +02:00
Nuke popup iFrames
This commit is contained in:
parent
29f1119c16
commit
7a7e944c09
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
77
js/grocy.js
77
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
|
|||
$("<link/>", {
|
||||
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: '<div id="' + scopeId + '">' + data.template + '</div>',
|
||||
message: '<div class="embedded" id="' + scopeId + '">' + data.template + '</div>',
|
||||
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); }
|
||||
})
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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']],
|
||||
|
|
|
|||
|
|
@ -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']],
|
||||
|
|
|
|||
|
|
@ -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']],
|
||||
|
|
|
|||
|
|
@ -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']],
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -17,8 +17,12 @@
|
|||
@endsection
|
||||
|
||||
@section('content')
|
||||
@php
|
||||
$classes = $embedded ? '' : 'col-md-6 col-xl-4';
|
||||
@endphp
|
||||
|
||||
<div class="row">
|
||||
<div class="col-xs-12 col-md-6 col-xl-4 pb-3">
|
||||
<div class="col-12 {{ $classes }} pb-3">
|
||||
<div class="title-related-links">
|
||||
<h2 class="title">@yield('title')</h2>
|
||||
<button class="btn btn-outline-dark d-md-none mt-2 float-right order-1 order-md-3 hide-when-embedded"
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user