diff --git a/aircox/models/page.py b/aircox/models/page.py
index 6a51195..ef5b390 100644
--- a/aircox/models/page.py
+++ b/aircox/models/page.py
@@ -185,12 +185,25 @@ class StaticPage(BasePage):
(ATTACH_TO_EPISODES, _('Episodes list')),
(ATTACH_TO_ARTICLES, _('Articles list')),
)
+ VIEWS = {
+ ATTACH_TO_HOME: 'home',
+ ATTACH_TO_DIFFUSIONS: 'diffusion-list',
+ ATTACH_TO_LOGS: 'log-list',
+ ATTACH_TO_PROGRAMS: 'program-list',
+ ATTACH_TO_EPISODES: 'episode-list',
+ ATTACH_TO_ARTICLES: 'article-list',
+ }
attach_to = models.SmallIntegerField(
_('attach to'), choices=ATTACH_TO_CHOICES, blank=True, null=True,
help_text=_('display this page content to related element'),
)
+ def get_absolute_url(self):
+ if self.attach_to:
+ return reverse(self.VIEWS[self.attach_to])
+ return super().get_absolute_url()
+
class Comment(models.Model):
page = models.ForeignKey(
@@ -216,8 +229,7 @@ class NavItem(models.Model):
text = models.CharField(_('title'), max_length=64)
url = models.CharField(_('url'), max_length=256, blank=True, null=True)
page = models.ForeignKey(StaticPage, models.CASCADE,
- verbose_name=_('page'), blank=True, null=True,
- limit_choices_to={'attach_to__isnull': True})
+ verbose_name=_('page'), blank=True, null=True)
class Meta:
verbose_name = _('Menu item')
verbose_name_plural = _('Menu items')
diff --git a/aircox/static/aircox/admin.js b/aircox/static/aircox/admin.js
index 30e4fa7..a5611e3 100644
--- a/aircox/static/aircox/admin.js
+++ b/aircox/static/aircox/admin.js
@@ -222,7 +222,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _nod
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"defaultConfig\", function() { return defaultConfig; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return AppBuilder; });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n\n\nconst defaultConfig = {\n el: '#app',\n delimiters: ['[[', ']]'],\n\n computed: {\n player() { return window.aircox.player; },\n },\n}\n\n\nclass AppBuilder {\n constructor(config={}) {\n this._config = config;\n this.app = null;\n }\n\n get config() {\n let config = this._config instanceof Function ? this._config() : this._config;\n for(var k of new Set([...Object.keys(config || {}), ...Object.keys(defaultConfig)])) {\n if(!config[k] && defaultConfig[k])\n config[k] = defaultConfig[k]\n else if(config[k] instanceof Object)\n config[k] = {...defaultConfig[k], ...config[k]}\n }\n return config;\n }\n\n set config(value) {\n this._config = value;\n }\n\n destroy() {\n self.app && self.app.$destroy();\n self.app = null;\n }\n\n fetch(url, options) {\n return fetch(url, options).then(response => response.text())\n .then(content => {\n let doc = new DOMParser().parseFromString(content, 'text/html');\n let app = doc.getElementById('app');\n content = app ? app.innerHTML : content;\n return this.load({sync: true, content, title: doc.title, url })\n })\n }\n\n load({async=false,content=null, title=null, url=null}={}) {\n var self = this;\n return new Promise((resolve, reject) => {\n let func = () => {\n try {\n let config = self.config;\n const el = document.querySelector(config.el);\n if(!el)\n return reject(`Error: can't get element ${config.el}`)\n\n if(content)\n el.innerHTML = content\n if(title)\n document.title = title;\n if(url && content)\n history.pushState({ content: content, title: title }, '', url)\n\n this.app = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"](config);\n resolve(self.app)\n } catch(error) {\n self.destroy();\n reject(error)\n }};\n async ? window.addEventListener('load', func) : func();\n });\n }\n\n loadFromState(state) {\n return this.load({ content: state.content, title: state.title });\n }\n}\n\n\n\n\n//# sourceURL=webpack:///./assets/public/app.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"defaultConfig\", function() { return defaultConfig; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return AppBuilder; });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n\n\nconst defaultConfig = {\n el: '#app',\n delimiters: ['[[', ']]'],\n\n computed: {\n player() { return window.aircox.player; },\n },\n}\n\n\nclass AppBuilder {\n constructor(config={}) {\n this._config = config;\n this.title = null;\n this.app = null;\n }\n\n get config() {\n let config = this._config instanceof Function ? this._config() : this._config;\n for(var k of new Set([...Object.keys(config || {}), ...Object.keys(defaultConfig)])) {\n if(!config[k] && defaultConfig[k])\n config[k] = defaultConfig[k]\n else if(config[k] instanceof Object)\n config[k] = {...defaultConfig[k], ...config[k]}\n }\n return config;\n }\n\n set config(value) {\n this._config = value;\n }\n\n destroy() {\n self.app && self.app.$destroy();\n self.app = null;\n }\n\n fetch(url, options) {\n return fetch(url, options).then(response => response.text())\n .then(content => {\n let doc = new DOMParser().parseFromString(content, 'text/html');\n let app = doc.getElementById('app');\n content = app ? app.innerHTML : content;\n return this.load({sync: true, content, title: doc.title, url })\n })\n }\n\n load({async=false,content=null,title=null}={}) {\n var self = this;\n return new Promise((resolve, reject) => {\n let func = () => {\n try {\n let config = self.config;\n const el = document.querySelector(config.el);\n if(!el)\n return reject(`Error: can't get element ${config.el}`)\n\n if(content)\n el.innerHTML = content\n if(title)\n document.title = title;\n this.app = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"](config);\n resolve(self.app)\n } catch(error) {\n self.destroy();\n reject(error)\n }};\n async ? window.addEventListener('load', func) : func();\n });\n }\n\n /// Save application state into browser history\n historySave(url,replace=false) {\n const el = document.querySelector(this.config.el);\n const state = {\n content: el.innerHTML,\n title: document.title,\n };\n\n if(replace)\n history.replaceState(state, '', url)\n else\n history.pushState(state, '', url)\n }\n\n /// Load application from browser history's state\n historyLoad(state) {\n return this.load({ content: state.content, title: state.title });\n }\n}\n\n\n\n\n//# sourceURL=webpack:///./assets/public/app.js?");
/***/ }),
@@ -306,7 +306,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _nod
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/all.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/all.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/fontawesome.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./app */ \"./assets/public/app.js\");\n/* harmony import */ var _sound__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./sound */ \"./assets/public/sound.js\");\n/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./model */ \"./assets/public/model.js\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./styles.scss */ \"./assets/public/styles.scss\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_styles_scss__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _autocomplete__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./autocomplete */ \"./assets/public/autocomplete.vue\");\n/* harmony import */ var _episode__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./episode */ \"./assets/public/episode.vue\");\n/* harmony import */ var _player__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./player */ \"./assets/public/player.vue\");\n/* harmony import */ var _playlist__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./playlist */ \"./assets/public/playlist.vue\");\n/* harmony import */ var _soundItem__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./soundItem */ \"./assets/public/soundItem.vue\");\n/**\n * This module includes code available for both the public website and\n * administration interface)\n */\n//-- vendor\n\n\n\n\n\n\n//-- aircox\n\n\n\n\n\n\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-autocomplete', _autocomplete__WEBPACK_IMPORTED_MODULE_7__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-episode', _episode__WEBPACK_IMPORTED_MODULE_8__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-player', _player__WEBPACK_IMPORTED_MODULE_9__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-playlist', _playlist__WEBPACK_IMPORTED_MODULE_10__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-sound-item', _soundItem__WEBPACK_IMPORTED_MODULE_11__[\"default\"])\n\n\nwindow.aircox = {\n // main application\n appBuilder: null,\n appConfig: {},\n get app() { return this.appBuilder.app },\n\n // player application\n playerBuilder: null,\n get playerApp() { return this.playerBuilder && this.playerBuilder.app },\n get player() { return this.playerApp && this.playerApp.$refs.player },\n\n onPageFetch(event) {\n let submit = event.type == 'submit';\n let target = submit || event.target.tagName == 'A'\n ? event.target : event.target.closest('a');\n if(!target || target.hasAttribute('target'))\n return;\n\n let url = submit ? target.getAttribute('action') || ''\n : target.getAttribute('href');\n if(url===null || !(url === '' || url.startsWith('/') || url.startsWith('?')))\n return;\n\n let options = {};\n if(submit) {\n let formData = new FormData(event.target);\n if(target.method == 'get')\n url += '?' + (new URLSearchParams(formData)).toString();\n else {\n options['method'] = target.method;\n options['body'] = formData;\n }\n }\n this.appBuilder.fetch(url, options);\n event.preventDefault();\n event.stopPropagation();\n },\n\n Set: _model__WEBPACK_IMPORTED_MODULE_5__[\"Set\"], Sound: _sound__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n};\nwindow.Vue = vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"];\n\n\naircox.playerBuilder = new _app__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({el: '#player'});\naircox.playerBuilder.load({async:true});\naircox.appBuilder = new _app__WEBPACK_IMPORTED_MODULE_3__[\"default\"](x => window.aircox.appConfig);\naircox.appBuilder.load({async:true}).then(app => {\n //-- load page hooks\n window.addEventListener('click', event => aircox.onPageFetch(event), true);\n window.addEventListener('submit', event => aircox.onPageFetch(event), true);\n window.addEventListener('popstate', event => {\n if(event.state && event.state.content)\n aircox.appBuilder.loadFromState(event.state);\n });\n})\n\n\n\n\n//# sourceURL=webpack:///./assets/public/index.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/all.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/all.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/fontawesome.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./app */ \"./assets/public/app.js\");\n/* harmony import */ var _sound__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./sound */ \"./assets/public/sound.js\");\n/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./model */ \"./assets/public/model.js\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./styles.scss */ \"./assets/public/styles.scss\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_styles_scss__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _autocomplete__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./autocomplete */ \"./assets/public/autocomplete.vue\");\n/* harmony import */ var _episode__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./episode */ \"./assets/public/episode.vue\");\n/* harmony import */ var _player__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./player */ \"./assets/public/player.vue\");\n/* harmony import */ var _playlist__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./playlist */ \"./assets/public/playlist.vue\");\n/* harmony import */ var _soundItem__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./soundItem */ \"./assets/public/soundItem.vue\");\n/**\n * This module includes code available for both the public website and\n * administration interface)\n */\n//-- vendor\n\n\n\n\n\n\n//-- aircox\n\n\n\n\n\n\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-autocomplete', _autocomplete__WEBPACK_IMPORTED_MODULE_7__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-episode', _episode__WEBPACK_IMPORTED_MODULE_8__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-player', _player__WEBPACK_IMPORTED_MODULE_9__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-playlist', _playlist__WEBPACK_IMPORTED_MODULE_10__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-sound-item', _soundItem__WEBPACK_IMPORTED_MODULE_11__[\"default\"])\n\n\nwindow.aircox = {\n // main application\n appBuilder: null,\n appConfig: {},\n get app() { return this.appBuilder.app },\n\n // player application\n playerBuilder: null,\n get playerApp() { return this.playerBuilder && this.playerBuilder.app },\n get player() { return this.playerApp && this.playerApp.$refs.player },\n\n // Handle hot-reload (link click and form submits).\n onPageFetch(event) {\n let submit = event.type == 'submit';\n let target = submit || event.target.tagName == 'A'\n ? event.target : event.target.closest('a');\n if(!target || target.hasAttribute('target'))\n return;\n\n let url = submit ? target.getAttribute('action') || ''\n : target.getAttribute('href');\n if(url===null || !(url === '' || url.startsWith('/') || url.startsWith('?')))\n return;\n\n let options = {};\n if(submit) {\n let formData = new FormData(event.target);\n if(target.method == 'get')\n url += '?' + (new URLSearchParams(formData)).toString();\n else {\n options['method'] = target.method;\n options['body'] = formData;\n }\n }\n this.appBuilder.fetch(url, options).then(app => {\n this.appBuilder.historySave(url);\n });\n event.preventDefault();\n event.stopPropagation();\n },\n\n Set: _model__WEBPACK_IMPORTED_MODULE_5__[\"Set\"], Sound: _sound__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n};\nwindow.Vue = vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"];\n\n\naircox.playerBuilder = new _app__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({el: '#player'});\naircox.playerBuilder.load({async:true});\naircox.appBuilder = new _app__WEBPACK_IMPORTED_MODULE_3__[\"default\"](x => window.aircox.appConfig);\naircox.appBuilder.load({async:true}).then(app => {\n aircox.appBuilder.historySave(document.location, true);\n\n //-- load page hooks\n window.addEventListener('click', event => aircox.onPageFetch(event), true);\n window.addEventListener('submit', event => aircox.onPageFetch(event), true);\n window.addEventListener('popstate', event => {\n if(event.state && event.state.content) {\n document.title = aircox.appBuilder.title;\n aircox.appBuilder.historyLoad(event.state);\n }\n });\n})\n\n\n\n\n//# sourceURL=webpack:///./assets/public/index.js?");
/***/ }),
@@ -374,11 +374,11 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
/*!********************************!*\
!*** ./assets/public/page.vue ***!
\********************************/
-/*! no static exports found */
+/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./page.vue?vue&type=template&id=a4303912& */ \"./assets/public/page.vue?vue&type=template&id=a4303912&\");\n/* harmony import */ var _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./page.vue?vue&type=script&lang=js& */ \"./assets/public/page.vue?vue&type=script&lang=js&\");\n/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__) if([\"default\"].indexOf(__WEBPACK_IMPORT_KEY__) < 0) (function(key) { __webpack_require__.d(__webpack_exports__, key, function() { return _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[key]; }) }(__WEBPACK_IMPORT_KEY__));\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(\n _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__[\"render\"],\n _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/public/page.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/public/page.vue?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./page.vue?vue&type=template&id=a4303912& */ \"./assets/public/page.vue?vue&type=template&id=a4303912&\");\n/* harmony import */ var _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./page.vue?vue&type=script&lang=js& */ \"./assets/public/page.vue?vue&type=script&lang=js&\");\n/* empty/unused harmony star reexport *//* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(\n _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__[\"render\"],\n _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/public/page.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/public/page.vue?");
/***/ }),
@@ -386,7 +386,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _pag
/*!*********************************************************!*\
!*** ./assets/public/page.vue?vue&type=script&lang=js& ***!
\*********************************************************/
-/*! no static exports found */
+/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
diff --git a/aircox/static/aircox/main.js b/aircox/static/aircox/main.js
index 4fe990b..63813b6 100644
--- a/aircox/static/aircox/main.js
+++ b/aircox/static/aircox/main.js
@@ -163,7 +163,7 @@
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"defaultConfig\", function() { return defaultConfig; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return AppBuilder; });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n\n\nconst defaultConfig = {\n el: '#app',\n delimiters: ['[[', ']]'],\n\n computed: {\n player() { return window.aircox.player; },\n },\n}\n\n\nclass AppBuilder {\n constructor(config={}) {\n this._config = config;\n this.app = null;\n }\n\n get config() {\n let config = this._config instanceof Function ? this._config() : this._config;\n for(var k of new Set([...Object.keys(config || {}), ...Object.keys(defaultConfig)])) {\n if(!config[k] && defaultConfig[k])\n config[k] = defaultConfig[k]\n else if(config[k] instanceof Object)\n config[k] = {...defaultConfig[k], ...config[k]}\n }\n return config;\n }\n\n set config(value) {\n this._config = value;\n }\n\n destroy() {\n self.app && self.app.$destroy();\n self.app = null;\n }\n\n fetch(url, options) {\n return fetch(url, options).then(response => response.text())\n .then(content => {\n let doc = new DOMParser().parseFromString(content, 'text/html');\n let app = doc.getElementById('app');\n content = app ? app.innerHTML : content;\n return this.load({sync: true, content, title: doc.title, url })\n })\n }\n\n load({async=false,content=null, title=null, url=null}={}) {\n var self = this;\n return new Promise((resolve, reject) => {\n let func = () => {\n try {\n let config = self.config;\n const el = document.querySelector(config.el);\n if(!el)\n return reject(`Error: can't get element ${config.el}`)\n\n if(content)\n el.innerHTML = content\n if(title)\n document.title = title;\n if(url && content)\n history.pushState({ content: content, title: title }, '', url)\n\n this.app = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"](config);\n resolve(self.app)\n } catch(error) {\n self.destroy();\n reject(error)\n }};\n async ? window.addEventListener('load', func) : func();\n });\n }\n\n loadFromState(state) {\n return this.load({ content: state.content, title: state.title });\n }\n}\n\n\n\n\n//# sourceURL=webpack:///./assets/public/app.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"defaultConfig\", function() { return defaultConfig; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return AppBuilder; });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n\n\nconst defaultConfig = {\n el: '#app',\n delimiters: ['[[', ']]'],\n\n computed: {\n player() { return window.aircox.player; },\n },\n}\n\n\nclass AppBuilder {\n constructor(config={}) {\n this._config = config;\n this.title = null;\n this.app = null;\n }\n\n get config() {\n let config = this._config instanceof Function ? this._config() : this._config;\n for(var k of new Set([...Object.keys(config || {}), ...Object.keys(defaultConfig)])) {\n if(!config[k] && defaultConfig[k])\n config[k] = defaultConfig[k]\n else if(config[k] instanceof Object)\n config[k] = {...defaultConfig[k], ...config[k]}\n }\n return config;\n }\n\n set config(value) {\n this._config = value;\n }\n\n destroy() {\n self.app && self.app.$destroy();\n self.app = null;\n }\n\n fetch(url, options) {\n return fetch(url, options).then(response => response.text())\n .then(content => {\n let doc = new DOMParser().parseFromString(content, 'text/html');\n let app = doc.getElementById('app');\n content = app ? app.innerHTML : content;\n return this.load({sync: true, content, title: doc.title, url })\n })\n }\n\n load({async=false,content=null,title=null}={}) {\n var self = this;\n return new Promise((resolve, reject) => {\n let func = () => {\n try {\n let config = self.config;\n const el = document.querySelector(config.el);\n if(!el)\n return reject(`Error: can't get element ${config.el}`)\n\n if(content)\n el.innerHTML = content\n if(title)\n document.title = title;\n this.app = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"](config);\n resolve(self.app)\n } catch(error) {\n self.destroy();\n reject(error)\n }};\n async ? window.addEventListener('load', func) : func();\n });\n }\n\n /// Save application state into browser history\n historySave(url,replace=false) {\n const el = document.querySelector(this.config.el);\n const state = {\n content: el.innerHTML,\n title: document.title,\n };\n\n if(replace)\n history.replaceState(state, '', url)\n else\n history.pushState(state, '', url)\n }\n\n /// Load application from browser history's state\n historyLoad(state) {\n return this.load({ content: state.content, title: state.title });\n }\n}\n\n\n\n\n//# sourceURL=webpack:///./assets/public/app.js?");
/***/ }),
@@ -247,7 +247,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _nod
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/all.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/all.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/fontawesome.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./app */ \"./assets/public/app.js\");\n/* harmony import */ var _sound__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./sound */ \"./assets/public/sound.js\");\n/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./model */ \"./assets/public/model.js\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./styles.scss */ \"./assets/public/styles.scss\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_styles_scss__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _autocomplete__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./autocomplete */ \"./assets/public/autocomplete.vue\");\n/* harmony import */ var _episode__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./episode */ \"./assets/public/episode.vue\");\n/* harmony import */ var _player__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./player */ \"./assets/public/player.vue\");\n/* harmony import */ var _playlist__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./playlist */ \"./assets/public/playlist.vue\");\n/* harmony import */ var _soundItem__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./soundItem */ \"./assets/public/soundItem.vue\");\n/**\n * This module includes code available for both the public website and\n * administration interface)\n */\n//-- vendor\n\n\n\n\n\n\n//-- aircox\n\n\n\n\n\n\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-autocomplete', _autocomplete__WEBPACK_IMPORTED_MODULE_7__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-episode', _episode__WEBPACK_IMPORTED_MODULE_8__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-player', _player__WEBPACK_IMPORTED_MODULE_9__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-playlist', _playlist__WEBPACK_IMPORTED_MODULE_10__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-sound-item', _soundItem__WEBPACK_IMPORTED_MODULE_11__[\"default\"])\n\n\nwindow.aircox = {\n // main application\n appBuilder: null,\n appConfig: {},\n get app() { return this.appBuilder.app },\n\n // player application\n playerBuilder: null,\n get playerApp() { return this.playerBuilder && this.playerBuilder.app },\n get player() { return this.playerApp && this.playerApp.$refs.player },\n\n onPageFetch(event) {\n let submit = event.type == 'submit';\n let target = submit || event.target.tagName == 'A'\n ? event.target : event.target.closest('a');\n if(!target || target.hasAttribute('target'))\n return;\n\n let url = submit ? target.getAttribute('action') || ''\n : target.getAttribute('href');\n if(url===null || !(url === '' || url.startsWith('/') || url.startsWith('?')))\n return;\n\n let options = {};\n if(submit) {\n let formData = new FormData(event.target);\n if(target.method == 'get')\n url += '?' + (new URLSearchParams(formData)).toString();\n else {\n options['method'] = target.method;\n options['body'] = formData;\n }\n }\n this.appBuilder.fetch(url, options);\n event.preventDefault();\n event.stopPropagation();\n },\n\n Set: _model__WEBPACK_IMPORTED_MODULE_5__[\"Set\"], Sound: _sound__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n};\nwindow.Vue = vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"];\n\n\naircox.playerBuilder = new _app__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({el: '#player'});\naircox.playerBuilder.load({async:true});\naircox.appBuilder = new _app__WEBPACK_IMPORTED_MODULE_3__[\"default\"](x => window.aircox.appConfig);\naircox.appBuilder.load({async:true}).then(app => {\n //-- load page hooks\n window.addEventListener('click', event => aircox.onPageFetch(event), true);\n window.addEventListener('submit', event => aircox.onPageFetch(event), true);\n window.addEventListener('popstate', event => {\n if(event.state && event.state.content)\n aircox.appBuilder.loadFromState(event.state);\n });\n})\n\n\n\n\n//# sourceURL=webpack:///./assets/public/index.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/all.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/all.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_all_min_css__WEBPACK_IMPORTED_MODULE_1__);\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! @fortawesome/fontawesome-free/css/fontawesome.min.css */ \"./node_modules/@fortawesome/fontawesome-free/css/fontawesome.min.css\");\n/* harmony import */ var _fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2___default = /*#__PURE__*/__webpack_require__.n(_fortawesome_fontawesome_free_css_fontawesome_min_css__WEBPACK_IMPORTED_MODULE_2__);\n/* harmony import */ var _app__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./app */ \"./assets/public/app.js\");\n/* harmony import */ var _sound__WEBPACK_IMPORTED_MODULE_4__ = __webpack_require__(/*! ./sound */ \"./assets/public/sound.js\");\n/* harmony import */ var _model__WEBPACK_IMPORTED_MODULE_5__ = __webpack_require__(/*! ./model */ \"./assets/public/model.js\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6__ = __webpack_require__(/*! ./styles.scss */ \"./assets/public/styles.scss\");\n/* harmony import */ var _styles_scss__WEBPACK_IMPORTED_MODULE_6___default = /*#__PURE__*/__webpack_require__.n(_styles_scss__WEBPACK_IMPORTED_MODULE_6__);\n/* harmony import */ var _autocomplete__WEBPACK_IMPORTED_MODULE_7__ = __webpack_require__(/*! ./autocomplete */ \"./assets/public/autocomplete.vue\");\n/* harmony import */ var _episode__WEBPACK_IMPORTED_MODULE_8__ = __webpack_require__(/*! ./episode */ \"./assets/public/episode.vue\");\n/* harmony import */ var _player__WEBPACK_IMPORTED_MODULE_9__ = __webpack_require__(/*! ./player */ \"./assets/public/player.vue\");\n/* harmony import */ var _playlist__WEBPACK_IMPORTED_MODULE_10__ = __webpack_require__(/*! ./playlist */ \"./assets/public/playlist.vue\");\n/* harmony import */ var _soundItem__WEBPACK_IMPORTED_MODULE_11__ = __webpack_require__(/*! ./soundItem */ \"./assets/public/soundItem.vue\");\n/**\n * This module includes code available for both the public website and\n * administration interface)\n */\n//-- vendor\n\n\n\n\n\n\n//-- aircox\n\n\n\n\n\n\n\n\n\n\n\n\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-autocomplete', _autocomplete__WEBPACK_IMPORTED_MODULE_7__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-episode', _episode__WEBPACK_IMPORTED_MODULE_8__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-player', _player__WEBPACK_IMPORTED_MODULE_9__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-playlist', _playlist__WEBPACK_IMPORTED_MODULE_10__[\"default\"])\nvue__WEBPACK_IMPORTED_MODULE_0__[\"default\"].component('a-sound-item', _soundItem__WEBPACK_IMPORTED_MODULE_11__[\"default\"])\n\n\nwindow.aircox = {\n // main application\n appBuilder: null,\n appConfig: {},\n get app() { return this.appBuilder.app },\n\n // player application\n playerBuilder: null,\n get playerApp() { return this.playerBuilder && this.playerBuilder.app },\n get player() { return this.playerApp && this.playerApp.$refs.player },\n\n // Handle hot-reload (link click and form submits).\n onPageFetch(event) {\n let submit = event.type == 'submit';\n let target = submit || event.target.tagName == 'A'\n ? event.target : event.target.closest('a');\n if(!target || target.hasAttribute('target'))\n return;\n\n let url = submit ? target.getAttribute('action') || ''\n : target.getAttribute('href');\n if(url===null || !(url === '' || url.startsWith('/') || url.startsWith('?')))\n return;\n\n let options = {};\n if(submit) {\n let formData = new FormData(event.target);\n if(target.method == 'get')\n url += '?' + (new URLSearchParams(formData)).toString();\n else {\n options['method'] = target.method;\n options['body'] = formData;\n }\n }\n this.appBuilder.fetch(url, options).then(app => {\n this.appBuilder.historySave(url);\n });\n event.preventDefault();\n event.stopPropagation();\n },\n\n Set: _model__WEBPACK_IMPORTED_MODULE_5__[\"Set\"], Sound: _sound__WEBPACK_IMPORTED_MODULE_4__[\"default\"],\n};\nwindow.Vue = vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"];\n\n\naircox.playerBuilder = new _app__WEBPACK_IMPORTED_MODULE_3__[\"default\"]({el: '#player'});\naircox.playerBuilder.load({async:true});\naircox.appBuilder = new _app__WEBPACK_IMPORTED_MODULE_3__[\"default\"](x => window.aircox.appConfig);\naircox.appBuilder.load({async:true}).then(app => {\n aircox.appBuilder.historySave(document.location, true);\n\n //-- load page hooks\n window.addEventListener('click', event => aircox.onPageFetch(event), true);\n window.addEventListener('submit', event => aircox.onPageFetch(event), true);\n window.addEventListener('popstate', event => {\n if(event.state && event.state.content) {\n document.title = aircox.appBuilder.title;\n aircox.appBuilder.historyLoad(event.state);\n }\n });\n})\n\n\n\n\n//# sourceURL=webpack:///./assets/public/index.js?");
/***/ }),
@@ -315,11 +315,11 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) *
/*!********************************!*\
!*** ./assets/public/page.vue ***!
\********************************/
-/*! no static exports found */
+/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./page.vue?vue&type=template&id=a4303912& */ \"./assets/public/page.vue?vue&type=template&id=a4303912&\");\n/* harmony import */ var _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./page.vue?vue&type=script&lang=js& */ \"./assets/public/page.vue?vue&type=script&lang=js&\");\n/* harmony reexport (unknown) */ for(var __WEBPACK_IMPORT_KEY__ in _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__) if([\"default\"].indexOf(__WEBPACK_IMPORT_KEY__) < 0) (function(key) { __webpack_require__.d(__webpack_exports__, key, function() { return _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[key]; }) }(__WEBPACK_IMPORT_KEY__));\n/* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(\n _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__[\"render\"],\n _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/public/page.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/public/page.vue?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./page.vue?vue&type=template&id=a4303912& */ \"./assets/public/page.vue?vue&type=template&id=a4303912&\");\n/* harmony import */ var _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./page.vue?vue&type=script&lang=js& */ \"./assets/public/page.vue?vue&type=script&lang=js&\");\n/* empty/unused harmony star reexport *//* harmony import */ var _node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../../node_modules/vue-loader/lib/runtime/componentNormalizer.js */ \"./node_modules/vue-loader/lib/runtime/componentNormalizer.js\");\n\n\n\n\n\n/* normalize component */\n\nvar component = Object(_node_modules_vue_loader_lib_runtime_componentNormalizer_js__WEBPACK_IMPORTED_MODULE_2__[\"default\"])(\n _page_vue_vue_type_script_lang_js___WEBPACK_IMPORTED_MODULE_1__[\"default\"],\n _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__[\"render\"],\n _page_vue_vue_type_template_id_a4303912___WEBPACK_IMPORTED_MODULE_0__[\"staticRenderFns\"],\n false,\n null,\n null,\n null\n \n)\n\n/* hot reload */\nif (false) { var api; }\ncomponent.options.__file = \"assets/public/page.vue\"\n/* harmony default export */ __webpack_exports__[\"default\"] = (component.exports);\n\n//# sourceURL=webpack:///./assets/public/page.vue?");
/***/ }),
@@ -327,7 +327,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _pag
/*!*********************************************************!*\
!*** ./assets/public/page.vue?vue&type=script&lang=js& ***!
\*********************************************************/
-/*! no static exports found */
+/*! exports provided: default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
diff --git a/aircox/static/aircox/streamer.js b/aircox/static/aircox/streamer.js
index 76193f5..a12d92d 100644
--- a/aircox/static/aircox/streamer.js
+++ b/aircox/static/aircox/streamer.js
@@ -163,7 +163,7 @@
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"defaultConfig\", function() { return defaultConfig; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return AppBuilder; });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n\n\nconst defaultConfig = {\n el: '#app',\n delimiters: ['[[', ']]'],\n\n computed: {\n player() { return window.aircox.player; },\n },\n}\n\n\nclass AppBuilder {\n constructor(config={}) {\n this._config = config;\n this.app = null;\n }\n\n get config() {\n let config = this._config instanceof Function ? this._config() : this._config;\n for(var k of new Set([...Object.keys(config || {}), ...Object.keys(defaultConfig)])) {\n if(!config[k] && defaultConfig[k])\n config[k] = defaultConfig[k]\n else if(config[k] instanceof Object)\n config[k] = {...defaultConfig[k], ...config[k]}\n }\n return config;\n }\n\n set config(value) {\n this._config = value;\n }\n\n destroy() {\n self.app && self.app.$destroy();\n self.app = null;\n }\n\n fetch(url, options) {\n return fetch(url, options).then(response => response.text())\n .then(content => {\n let doc = new DOMParser().parseFromString(content, 'text/html');\n let app = doc.getElementById('app');\n content = app ? app.innerHTML : content;\n return this.load({sync: true, content, title: doc.title, url })\n })\n }\n\n load({async=false,content=null, title=null, url=null}={}) {\n var self = this;\n return new Promise((resolve, reject) => {\n let func = () => {\n try {\n let config = self.config;\n const el = document.querySelector(config.el);\n if(!el)\n return reject(`Error: can't get element ${config.el}`)\n\n if(content)\n el.innerHTML = content\n if(title)\n document.title = title;\n if(url && content)\n history.pushState({ content: content, title: title }, '', url)\n\n this.app = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"](config);\n resolve(self.app)\n } catch(error) {\n self.destroy();\n reject(error)\n }};\n async ? window.addEventListener('load', func) : func();\n });\n }\n\n loadFromState(state) {\n return this.load({ content: state.content, title: state.title });\n }\n}\n\n\n\n\n//# sourceURL=webpack:///./assets/public/app.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"defaultConfig\", function() { return defaultConfig; });\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"default\", function() { return AppBuilder; });\n/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ \"./node_modules/vue/dist/vue.esm.browser.js\");\n\n\nconst defaultConfig = {\n el: '#app',\n delimiters: ['[[', ']]'],\n\n computed: {\n player() { return window.aircox.player; },\n },\n}\n\n\nclass AppBuilder {\n constructor(config={}) {\n this._config = config;\n this.title = null;\n this.app = null;\n }\n\n get config() {\n let config = this._config instanceof Function ? this._config() : this._config;\n for(var k of new Set([...Object.keys(config || {}), ...Object.keys(defaultConfig)])) {\n if(!config[k] && defaultConfig[k])\n config[k] = defaultConfig[k]\n else if(config[k] instanceof Object)\n config[k] = {...defaultConfig[k], ...config[k]}\n }\n return config;\n }\n\n set config(value) {\n this._config = value;\n }\n\n destroy() {\n self.app && self.app.$destroy();\n self.app = null;\n }\n\n fetch(url, options) {\n return fetch(url, options).then(response => response.text())\n .then(content => {\n let doc = new DOMParser().parseFromString(content, 'text/html');\n let app = doc.getElementById('app');\n content = app ? app.innerHTML : content;\n return this.load({sync: true, content, title: doc.title, url })\n })\n }\n\n load({async=false,content=null,title=null}={}) {\n var self = this;\n return new Promise((resolve, reject) => {\n let func = () => {\n try {\n let config = self.config;\n const el = document.querySelector(config.el);\n if(!el)\n return reject(`Error: can't get element ${config.el}`)\n\n if(content)\n el.innerHTML = content\n if(title)\n document.title = title;\n this.app = new vue__WEBPACK_IMPORTED_MODULE_0__[\"default\"](config);\n resolve(self.app)\n } catch(error) {\n self.destroy();\n reject(error)\n }};\n async ? window.addEventListener('load', func) : func();\n });\n }\n\n /// Save application state into browser history\n historySave(url,replace=false) {\n const el = document.querySelector(this.config.el);\n const state = {\n content: el.innerHTML,\n title: document.title,\n };\n\n if(replace)\n history.replaceState(state, '', url)\n else\n history.pushState(state, '', url)\n }\n\n /// Load application from browser history's state\n historyLoad(state) {\n return this.load({ content: state.content, title: state.title });\n }\n}\n\n\n\n\n//# sourceURL=webpack:///./assets/public/app.js?");
/***/ }),
diff --git a/aircox/templates/aircox/base.html b/aircox/templates/aircox/base.html
index 259e521..7bfe4ad 100644
--- a/aircox/templates/aircox/base.html
+++ b/aircox/templates/aircox/base.html
@@ -5,7 +5,6 @@ variables.
Usefull context:
- cover: image cover
- site: current website
-- has_filters: display filter bar (using block "filters")
- model: view model or displayed `object`'s
- sidebar_object_list: item to display in sidebar
- sidebar_url_name: url name sidebar item complete list
@@ -99,17 +98,6 @@ Usefull context: