work on home page, fix views & templates issues
This commit is contained in:
		
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							
										
											Binary file not shown.
										
									
								
							@ -19,7 +19,7 @@ __all__ = ['Episode', 'Diffusion', 'DiffusionQuerySet']
 | 
			
		||||
class Episode(Page):
 | 
			
		||||
    objects = ProgramChildQuerySet.as_manager()
 | 
			
		||||
    detail_url_name = 'episode-detail'
 | 
			
		||||
    item_template_name = 'aircox/episode_item.html'
 | 
			
		||||
    item_template_name = 'aircox/widgets/episode_item.html'
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def program(self):
 | 
			
		||||
@ -75,7 +75,9 @@ class DiffusionQuerySet(BaseRerunQuerySet):
 | 
			
		||||
    def today(self, today=None, order=True):
 | 
			
		||||
        """ Diffusions occuring today. """
 | 
			
		||||
        today = today or datetime.date.today()
 | 
			
		||||
        qs = self.filter(Q(start__date=today) | Q(end__date=today))
 | 
			
		||||
        start = tz.datetime.combine(today, datetime.time())
 | 
			
		||||
        end = tz.datetime.combine(today, datetime.time(23, 59, 59, 999))
 | 
			
		||||
        qs = self.filter(start__range = (start, end))
 | 
			
		||||
        return qs.order_by('start') if order else qs
 | 
			
		||||
 | 
			
		||||
    def at(self, date, order=True):
 | 
			
		||||
@ -90,9 +92,9 @@ class DiffusionQuerySet(BaseRerunQuerySet):
 | 
			
		||||
        """
 | 
			
		||||
        date = utils.date_or_default(date)
 | 
			
		||||
        if isinstance(date, tz.datetime):
 | 
			
		||||
            qs = self.filter(start__gte=date)
 | 
			
		||||
            qs = self.filter(Q(start__gte=date) | Q(end__gte=date))
 | 
			
		||||
        else:
 | 
			
		||||
            qs = self.filter(start__date__gte=date)
 | 
			
		||||
            qs = self.filter(Q(start__date__gte=date) | Q(end__date__gte=date))
 | 
			
		||||
        return qs.order_by('start')
 | 
			
		||||
 | 
			
		||||
    def before(self, date=None):
 | 
			
		||||
@ -157,7 +159,7 @@ class Diffusion(BaseRerun):
 | 
			
		||||
    #    help_text = _('use this input port'),
 | 
			
		||||
    # )
 | 
			
		||||
 | 
			
		||||
    item_template_name = 'aircox/diffusion_item.html'
 | 
			
		||||
    item_template_name = 'aircox/widgets/diffusion_item.html'
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        verbose_name = _('Diffusion')
 | 
			
		||||
@ -181,12 +183,10 @@ class Diffusion(BaseRerun):
 | 
			
		||||
        #    self.check_conflicts()
 | 
			
		||||
 | 
			
		||||
    def save_rerun(self):
 | 
			
		||||
        print('rerun save', self)
 | 
			
		||||
        self.episode = self.initial.episode
 | 
			
		||||
        self.program = self.episode.program
 | 
			
		||||
 | 
			
		||||
    def save_initial(self):
 | 
			
		||||
        print('initial save', self)
 | 
			
		||||
        self.program = self.episode.program
 | 
			
		||||
        if self.episode != self._initial['episode']:
 | 
			
		||||
            self.rerun_set.update(episode=self.episode, program=self.program)
 | 
			
		||||
@ -221,6 +221,13 @@ class Diffusion(BaseRerun):
 | 
			
		||||
 | 
			
		||||
        return tz.localtime(self.end, tz.get_current_timezone())
 | 
			
		||||
 | 
			
		||||
    @property
 | 
			
		||||
    def is_now(self):
 | 
			
		||||
        """ True if diffusion is currently running """
 | 
			
		||||
        now = tz.now()
 | 
			
		||||
        return self.type == self.TYPE_ON_AIR and \
 | 
			
		||||
            self.start <= now and self.end >= now
 | 
			
		||||
 | 
			
		||||
    # TODO: property?
 | 
			
		||||
    def is_live(self):
 | 
			
		||||
        """ True if Diffusion is live (False if there are sounds files). """
 | 
			
		||||
 | 
			
		||||
@ -271,21 +271,22 @@ class Log(models.Model):
 | 
			
		||||
                object_list += logs[:index]
 | 
			
		||||
                logs = logs[index:]
 | 
			
		||||
 | 
			
		||||
            # - last log while diff is running
 | 
			
		||||
            if logs[0].date > diff.start:
 | 
			
		||||
                object_list.append(logs[0])
 | 
			
		||||
            if len(logs):
 | 
			
		||||
                # FIXME
 | 
			
		||||
                # - last log while diff is running
 | 
			
		||||
                #if logs[0].date > diff.start:
 | 
			
		||||
                #    object_list.append(logs[0])
 | 
			
		||||
 | 
			
		||||
            # - skips logs while diff is running
 | 
			
		||||
            index = next((i for i, v in enumerate(logs)
 | 
			
		||||
                         if v.date < diff.start), len(logs))
 | 
			
		||||
            if index is not None and index > 0:
 | 
			
		||||
                logs = logs[index:]
 | 
			
		||||
                # - skips logs while diff is running
 | 
			
		||||
                index = next((i for i, v in enumerate(logs)
 | 
			
		||||
                             if v.date < diff.start), len(logs))
 | 
			
		||||
                if index is not None and index > 0:
 | 
			
		||||
                    logs = logs[index:]
 | 
			
		||||
 | 
			
		||||
            # - add diff
 | 
			
		||||
            object_list.append(diff)
 | 
			
		||||
 | 
			
		||||
        return object_list
 | 
			
		||||
 | 
			
		||||
        return object_list if count is None else object_list[:count]
 | 
			
		||||
 | 
			
		||||
    def print(self):
 | 
			
		||||
        r = []
 | 
			
		||||
 | 
			
		||||
@ -92,7 +92,7 @@ class Page(models.Model):
 | 
			
		||||
    objects = PageQuerySet.as_manager()
 | 
			
		||||
 | 
			
		||||
    detail_url_name = None
 | 
			
		||||
    item_template_name = 'aircox/page_item.html'
 | 
			
		||||
    item_template_name = 'aircox/widgets/page_item.html'
 | 
			
		||||
 | 
			
		||||
    def __str__(self):
 | 
			
		||||
        return '{}'.format(self.title or self.pk)
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,3 @@
 | 
			
		||||
.navbar {
 | 
			
		||||
  box-shadow: 0em 0em 0.6em rgba(0, 0, 0, 0.4); }
 | 
			
		||||
 | 
			
		||||
.navbar .navbar-brand {
 | 
			
		||||
  padding-right: 1em; }
 | 
			
		||||
 | 
			
		||||
@ -7211,6 +7208,28 @@ a.navbar-item.is-active {
 | 
			
		||||
  margin: 0em;
 | 
			
		||||
  padding: 0em; }
 | 
			
		||||
 | 
			
		||||
.card .title {
 | 
			
		||||
  padding: 0.2em;
 | 
			
		||||
  font-size: 1.25rem;
 | 
			
		||||
  font-weight: 500; }
 | 
			
		||||
  .card .title a {
 | 
			
		||||
    color: #363636; }
 | 
			
		||||
 | 
			
		||||
.card.is-primary {
 | 
			
		||||
  box-shadow: 0em 0em 0.5em #0a0a0a; }
 | 
			
		||||
 | 
			
		||||
.card-super-title {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  z-index: 1000;
 | 
			
		||||
  font-size: 1.2em;
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
  padding: 0.2em;
 | 
			
		||||
  top: 1em;
 | 
			
		||||
  background-color: white; }
 | 
			
		||||
  .card-super-title .fas {
 | 
			
		||||
    padding: 0.1em;
 | 
			
		||||
    font-size: 0.8em; }
 | 
			
		||||
 | 
			
		||||
.filters {
 | 
			
		||||
  margin: 1em 0em;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
@ -7223,16 +7242,6 @@ a.navbar-item.is-active {
 | 
			
		||||
    color: #7a7a7a;
 | 
			
		||||
    font-weight: 300; }
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
.navbar-brand img {
 | 
			
		||||
    min-height: 6em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar-menu .navbar-item:not(:last-child) {
 | 
			
		||||
    border-right: 1px $grey solid;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
/** page **/
 | 
			
		||||
.page > .cover {
 | 
			
		||||
  float: right;
 | 
			
		||||
  max-width: 45%; }
 | 
			
		||||
@ -7247,26 +7256,23 @@ a.navbar-item.is-active {
 | 
			
		||||
.page p {
 | 
			
		||||
  padding: 0.4em 0em; }
 | 
			
		||||
 | 
			
		||||
section > .toolbar {
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.05);
 | 
			
		||||
  padding: 1em;
 | 
			
		||||
  margin-bottom: 1.5em; }
 | 
			
		||||
 | 
			
		||||
main .cover {
 | 
			
		||||
  margin: 1em 0em;
 | 
			
		||||
  border: 0.2em black solid; }
 | 
			
		||||
 | 
			
		||||
main .small-cover {
 | 
			
		||||
  width: 10em; }
 | 
			
		||||
 | 
			
		||||
aside .small-cover {
 | 
			
		||||
  width: 4em; }
 | 
			
		||||
 | 
			
		||||
aside .media .subtitle {
 | 
			
		||||
  font-size: 1em; }
 | 
			
		||||
 | 
			
		||||
aside .media .content {
 | 
			
		||||
  display: none; }
 | 
			
		||||
.media.item .headline {
 | 
			
		||||
  line-height: 1.2em;
 | 
			
		||||
  max-height: calc(1.2em * 3);
 | 
			
		||||
  overflow: hidden; }
 | 
			
		||||
  .media.item .headline + .headline-overflow {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 2em;
 | 
			
		||||
    margin-top: -2em; }
 | 
			
		||||
  .media.item .headline + .headline-overflow:before {
 | 
			
		||||
    content: '';
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    background: linear-gradient(transparent 1em, whitesmoke); }
 | 
			
		||||
 | 
			
		||||
.player {
 | 
			
		||||
  box-shadow: 0em 1.5em 2.5em rgba(0, 0, 0, 0.6); }
 | 
			
		||||
@ -7287,3 +7293,37 @@ aside .media .content {
 | 
			
		||||
  .player .title {
 | 
			
		||||
    margin: 0em; }
 | 
			
		||||
 | 
			
		||||
.media .subtitle {
 | 
			
		||||
  margin-bottom: 0.4em; }
 | 
			
		||||
 | 
			
		||||
.media .media-content .headline {
 | 
			
		||||
  font-size: 1em;
 | 
			
		||||
  font-weight: 400; }
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
  background-color: whitesmoke; }
 | 
			
		||||
 | 
			
		||||
section > .toolbar {
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.05);
 | 
			
		||||
  padding: 1em;
 | 
			
		||||
  margin-bottom: 1.5em; }
 | 
			
		||||
 | 
			
		||||
main .cover {
 | 
			
		||||
  margin: 1em 0em;
 | 
			
		||||
  border: 0.2em black solid; }
 | 
			
		||||
 | 
			
		||||
main .small-cover {
 | 
			
		||||
  width: 10em; }
 | 
			
		||||
 | 
			
		||||
aside > section {
 | 
			
		||||
  margin-bottom: 2em; }
 | 
			
		||||
 | 
			
		||||
aside .cover {
 | 
			
		||||
  margin-bottom: 2em; }
 | 
			
		||||
 | 
			
		||||
aside .small-cover {
 | 
			
		||||
  width: 4em; }
 | 
			
		||||
 | 
			
		||||
aside .media .subtitle {
 | 
			
		||||
  font-size: 1em; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -305,7 +305,7 @@ eval("// extracted by mini-css-extract-plugin\n\n//# sourceURL=webpack:///./asse
 | 
			
		||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
 | 
			
		||||
 | 
			
		||||
"use strict";
 | 
			
		||||
eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n\n\nconst splitReg = new RegExp(`,\\s*`, 'g');\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n    data() {\n        return {\n            counts: {},\n        }\n    },\n\n    methods: {\n        update() {\n            const items = this.$el.querySelectorAll('input[name=\"data\"]:checked')\n            const counts = {};\n\n            console.log(items)\n            for(var item of items)\n                if(item.value)\n                    for(var tag of item.value.split(splitReg))\n                        counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;\n            this.counts = counts;\n        }\n    },\n\n    mounted() {\n        this.$refs.form.addEventListener('change', () => this.update())\n        this.update()\n    }\n});\n\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?./node_modules/vue-loader/lib??vue-loader-options");
 | 
			
		||||
eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n\n\nconst splitReg = new RegExp(`,\\s*`, 'g');\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n    data() {\n        return {\n            counts: {},\n        }\n    },\n\n    methods: {\n        update() {\n            const items = this.$el.querySelectorAll('input[name=\"data\"]:checked')\n            const counts = {};\n\n            console.log(items)\n            for(var item of items)\n                if(item.value)\n                    for(var tag of item.value.split(splitReg))\n                        counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;\n            this.counts = counts;\n        },\n\n        onclick(event) {\n            // TODO: row click => check checkbox\n        }\n    },\n\n    mounted() {\n        this.$refs.form.addEventListener('change', () => this.update())\n        this.update()\n    }\n});\n\n\n//# sourceURL=webpack:///./assets/admin/statistics.vue?./node_modules/vue-loader/lib??vue-loader-options");
 | 
			
		||||
 | 
			
		||||
/***/ }),
 | 
			
		||||
 | 
			
		||||
@ -317,7 +317,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n//\n//\n//\n//\n//\n//\n\n\nc
 | 
			
		||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
 | 
			
		||||
 | 
			
		||||
"use strict";
 | 
			
		||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n    paused: 0,\n    playing: 1,\n    loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n    data() {\n        return {\n            state: State.paused,\n            liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n        }\n    },\n\n    props: {\n        buttonTitle: String,\n        liveInfoUrl: String,\n        liveInfoTimeout: { type: Number, default: 5},\n        src: String,\n    },\n\n    computed: {\n        paused() { return this.state == State.paused; },\n        playing() { return this.state == State.playing; },\n        loading() { return this.state == State.loading; },\n\n        onAir() {\n            return this.liveInfo.items && this.liveInfo.items[0];\n        },\n\n        buttonStyle() {\n            if(!this.onAir)\n                return;\n            return { backgroundImage: `url(${this.onAir.cover})` }\n        }\n    },\n\n    methods: {\n        load(src) {\n            const audio = this.$refs.audio;\n            audio.src = src;\n            audio.load()\n        },\n\n        play(src) {\n            if(src)\n                this.load(src);\n            this.$refs.audio.play().catch(e => console.error(e))\n        },\n\n        pause() {\n            this.$refs.audio.pause()\n        },\n\n        toggle() {\n            if(this.paused)\n                this.play()\n            else\n                this.pause()\n        },\n\n        onChange(event) {\n            const audio = this.$refs.audio;\n            this.state = audio.paused ? State.paused : State.playing;\n        },\n    },\n\n    mounted() {\n        this.liveInfo.refresh()\n    },\n\n    destroyed() {\n        this.liveInfo.drop()\n    },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
 | 
			
		||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n    paused: 0,\n    playing: 1,\n    loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n    data() {\n        return {\n            state: State.paused,\n            liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n        }\n    },\n\n    props: {\n        buttonTitle: String,\n        liveInfoUrl: String,\n        liveInfoTimeout: { type: Number, default: 5},\n        src: String,\n    },\n\n    computed: {\n        paused() { return this.state == State.paused; },\n        playing() { return this.state == State.playing; },\n        loading() { return this.state == State.loading; },\n\n        onAir() {\n            return this.liveInfo.items && this.liveInfo.items[0];\n        },\n\n        buttonStyle() {\n            if(!this.onAir)\n                return;\n            return { backgroundImage: `url(${this.onAir.cover})` }\n        }\n    },\n\n    methods: {\n        load(src) {\n            const audio = this.$refs.audio;\n            audio.src = src;\n            audio.load()\n        },\n\n        play(src) {\n            if(src)\n                this.load(src);\n            this.$refs.audio.play().catch(e => console.error(e))\n        },\n\n        pause() {\n            this.$refs.audio.pause()\n        },\n\n        toggle() {\n            console.log('tooogle', this.paused, '-', this.$refs.audio.src)\n            if(this.paused)\n                this.play()\n            else\n                this.pause()\n        },\n\n        onChange(event) {\n            const audio = this.$refs.audio;\n            this.state = audio.paused ? State.paused : State.playing;\n        },\n    },\n\n    mounted() {\n        this.liveInfo.refresh()\n    },\n\n    destroyed() {\n        this.liveInfo.drop()\n    },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
 | 
			
		||||
 | 
			
		||||
/***/ }),
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -7190,6 +7190,28 @@ a.navbar-item.is-active {
 | 
			
		||||
  margin: 0em;
 | 
			
		||||
  padding: 0em; }
 | 
			
		||||
 | 
			
		||||
.card .title {
 | 
			
		||||
  padding: 0.2em;
 | 
			
		||||
  font-size: 1.25rem;
 | 
			
		||||
  font-weight: 500; }
 | 
			
		||||
  .card .title a {
 | 
			
		||||
    color: #363636; }
 | 
			
		||||
 | 
			
		||||
.card.is-primary {
 | 
			
		||||
  box-shadow: 0em 0em 0.5em #0a0a0a; }
 | 
			
		||||
 | 
			
		||||
.card-super-title {
 | 
			
		||||
  position: absolute;
 | 
			
		||||
  z-index: 1000;
 | 
			
		||||
  font-size: 1.2em;
 | 
			
		||||
  font-weight: 700;
 | 
			
		||||
  padding: 0.2em;
 | 
			
		||||
  top: 1em;
 | 
			
		||||
  background-color: white; }
 | 
			
		||||
  .card-super-title .fas {
 | 
			
		||||
    padding: 0.1em;
 | 
			
		||||
    font-size: 0.8em; }
 | 
			
		||||
 | 
			
		||||
.filters {
 | 
			
		||||
  margin: 1em 0em;
 | 
			
		||||
  background-color: transparent;
 | 
			
		||||
@ -7202,16 +7224,6 @@ a.navbar-item.is-active {
 | 
			
		||||
    color: #7a7a7a;
 | 
			
		||||
    font-weight: 300; }
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
.navbar-brand img {
 | 
			
		||||
    min-height: 6em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar-menu .navbar-item:not(:last-child) {
 | 
			
		||||
    border-right: 1px $grey solid;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
/** page **/
 | 
			
		||||
.page > .cover {
 | 
			
		||||
  float: right;
 | 
			
		||||
  max-width: 45%; }
 | 
			
		||||
@ -7226,26 +7238,23 @@ a.navbar-item.is-active {
 | 
			
		||||
.page p {
 | 
			
		||||
  padding: 0.4em 0em; }
 | 
			
		||||
 | 
			
		||||
section > .toolbar {
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.05);
 | 
			
		||||
  padding: 1em;
 | 
			
		||||
  margin-bottom: 1.5em; }
 | 
			
		||||
 | 
			
		||||
main .cover {
 | 
			
		||||
  margin: 1em 0em;
 | 
			
		||||
  border: 0.2em black solid; }
 | 
			
		||||
 | 
			
		||||
main .small-cover {
 | 
			
		||||
  width: 10em; }
 | 
			
		||||
 | 
			
		||||
aside .small-cover {
 | 
			
		||||
  width: 4em; }
 | 
			
		||||
 | 
			
		||||
aside .media .subtitle {
 | 
			
		||||
  font-size: 1em; }
 | 
			
		||||
 | 
			
		||||
aside .media .content {
 | 
			
		||||
  display: none; }
 | 
			
		||||
.media.item .headline {
 | 
			
		||||
  line-height: 1.2em;
 | 
			
		||||
  max-height: calc(1.2em * 3);
 | 
			
		||||
  overflow: hidden; }
 | 
			
		||||
  .media.item .headline + .headline-overflow {
 | 
			
		||||
    position: relative;
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 2em;
 | 
			
		||||
    margin-top: -2em; }
 | 
			
		||||
  .media.item .headline + .headline-overflow:before {
 | 
			
		||||
    content: '';
 | 
			
		||||
    width: 100%;
 | 
			
		||||
    height: 100%;
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    left: 0;
 | 
			
		||||
    bottom: 0;
 | 
			
		||||
    background: linear-gradient(transparent 1em, whitesmoke); }
 | 
			
		||||
 | 
			
		||||
.player {
 | 
			
		||||
  box-shadow: 0em 1.5em 2.5em rgba(0, 0, 0, 0.6); }
 | 
			
		||||
@ -7266,3 +7275,37 @@ aside .media .content {
 | 
			
		||||
  .player .title {
 | 
			
		||||
    margin: 0em; }
 | 
			
		||||
 | 
			
		||||
.media .subtitle {
 | 
			
		||||
  margin-bottom: 0.4em; }
 | 
			
		||||
 | 
			
		||||
.media .media-content .headline {
 | 
			
		||||
  font-size: 1em;
 | 
			
		||||
  font-weight: 400; }
 | 
			
		||||
 | 
			
		||||
body {
 | 
			
		||||
  background-color: whitesmoke; }
 | 
			
		||||
 | 
			
		||||
section > .toolbar {
 | 
			
		||||
  background-color: rgba(0, 0, 0, 0.05);
 | 
			
		||||
  padding: 1em;
 | 
			
		||||
  margin-bottom: 1.5em; }
 | 
			
		||||
 | 
			
		||||
main .cover {
 | 
			
		||||
  margin: 1em 0em;
 | 
			
		||||
  border: 0.2em black solid; }
 | 
			
		||||
 | 
			
		||||
main .small-cover {
 | 
			
		||||
  width: 10em; }
 | 
			
		||||
 | 
			
		||||
aside > section {
 | 
			
		||||
  margin-bottom: 2em; }
 | 
			
		||||
 | 
			
		||||
aside .cover {
 | 
			
		||||
  margin-bottom: 2em; }
 | 
			
		||||
 | 
			
		||||
aside .small-cover {
 | 
			
		||||
  width: 4em; }
 | 
			
		||||
 | 
			
		||||
aside .media .subtitle {
 | 
			
		||||
  font-size: 1em; }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -246,7 +246,7 @@ eval("// extracted by mini-css-extract-plugin\n\n//# sourceURL=webpack:///./asse
 | 
			
		||||
/***/ (function(module, __webpack_exports__, __webpack_require__) {
 | 
			
		||||
 | 
			
		||||
"use strict";
 | 
			
		||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n    paused: 0,\n    playing: 1,\n    loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n    data() {\n        return {\n            state: State.paused,\n            liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n        }\n    },\n\n    props: {\n        buttonTitle: String,\n        liveInfoUrl: String,\n        liveInfoTimeout: { type: Number, default: 5},\n        src: String,\n    },\n\n    computed: {\n        paused() { return this.state == State.paused; },\n        playing() { return this.state == State.playing; },\n        loading() { return this.state == State.loading; },\n\n        onAir() {\n            return this.liveInfo.items && this.liveInfo.items[0];\n        },\n\n        buttonStyle() {\n            if(!this.onAir)\n                return;\n            return { backgroundImage: `url(${this.onAir.cover})` }\n        }\n    },\n\n    methods: {\n        load(src) {\n            const audio = this.$refs.audio;\n            audio.src = src;\n            audio.load()\n        },\n\n        play(src) {\n            if(src)\n                this.load(src);\n            this.$refs.audio.play().catch(e => console.error(e))\n        },\n\n        pause() {\n            this.$refs.audio.pause()\n        },\n\n        toggle() {\n            if(this.paused)\n                this.play()\n            else\n                this.pause()\n        },\n\n        onChange(event) {\n            const audio = this.$refs.audio;\n            this.state = audio.paused ? State.paused : State.playing;\n        },\n    },\n\n    mounted() {\n        this.liveInfo.refresh()\n    },\n\n    destroyed() {\n        this.liveInfo.drop()\n    },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
 | 
			
		||||
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"State\", function() { return State; });\n/* harmony import */ var _liveInfo__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./liveInfo */ \"./assets/public/liveInfo.js\");\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n//\n\n\n\nconst State = {\n    paused: 0,\n    playing: 1,\n    loading: 2,\n}\n\n/* harmony default export */ __webpack_exports__[\"default\"] = ({\n    data() {\n        return {\n            state: State.paused,\n            liveInfo: new _liveInfo__WEBPACK_IMPORTED_MODULE_0__[\"default\"](this.liveInfoUrl, this.liveInfoTimeout),\n        }\n    },\n\n    props: {\n        buttonTitle: String,\n        liveInfoUrl: String,\n        liveInfoTimeout: { type: Number, default: 5},\n        src: String,\n    },\n\n    computed: {\n        paused() { return this.state == State.paused; },\n        playing() { return this.state == State.playing; },\n        loading() { return this.state == State.loading; },\n\n        onAir() {\n            return this.liveInfo.items && this.liveInfo.items[0];\n        },\n\n        buttonStyle() {\n            if(!this.onAir)\n                return;\n            return { backgroundImage: `url(${this.onAir.cover})` }\n        }\n    },\n\n    methods: {\n        load(src) {\n            const audio = this.$refs.audio;\n            audio.src = src;\n            audio.load()\n        },\n\n        play(src) {\n            if(src)\n                this.load(src);\n            this.$refs.audio.play().catch(e => console.error(e))\n        },\n\n        pause() {\n            this.$refs.audio.pause()\n        },\n\n        toggle() {\n            console.log('tooogle', this.paused, '-', this.$refs.audio.src)\n            if(this.paused)\n                this.play()\n            else\n                this.pause()\n        },\n\n        onChange(event) {\n            const audio = this.$refs.audio;\n            this.state = audio.paused ? State.paused : State.playing;\n        },\n    },\n\n    mounted() {\n        this.liveInfo.refresh()\n    },\n\n    destroyed() {\n        this.liveInfo.drop()\n    },\n});\n\n\n\n//# sourceURL=webpack:///./assets/public/player.vue?./node_modules/vue-loader/lib??vue-loader-options");
 | 
			
		||||
 | 
			
		||||
/***/ }),
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -3,8 +3,14 @@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block content %}{{ block.super }}
 | 
			
		||||
<div id="app">
 | 
			
		||||
 | 
			
		||||
{# TODO: date subtitle #}
 | 
			
		||||
<div class="columns">
 | 
			
		||||
<nav class="navbar" role="menu">
 | 
			
		||||
    {% with "admin:tools-stats" as url_name %}
 | 
			
		||||
    {% include "aircox/widgets/dates_menu.html" %}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
<a-statistics class="column">
 | 
			
		||||
<template v-slot:default="{counts}">
 | 
			
		||||
@ -23,13 +29,12 @@
 | 
			
		||||
        {% for track in tracks %}
 | 
			
		||||
        <tr>
 | 
			
		||||
            {% if forloop.first %}
 | 
			
		||||
            <td rowspan="{{ tracks|length }}">{{ object.start|time:"H:i" }}</td>
 | 
			
		||||
            <td rowspan="{{ tracks|length }}">{{ object.start|time:"H:i" }} {% if object|is_diffusion %} - {{ object.end|time:"H:i" }}{% endif %}</td>
 | 
			
		||||
            <td rowspan="{{ tracks|length }}">{{ object.episode|default:"" }}</td>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
 | 
			
		||||
            {% if not object|is_diffusion %}
 | 
			
		||||
            {% with track as object %}
 | 
			
		||||
            <td>{% include "aircox/track_item.html" %}</td>
 | 
			
		||||
            <td>{% include "aircox/widgets/track_item.html" %}</td>
 | 
			
		||||
            {% endwith %}
 | 
			
		||||
            {% with track.tags.all|join:', ' as tags %}
 | 
			
		||||
            <td>
 | 
			
		||||
@ -41,10 +46,17 @@
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </td>
 | 
			
		||||
            {% endwith %}
 | 
			
		||||
        {% else %}
 | 
			
		||||
        </tr>
 | 
			
		||||
        {% empty %}
 | 
			
		||||
        {% if object|is_diffusion %}
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>{{ object.start|time:"H:i" }} - {{ object.end|time:"H:i" }}</td>
 | 
			
		||||
            <td>{{ object.episode|default:"" }}</td>
 | 
			
		||||
            <td></td>
 | 
			
		||||
            <td></td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        {% endif %}
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
        <tr>
 | 
			
		||||
        {% endwith %}
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
        </tbody>
 | 
			
		||||
@ -65,14 +77,6 @@
 | 
			
		||||
</template>
 | 
			
		||||
</a-statistics>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
<nav class="column menu is-one-fifth-desktop" role="menu">
 | 
			
		||||
    {% with "admin:tools-stats" as url_name %}
 | 
			
		||||
    {% include "aircox/widgets/dates_menu.html" %}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
</nav>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -29,11 +29,10 @@
 | 
			
		||||
  data-admin-utc-offset="{% now "Z" %}">
 | 
			
		||||
 | 
			
		||||
<!-- Container -->
 | 
			
		||||
<div id="app">
 | 
			
		||||
 | 
			
		||||
<div>
 | 
			
		||||
    {% if not is_popup %}
 | 
			
		||||
    <!-- Header -->
 | 
			
		||||
    <nav class="navbar is-dark">
 | 
			
		||||
    <nav class="navbar is-dark has-shadow">
 | 
			
		||||
        <div class="navbar-brand">
 | 
			
		||||
        {% block branding %}{% endblock %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
@ -37,7 +37,7 @@
 | 
			
		||||
{% block coltype %}flex{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block content %}
 | 
			
		||||
  <div id="content-main">
 | 
			
		||||
<div id="content-main">
 | 
			
		||||
    {% block object-tools %}
 | 
			
		||||
        <ul class="object-tools">
 | 
			
		||||
          {% block object-tools-items %}
 | 
			
		||||
@ -74,16 +74,16 @@
 | 
			
		||||
          {% block date_hierarchy %}{% if cl.date_hierarchy %}{% date_hierarchy cl %}{% endif %}{% endblock %}
 | 
			
		||||
 | 
			
		||||
          {% block filters %}
 | 
			
		||||
              {% if cl.has_filters %}
 | 
			
		||||
                  <div id="changelist-filter">
 | 
			
		||||
                    <h2>{% trans 'Filter' %}</h2>
 | 
			
		||||
                    {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
 | 
			
		||||
                  </div>
 | 
			
		||||
              {% endif %}
 | 
			
		||||
          {% if cl.has_filters %}
 | 
			
		||||
              <div id="changelist-filter">
 | 
			
		||||
                <h2>{% trans 'Filter' %}</h2>
 | 
			
		||||
                {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
 | 
			
		||||
              </div>
 | 
			
		||||
          {% endif %}
 | 
			
		||||
          {% endblock %}
 | 
			
		||||
      </div>
 | 
			
		||||
    </div>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    </div>
 | 
			
		||||
  </div>
 | 
			
		||||
</div>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
@ -4,12 +4,12 @@
 | 
			
		||||
{% block sidebar %}
 | 
			
		||||
{{ block.super }}
 | 
			
		||||
 | 
			
		||||
{% if sidebar_items %}
 | 
			
		||||
{% if sidebar_object_list %}
 | 
			
		||||
<section>
 | 
			
		||||
    <h4 class="title is-4">{% trans "Latest news" %}</h4>
 | 
			
		||||
 | 
			
		||||
    {% for object in sidebar_items %}
 | 
			
		||||
    {% include "aircox/page_item.html" %}
 | 
			
		||||
    {% for object in sidebar_object_list %}
 | 
			
		||||
    {% include "aircox/widgets/page_item.html" %}
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
 | 
			
		||||
    <br>
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,29 @@
 | 
			
		||||
{% load static i18n thumbnail aircox %}
 | 
			
		||||
{% comment %}
 | 
			
		||||
Context:
 | 
			
		||||
- cover: image cover
 | 
			
		||||
- site: current website
 | 
			
		||||
- has_filters: display filter bar (using block "filters")
 | 
			
		||||
- sidebar_object_list: item to display in sidebar
 | 
			
		||||
- sidebar_url_name: url name sidebar item complete list
 | 
			
		||||
- sidebar_url_parent: parent page for sidebar items complete list
 | 
			
		||||
 | 
			
		||||
Blocks:
 | 
			
		||||
- assets
 | 
			
		||||
- head_title
 | 
			
		||||
- head_extra
 | 
			
		||||
- top_nav
 | 
			
		||||
- header:
 | 
			
		||||
    - title
 | 
			
		||||
    - subtitle
 | 
			
		||||
    - header_meta
 | 
			
		||||
- main:
 | 
			
		||||
    - filters
 | 
			
		||||
- cover
 | 
			
		||||
- sidebar:
 | 
			
		||||
    - sidebar_title
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
{% load static i18n thumbnail aircox %}
 | 
			
		||||
 | 
			
		||||
<html>
 | 
			
		||||
    <head>
 | 
			
		||||
        <meta charset="utf-8" />
 | 
			
		||||
@ -72,14 +91,14 @@ Context:
 | 
			
		||||
                            {% endblock %}
 | 
			
		||||
                        </header>
 | 
			
		||||
 | 
			
		||||
                        {% if has_filters %}
 | 
			
		||||
                        <nav class="navbar filters"
 | 
			
		||||
                            aria-label="{% trans "list filters" %}">
 | 
			
		||||
                        {% block filters %}{% endblock %}
 | 
			
		||||
                        </nav>
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
 | 
			
		||||
                        {% block main %}{% endblock main %}
 | 
			
		||||
                        {% block main %}
 | 
			
		||||
                            {% if has_filters %}
 | 
			
		||||
                            <nav class="navbar filters"
 | 
			
		||||
                                aria-label="{% trans "list filters" %}">
 | 
			
		||||
                            {% block filters %}{% endblock %}
 | 
			
		||||
                            </nav>
 | 
			
		||||
                            {% endif %}
 | 
			
		||||
                        {% endblock main %}
 | 
			
		||||
                    </main>
 | 
			
		||||
 | 
			
		||||
                    {% if has_sidebar %}
 | 
			
		||||
@ -92,28 +111,18 @@ Context:
 | 
			
		||||
                        {% endblock %}
 | 
			
		||||
 | 
			
		||||
                        {% block sidebar %}
 | 
			
		||||
                        {% if sidebar_items %} 
 | 
			
		||||
                        {% if sidebar_object_list %}
 | 
			
		||||
                        {% with object_list=sidebar_object_list %}
 | 
			
		||||
                        {% with list_url=sidebar_list_url %}
 | 
			
		||||
                        {% with has_headline=False %}
 | 
			
		||||
                        <section>
 | 
			
		||||
                            <h4 class="title is-4">
 | 
			
		||||
                                {% block sidebar_title %}{% trans "Recently" %}{% endblock %}
 | 
			
		||||
                            </h4>
 | 
			
		||||
 | 
			
		||||
                        {% for object in sidebar_items %}
 | 
			
		||||
                        {% include "aircox/episode_item.html" %}
 | 
			
		||||
                        {% endfor %}
 | 
			
		||||
 | 
			
		||||
                        <br>
 | 
			
		||||
                        <nav class="pagination is-centered">
 | 
			
		||||
                            <ul class="pagination-list">
 | 
			
		||||
                                <li>
 | 
			
		||||
                                    <a {% if parent %}href="{% url "page-list" parent_slug=parent.slug %}"{% else %}href="{% url "page-list" %}"{% endif %}
 | 
			
		||||
                                        class="pagination-link"
 | 
			
		||||
                                        aria-label="{% trans "Show all program's diffusions" %}">
 | 
			
		||||
                                        {% trans "Show more" %}
 | 
			
		||||
                                    </a>
 | 
			
		||||
                                </li>
 | 
			
		||||
                            </ul>
 | 
			
		||||
                        </nav>
 | 
			
		||||
                            {% include "aircox/widgets/page_list.html" %}
 | 
			
		||||
                        {% endwith %}
 | 
			
		||||
                        {% endwith %}
 | 
			
		||||
                        {% endwith %}
 | 
			
		||||
                        {% endif %}
 | 
			
		||||
                        </section>
 | 
			
		||||
                        {% endblock %}
 | 
			
		||||
 | 
			
		||||
@ -16,7 +16,7 @@
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block main %}{{ block.super }}
 | 
			
		||||
{% with True as hide_schedule %}
 | 
			
		||||
{% with hide_schedule=True %}
 | 
			
		||||
<section role="list">
 | 
			
		||||
    <div id="timetable-{{ date|date:"Y-m-d" }}">
 | 
			
		||||
        {% for diffusion in object_list %}
 | 
			
		||||
@ -24,12 +24,12 @@
 | 
			
		||||
        <div class="columns {% if diffusion.start.date != date and diffusion.start.end <= date %}is-opacity-light{% endif %}">
 | 
			
		||||
            <div class="column is-one-fifth has-text-right">
 | 
			
		||||
                <time datetime="{{ diffusion.start|date:"c" }}">
 | 
			
		||||
                {{ diffusion.start|date:"d H:i" }} - {{ diffusion.end|date:"d H:i" }}
 | 
			
		||||
                {{ diffusion.start|date:"H:i" }} - {{ diffusion.end|date:"H:i" }}
 | 
			
		||||
                </time>
 | 
			
		||||
            </div>
 | 
			
		||||
            <div class="column">
 | 
			
		||||
                {% with diffusion.episode as object %}
 | 
			
		||||
                {% include "aircox/episode_item.html" %}
 | 
			
		||||
                {% include "aircox/widgets/episode_item.html" %}
 | 
			
		||||
                {% endwith %}
 | 
			
		||||
            </div>
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
@ -50,7 +50,7 @@
 | 
			
		||||
    <section class="column">
 | 
			
		||||
        <h4 class="title is-4">{% trans "Podcasts" %}</h4>
 | 
			
		||||
        {% for object in podcasts %}
 | 
			
		||||
        {% include "aircox/podcast_item.html" %}
 | 
			
		||||
        {% include "aircox/widgets/podcast_item.html" %}
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
    </section>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										83
									
								
								aircox/templates/aircox/home.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										83
									
								
								aircox/templates/aircox/home.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,83 @@
 | 
			
		||||
{% extends "aircox/page_list.html" %}
 | 
			
		||||
{% comment %}
 | 
			
		||||
Context:
 | 
			
		||||
- 
 | 
			
		||||
- 
 | 
			
		||||
 | 
			
		||||
TODO:
 | 
			
		||||
- sidebar:
 | 
			
		||||
    - logs
 | 
			
		||||
    - diffusions
 | 
			
		||||
- main:
 | 
			
		||||
    - focused
 | 
			
		||||
    - nav to 'publications' view
 | 
			
		||||
    - 
 | 
			
		||||
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
{% block head_title %}{% block title %}{{ station.name }}{% endblock %}{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block main %}
 | 
			
		||||
<div class="columns">
 | 
			
		||||
    {% with render_card=True %}
 | 
			
		||||
    {% for object in top_diffs %}
 | 
			
		||||
    {% with is_primary=object.is_now %}
 | 
			
		||||
    <div class="column is-relative">
 | 
			
		||||
        <h4 class="card-super-title">
 | 
			
		||||
            {% if is_primary %}
 | 
			
		||||
            <span class="fas fa-play"></span>
 | 
			
		||||
            {% trans "Currently" %}
 | 
			
		||||
            {% else %}{{ object.start|date:"H:i" }}{% endif %}
 | 
			
		||||
        </h4>
 | 
			
		||||
        {% include object.item_template_name %}
 | 
			
		||||
    </div>
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
</div>
 | 
			
		||||
 | 
			
		||||
<hr>
 | 
			
		||||
<h4 class="title is-4">{% trans "Last publications" %}</h4>
 | 
			
		||||
{{ block.super }}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block pagination %}
 | 
			
		||||
<ul class="pagination-list">
 | 
			
		||||
    <li>
 | 
			
		||||
        <a href="{% url "page-list" %}" class="pagination-link"
 | 
			
		||||
            aria-label="{% trans "Show all publication" %}">
 | 
			
		||||
            {% trans "More publications..." %}
 | 
			
		||||
        </a>
 | 
			
		||||
    </li>
 | 
			
		||||
</ul>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block sidebar %}
 | 
			
		||||
<section>
 | 
			
		||||
    <h4 class="title is-4">{% trans "Previously on air" %}</h4>
 | 
			
		||||
    {% with logs as object_list %}
 | 
			
		||||
    {% include "aircox/widgets/log_list.html" %}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
<section>
 | 
			
		||||
    <h4 class="title is-4">{% trans "Today" %}</h4>
 | 
			
		||||
    {% with hide_schedule=True %}
 | 
			
		||||
    {% with has_headline=False %}
 | 
			
		||||
    <table class="table is-fullwidth has-background-transparent">
 | 
			
		||||
    {% for object in sidebar_object_list %}
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td>{{ object.start|date:"H:i" }}</td>
 | 
			
		||||
        <td>{% include "aircox/widgets/diffusion_item.html" %}</td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
    </table>
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
</section>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -16,29 +16,10 @@
 | 
			
		||||
{% endwith %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block main %}
 | 
			
		||||
{% block main %}{{ block.super }}
 | 
			
		||||
<section>
 | 
			
		||||
    {# <h4 class="subtitle size-4">{{ date }}</h4> #}
 | 
			
		||||
    {% with True as hide_schedule %}
 | 
			
		||||
    <table class="table is-striped is-hoverable is-fullwidth">
 | 
			
		||||
        {% for object in object_list %}
 | 
			
		||||
        <tr>
 | 
			
		||||
            <td>
 | 
			
		||||
                {% if object|is_diffusion %}
 | 
			
		||||
                <time datetime="{{ object.start }}" title="{{ object.start }}">
 | 
			
		||||
                    {{ object.start|date:"H:i" }} - {{ object.end|date:"H:i" }}
 | 
			
		||||
                </time>
 | 
			
		||||
                {% else %}
 | 
			
		||||
                <time datetime="{{ object.date }}" title="{{ object.date }}">
 | 
			
		||||
                    {{ object.date|date:"H:i" }}
 | 
			
		||||
                </time>
 | 
			
		||||
                {% endif %}
 | 
			
		||||
            </td>
 | 
			
		||||
            <td>{% include "aircox/log_item.html" %}</td>
 | 
			
		||||
        </tr>
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
    </table>
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
    {% include "aircox/widgets/log_list.html" %}
 | 
			
		||||
</section>
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -56,21 +56,23 @@
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% block main %}
 | 
			
		||||
{% block main %}{{ block.super }}
 | 
			
		||||
<section role="list">
 | 
			
		||||
{% with has_headline=True %}
 | 
			
		||||
{% for object in object_list %}
 | 
			
		||||
{% block list_object %}
 | 
			
		||||
{% include object.item_template_name|default:item_template_name %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
{% endfor %}
 | 
			
		||||
{% endwith %}
 | 
			
		||||
</section>
 | 
			
		||||
 | 
			
		||||
{% if is_paginated %}
 | 
			
		||||
<hr>
 | 
			
		||||
 | 
			
		||||
{% update_query request.GET.copy page=None as GET %}
 | 
			
		||||
{% with GET.urlencode as GET %}
 | 
			
		||||
<nav class="pagination is-centered" role="pagination" aria-label="{% trans "pagination" %}">
 | 
			
		||||
    {% block pagination %}
 | 
			
		||||
    {% if page_obj.has_previous %}
 | 
			
		||||
    <a href="?{{ GET }}&page={{ page_obj.previous_page_number }}" class="pagination-previous">
 | 
			
		||||
    {% else %}
 | 
			
		||||
@ -93,6 +95,7 @@
 | 
			
		||||
        </li>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
    </ul>
 | 
			
		||||
    {% endblock %}
 | 
			
		||||
</nav>
 | 
			
		||||
{% endwith %}
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
@ -3,13 +3,7 @@
 | 
			
		||||
 | 
			
		||||
{% block sidebar_title %}
 | 
			
		||||
{% with program.title as program %}
 | 
			
		||||
{% blocktrans %} Recently on {{ program }}{% endblocktrans %}
 | 
			
		||||
{% endwith %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
{% block sidebar %}
 | 
			
		||||
{% with program as parent %}
 | 
			
		||||
{{ block.super }}
 | 
			
		||||
{% blocktrans %}Recently on {{ program }}{% endblocktrans %}
 | 
			
		||||
{% endwith %}
 | 
			
		||||
{% endblock %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -10,15 +10,14 @@
 | 
			
		||||
{% block content %}{{ block.super }}
 | 
			
		||||
 | 
			
		||||
<br>
 | 
			
		||||
 | 
			
		||||
{% with show_headline=False %}
 | 
			
		||||
{% with has_headline=False %}
 | 
			
		||||
<div class="columns is-desktop">
 | 
			
		||||
    {% if articles %}
 | 
			
		||||
    <section class="column">
 | 
			
		||||
        <h4 class="title is-4">{% trans "Articles" %}</h4>
 | 
			
		||||
 | 
			
		||||
        {% for object in articles %}
 | 
			
		||||
        {% include "aircox/page_item.html" %}
 | 
			
		||||
        {% include "aircox/widgets/page_item.html" %}
 | 
			
		||||
        {% endfor %}
 | 
			
		||||
 | 
			
		||||
        <br>
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ Context:
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
{% with object as diffusion %}
 | 
			
		||||
{% with object.episode as object %}
 | 
			
		||||
{% include "aircox/episode_item.html" %}
 | 
			
		||||
{% include "aircox/widgets/episode_item.html" %}
 | 
			
		||||
{% endwith %}
 | 
			
		||||
{% endwith %}
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
{% extends "aircox/page_item.html" %}
 | 
			
		||||
{% extends "aircox/widgets/page_item.html" %}
 | 
			
		||||
{% load i18n easy_thumbnails_tags aircox %}
 | 
			
		||||
 | 
			
		||||
{% comment %}
 | 
			
		||||
@ -11,11 +11,11 @@ for design review.
 | 
			
		||||
 | 
			
		||||
{% if object|is_diffusion %}
 | 
			
		||||
    {% with object as diffusion %}
 | 
			
		||||
    {% include "aircox/diffusion_item.html" %}
 | 
			
		||||
    {% include "aircox/widgets/diffusion_item.html" %}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
{% else %}
 | 
			
		||||
    {% with object.track as object %}
 | 
			
		||||
    {% include "aircox/track_item.html" %}
 | 
			
		||||
    {% include "aircox/widgets/track_item.html" %}
 | 
			
		||||
    {% endwith %}
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										29
									
								
								aircox/templates/aircox/widgets/log_list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								aircox/templates/aircox/widgets/log_list.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,29 @@
 | 
			
		||||
{% comment %}
 | 
			
		||||
Render list of logs (as widget).
 | 
			
		||||
 | 
			
		||||
Context:
 | 
			
		||||
- object_list: list of logs to display
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
{% load aircox %}
 | 
			
		||||
 | 
			
		||||
{% with True as hide_schedule %}
 | 
			
		||||
<table class="table is-striped is-hoverable is-fullwidth" role="list">
 | 
			
		||||
    {% for object in object_list %}
 | 
			
		||||
    <tr>
 | 
			
		||||
        <td>
 | 
			
		||||
            {% if object|is_diffusion %}
 | 
			
		||||
            <time datetime="{{ object.start }}" title="{{ object.start }}">
 | 
			
		||||
                {{ object.start|date:"H:i" }} - {{ object.end|date:"H:i" }}
 | 
			
		||||
            </time>
 | 
			
		||||
            {% else %}
 | 
			
		||||
            <time datetime="{{ object.date }}" title="{{ object.date }}">
 | 
			
		||||
                {{ object.date|date:"H:i" }}
 | 
			
		||||
            </time>
 | 
			
		||||
            {% endif %}
 | 
			
		||||
        </td>
 | 
			
		||||
        <td>{% include "aircox/widgets/log_item.html" %}</td>
 | 
			
		||||
    </tr>
 | 
			
		||||
    {% endfor %}
 | 
			
		||||
</table>
 | 
			
		||||
{% endwith %}
 | 
			
		||||
 | 
			
		||||
@ -1,15 +1,36 @@
 | 
			
		||||
{% load i18n easy_thumbnails_tags aircox %}
 | 
			
		||||
{% comment %}
 | 
			
		||||
Context variables:
 | 
			
		||||
- object: the actual diffusion
 | 
			
		||||
- show_headline: if True, display headline
 | 
			
		||||
- object: the object to render
 | 
			
		||||
- render_card: render as card
 | 
			
		||||
- is-primary: render as primary
 | 
			
		||||
- has_headline (=False): if True, display headline
 | 
			
		||||
- has_cover (=True): hide page cover
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
 | 
			
		||||
<article class="media">
 | 
			
		||||
{% if render_card %}
 | 
			
		||||
<article class="card {% if is_primary %}is-primary{% endif %}">
 | 
			
		||||
    <header class="card-image">
 | 
			
		||||
        <figure class="image is-4by3">
 | 
			
		||||
            <img src="{% thumbnail object.cover 480x480 %}">
 | 
			
		||||
        </figure>
 | 
			
		||||
    </header>
 | 
			
		||||
    <div class="card-header">
 | 
			
		||||
        <h4 class="title">
 | 
			
		||||
            <a href="{{ object.get_absolute_url }}">{{ object.title }}</a>
 | 
			
		||||
        </h4>
 | 
			
		||||
    </div>
 | 
			
		||||
</article>
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
{% else %}
 | 
			
		||||
<article class="media item {% if is_primary %}is-primary{% endif %}">
 | 
			
		||||
    {% if has_cover|default_if_none:True %}
 | 
			
		||||
    <div class="media-left">
 | 
			
		||||
        <img src="{% thumbnail object.cover 128x128 crop=scale %}"
 | 
			
		||||
            class="small-cover">
 | 
			
		||||
    </div>
 | 
			
		||||
    {% endif %}
 | 
			
		||||
    <div class="media-content">
 | 
			
		||||
        <h5 class="title is-5 has-text-weight-normal">
 | 
			
		||||
            {% block title %}
 | 
			
		||||
@ -26,8 +47,8 @@ Context variables:
 | 
			
		||||
            {% endblock %}
 | 
			
		||||
        </div>
 | 
			
		||||
 | 
			
		||||
        {% if show_headline %}
 | 
			
		||||
        <div class="">
 | 
			
		||||
        {% if has_headline|default_if_none:True %}
 | 
			
		||||
        <div class="headline">
 | 
			
		||||
        {% block headline %}
 | 
			
		||||
        {{ object.headline|safe }}
 | 
			
		||||
        {% endblock %}
 | 
			
		||||
@ -35,4 +56,5 @@ Context variables:
 | 
			
		||||
        {% endif %}
 | 
			
		||||
    </div>
 | 
			
		||||
</article>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										28
									
								
								aircox/templates/aircox/widgets/page_list.html
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								aircox/templates/aircox/widgets/page_list.html
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,28 @@
 | 
			
		||||
{% comment %}
 | 
			
		||||
Display list of items as small list
 | 
			
		||||
 | 
			
		||||
Context:
 | 
			
		||||
- object_list: object list
 | 
			
		||||
- list_url: url to complete list page
 | 
			
		||||
{% endcomment %}
 | 
			
		||||
{% load i18n %}
 | 
			
		||||
 | 
			
		||||
{% for object in object_list %}
 | 
			
		||||
{% include object.item_template_name %}
 | 
			
		||||
{% endfor %}
 | 
			
		||||
 | 
			
		||||
{% if list_url %}
 | 
			
		||||
<br>
 | 
			
		||||
<nav class="pagination is-centered">
 | 
			
		||||
    <ul class="pagination-list">
 | 
			
		||||
        <li>
 | 
			
		||||
            <a href="{{ list_url }}" class="pagination-link"
 | 
			
		||||
                aria-label="{% trans "Show all publications" %}">
 | 
			
		||||
                {% trans "Show more" %}
 | 
			
		||||
            </a>
 | 
			
		||||
        </li>
 | 
			
		||||
    </ul>
 | 
			
		||||
</nav>
 | 
			
		||||
{% endif %}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -24,8 +24,7 @@ api = [
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
urls = [
 | 
			
		||||
    path(_(''),
 | 
			
		||||
         views.DiffusionListView.as_view(), name='home'),
 | 
			
		||||
    path('', views.HomeView.as_view(), name='home'),
 | 
			
		||||
    path('api/', include(api)),
 | 
			
		||||
 | 
			
		||||
    # path('', views.PageDetailView.as_view(model=models.Article),
 | 
			
		||||
@ -51,9 +50,9 @@ urls = [
 | 
			
		||||
    # path('<page_path:path>', views.route_page, name='page'),
 | 
			
		||||
 | 
			
		||||
    path(_('publications/'),
 | 
			
		||||
         views.ProgramPageListView.as_view(), name='page-list'),
 | 
			
		||||
         views.PageListView.as_view(model=models.Page), name='page-list'),
 | 
			
		||||
 | 
			
		||||
    path(_('programs/'), views.PageListView.as_view(model=models.Program),
 | 
			
		||||
    path(_('programs/'), views.ProgramListView.as_view(model=models.Program),
 | 
			
		||||
         name='program-list'),
 | 
			
		||||
    path(_('programs/<slug:slug>/'),
 | 
			
		||||
         views.ProgramDetailView.as_view(), name='program-detail'),
 | 
			
		||||
@ -62,7 +61,7 @@ urls = [
 | 
			
		||||
    path(_('programs/<slug:parent_slug>/articles/'),
 | 
			
		||||
         views.ArticleListView.as_view(), name='article-list'),
 | 
			
		||||
    path(_('programs/<slug:parent_slug>/publications/'),
 | 
			
		||||
         views.ProgramPageListView.as_view(), name='page-list'),
 | 
			
		||||
         views.ProgramPageListView.as_view(), name='program-page-list'),
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,12 @@
 | 
			
		||||
from . import api, admin
 | 
			
		||||
 | 
			
		||||
from .article import ArticleDetailView, ArticleListView
 | 
			
		||||
from .base import BaseView
 | 
			
		||||
from .home import HomeView
 | 
			
		||||
 | 
			
		||||
from .article import ArticleDetailView, ArticleListView
 | 
			
		||||
from .episode import EpisodeDetailView, EpisodeListView, DiffusionListView
 | 
			
		||||
from .log import LogListView
 | 
			
		||||
from .page import PageDetailView, PageListView
 | 
			
		||||
from .program import ProgramDetailView, ProgramPageListView
 | 
			
		||||
from .program import ProgramDetailView, ProgramListView, \
 | 
			
		||||
        ProgramPageDetailView, ProgramPageListView
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -44,8 +44,7 @@ class AdminSite(admin.AdminSite):
 | 
			
		||||
 | 
			
		||||
    def get_urls(self):
 | 
			
		||||
        from django.urls import path, include
 | 
			
		||||
        urls = super().get_urls()
 | 
			
		||||
        urls += [
 | 
			
		||||
        urls = super().get_urls() + [
 | 
			
		||||
            path('tools/statistics/',
 | 
			
		||||
                 self.admin_view(StatisticsView.as_view()),
 | 
			
		||||
                 name='tools-stats'),
 | 
			
		||||
 | 
			
		||||
@ -4,7 +4,6 @@ from django.utils import timezone as tz
 | 
			
		||||
 | 
			
		||||
from rest_framework.generics import ListAPIView
 | 
			
		||||
 | 
			
		||||
from ..utils import str_to_date
 | 
			
		||||
from ..models import Log
 | 
			
		||||
from ..serializers import LogInfo, LogInfoSerializer
 | 
			
		||||
from .log import LogListMixin
 | 
			
		||||
 | 
			
		||||
@ -25,7 +25,7 @@ class ArticleDetailView(PageDetailView):
 | 
			
		||||
class ArticleListView(ParentMixin, PageListView):
 | 
			
		||||
    model = Article
 | 
			
		||||
    template_name = 'aircox/article_list.html'
 | 
			
		||||
    show_headline = True
 | 
			
		||||
    has_headline = True
 | 
			
		||||
    is_static = False
 | 
			
		||||
    parent_model = Program
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@
 | 
			
		||||
from django.http import Http404
 | 
			
		||||
from django.views.generic import DetailView, ListView
 | 
			
		||||
from django.views.generic.base import TemplateResponseMixin, ContextMixin
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
 | 
			
		||||
from ..models import Page
 | 
			
		||||
from ..utils import Redirect
 | 
			
		||||
@ -35,21 +36,25 @@ class BaseView(TemplateResponseMixin, ContextMixin):
 | 
			
		||||
        return Page.objects.select_subclasses().published() \
 | 
			
		||||
                           .order_by('-pub_date')
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, sidebar_items=None, **kwargs):
 | 
			
		||||
    def get_sidebar_url(self):
 | 
			
		||||
        return reverse('page-list')
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        kwargs.setdefault('station', self.station)
 | 
			
		||||
        kwargs.setdefault('cover', self.cover)
 | 
			
		||||
        kwargs.setdefault('has_filters', self.has_filters)
 | 
			
		||||
 | 
			
		||||
        has_sidebar = kwargs.setdefault('has_sidebar', self.has_sidebar)
 | 
			
		||||
        if has_sidebar and sidebar_items is None:
 | 
			
		||||
            sidebar_items = self.get_sidebar_queryset()
 | 
			
		||||
            sidebar_items = None if sidebar_items is None else \
 | 
			
		||||
                sidebar_items[:self.list_count]
 | 
			
		||||
        if has_sidebar and 'sidebar_object_list' not in kwargs:
 | 
			
		||||
            sidebar_object_list = self.get_sidebar_queryset()
 | 
			
		||||
            if sidebar_object_list is not None:
 | 
			
		||||
                kwargs['sidebar_object_list'] = sidebar_object_list[:self.list_count]
 | 
			
		||||
                kwargs['sidebar_list_url'] = self.get_sidebar_url()
 | 
			
		||||
 | 
			
		||||
        if not 'audio_streams' in kwargs:
 | 
			
		||||
            streams = self.station.audio_streams
 | 
			
		||||
            streams = streams and streams.split('\n')
 | 
			
		||||
            kwargs['audio_streams'] = streams
 | 
			
		||||
 | 
			
		||||
        return super().get_context_data(sidebar_items=sidebar_items, **kwargs)
 | 
			
		||||
        return super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -21,9 +21,6 @@ class EpisodeDetailView(ProgramPageDetailView):
 | 
			
		||||
        return Sound.objects.diffusion(diffusion).podcasts()
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        self.program = kwargs.setdefault('program', self.object.program)
 | 
			
		||||
 | 
			
		||||
        kwargs.setdefault('parent', self.program)
 | 
			
		||||
        if not 'tracks' in kwargs:
 | 
			
		||||
            kwargs['tracks'] = self.object.track_set.order_by('position')
 | 
			
		||||
        if not 'podcasts' in kwargs:
 | 
			
		||||
@ -33,8 +30,8 @@ class EpisodeDetailView(ProgramPageDetailView):
 | 
			
		||||
 | 
			
		||||
class EpisodeListView(ParentMixin, PageListView):
 | 
			
		||||
    model = Episode
 | 
			
		||||
    item_template_name = 'aircox/episode_item.html'
 | 
			
		||||
    show_headline = True
 | 
			
		||||
    item_template_name = 'aircox/widgets/episode_item.html'
 | 
			
		||||
    has_headline = True
 | 
			
		||||
    parent_model = Program
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										44
									
								
								aircox/views/home.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								aircox/views/home.py
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,44 @@
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
from django.utils.translation import ugettext as _
 | 
			
		||||
from django.utils import timezone as tz
 | 
			
		||||
 | 
			
		||||
from ..models import Diffusion, Log, Page
 | 
			
		||||
from .page import PageListView
 | 
			
		||||
 | 
			
		||||
class HomeView(PageListView):
 | 
			
		||||
    template_name = 'aircox/home.html'
 | 
			
		||||
    model = Page
 | 
			
		||||
    queryset = Page.objects.select_subclasses()
 | 
			
		||||
    paginate_by = 10
 | 
			
		||||
    list_count = 40
 | 
			
		||||
    logs_count = 5
 | 
			
		||||
    has_filters = False
 | 
			
		||||
 | 
			
		||||
    def get_logs(self):
 | 
			
		||||
        today = datetime.date.today()
 | 
			
		||||
        logs = Log.objects.on_air().today(today).filter(track__isnull=False)
 | 
			
		||||
        diffs = Diffusion.objects.on_air().today(today)
 | 
			
		||||
        return Log.merge_diffusions(logs, diffs, self.logs_count)
 | 
			
		||||
 | 
			
		||||
    def get_sidebar_queryset(self):
 | 
			
		||||
        today = datetime.date.today()
 | 
			
		||||
        return Diffusion.objects.on_air().today(today)
 | 
			
		||||
 | 
			
		||||
    def get_top_diffs(self):
 | 
			
		||||
        now = tz.now()
 | 
			
		||||
        current_diff = Diffusion.objects.on_air().now(now).first()
 | 
			
		||||
        next_diffs = Diffusion.objects.on_air().after(now)
 | 
			
		||||
        if current_diff:
 | 
			
		||||
            diffs = [current_diff] + list(next_diffs.exclude(pk=current_diff.pk)[:2])
 | 
			
		||||
        else:
 | 
			
		||||
            diffs = next_diffs[:3]
 | 
			
		||||
        return diffs
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        kwargs['logs'] = self.get_logs()
 | 
			
		||||
        kwargs['top_diffs'] = self.get_top_diffs()
 | 
			
		||||
        return super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -2,6 +2,7 @@ from collections import deque
 | 
			
		||||
import datetime
 | 
			
		||||
 | 
			
		||||
from django.views.generic import ListView
 | 
			
		||||
from django.utils import timezone as tz
 | 
			
		||||
 | 
			
		||||
from ..models import Diffusion, Log
 | 
			
		||||
from .base import BaseView
 | 
			
		||||
@ -23,12 +24,14 @@ class LogListMixin(GetDateMixin):
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        # only get logs for tracks: log for diffusion will be retrieved
 | 
			
		||||
        # by the diffusions' queryset.
 | 
			
		||||
        qs = super().get_queryset().on_air().filter(track__isnull=False)
 | 
			
		||||
        qs = super().get_queryset().on_air().filter(track__isnull=False) \
 | 
			
		||||
                                   .filter(date__lte=tz.now())
 | 
			
		||||
        return qs.today(self.date) if self.date is not None else \
 | 
			
		||||
            qs.after(self.min_date) if self.min_date is not None else qs
 | 
			
		||||
 | 
			
		||||
    def get_diffusions_queryset(self):
 | 
			
		||||
        qs = Diffusion.objects.station(self.station).on_air()
 | 
			
		||||
        qs = Diffusion.objects.station(self.station).on_air() \
 | 
			
		||||
                      .filter(start__lte=tz.now())
 | 
			
		||||
        return qs.today(self.date) if self.date is not None else \
 | 
			
		||||
            qs.after(self.min_date) if self.min_date is not None else qs
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -63,9 +63,9 @@ class ParentMixin:
 | 
			
		||||
        return super().get_queryset()
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        parent = kwargs.setdefault('parent', self.parent)
 | 
			
		||||
        if parent is not None:
 | 
			
		||||
            kwargs.setdefault('cover', parent.cover)
 | 
			
		||||
        self.parent = kwargs.setdefault('parent', self.parent)
 | 
			
		||||
        if self.parent is not None:
 | 
			
		||||
            kwargs.setdefault('cover', self.parent.cover)
 | 
			
		||||
        return super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -6,7 +6,7 @@ from django.views.generic import DetailView, ListView
 | 
			
		||||
from honeypot.decorators import check_honeypot
 | 
			
		||||
 | 
			
		||||
from ..forms import CommentForm
 | 
			
		||||
from ..models import Category, Comment
 | 
			
		||||
from ..models import Category, Comment, Page
 | 
			
		||||
from ..utils import Redirect
 | 
			
		||||
from .base import BaseView
 | 
			
		||||
 | 
			
		||||
@ -17,12 +17,12 @@ __all__ = ['PageDetailView', 'PageListView']
 | 
			
		||||
# TODO: pagination: in template, only a limited number of pages displayed
 | 
			
		||||
class PageListView(BaseView, ListView):
 | 
			
		||||
    template_name = 'aircox/page_list.html'
 | 
			
		||||
    item_template_name = 'aircox/page_item.html'
 | 
			
		||||
    item_template_name = 'aircox/widgets/page_item.html'
 | 
			
		||||
    has_sidebar = True
 | 
			
		||||
    has_filters = True
 | 
			
		||||
 | 
			
		||||
    paginate_by = 20
 | 
			
		||||
    show_headline = True
 | 
			
		||||
    has_headline = True
 | 
			
		||||
    categories = None
 | 
			
		||||
 | 
			
		||||
    def get(self, *args, **kwargs):
 | 
			
		||||
@ -30,7 +30,7 @@ class PageListView(BaseView, ListView):
 | 
			
		||||
        return super().get(*args, **kwargs)
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        qs = super().get_queryset().published() \
 | 
			
		||||
        qs = super().get_queryset().select_subclasses().published() \
 | 
			
		||||
                    .select_related('cover', 'category')
 | 
			
		||||
 | 
			
		||||
        # category can be filtered based on request.GET['categories']
 | 
			
		||||
@ -50,7 +50,7 @@ class PageListView(BaseView, ListView):
 | 
			
		||||
        kwargs.setdefault('item_template_name', self.item_template_name)
 | 
			
		||||
        kwargs.setdefault('filter_categories', self.get_categories_queryset())
 | 
			
		||||
        kwargs.setdefault('categories', self.categories)
 | 
			
		||||
        kwargs.setdefault('show_headline', self.show_headline)
 | 
			
		||||
        kwargs.setdefault('has_headline', self.has_headline)
 | 
			
		||||
        return super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
from django.db.models import Q
 | 
			
		||||
from django.core.exceptions import ObjectDoesNotExist
 | 
			
		||||
from django.shortcuts import get_object_or_404
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
 | 
			
		||||
from ..models import Episode, Program, Page
 | 
			
		||||
from .mixins import ParentMixin
 | 
			
		||||
@ -10,30 +11,54 @@ from .page import PageDetailView, PageListView
 | 
			
		||||
__all__ = ['ProgramPageDetailView', 'ProgramDetailView', 'ProgramPageListView']
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramPageDetailView(PageDetailView):
 | 
			
		||||
class BaseProgramMixin:
 | 
			
		||||
    def get_program(self):
 | 
			
		||||
        return self.object
 | 
			
		||||
 | 
			
		||||
    def get_sidebar_url(self):
 | 
			
		||||
        return reverse('program-page-list',
 | 
			
		||||
                       kwargs={"parent_slug": self.program.slug})
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        self.program = self.get_program()
 | 
			
		||||
        kwargs['program'] = self.program
 | 
			
		||||
        return super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramDetailView(BaseProgramMixin, PageDetailView):
 | 
			
		||||
    model = Program
 | 
			
		||||
 | 
			
		||||
    def get_sidebar_queryset(self):
 | 
			
		||||
        return super().get_sidebar_queryset().filter(parent=self.program)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramListView(PageListView):
 | 
			
		||||
    model = Program
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramPageDetailView(BaseProgramMixin, ParentMixin, PageDetailView):
 | 
			
		||||
    """
 | 
			
		||||
    Base view class for a page that is displayed as a program's child page.
 | 
			
		||||
    """
 | 
			
		||||
    program = None
 | 
			
		||||
    has_sidebar = True
 | 
			
		||||
    list_count = 5
 | 
			
		||||
    parent_model = Program
 | 
			
		||||
 | 
			
		||||
    def get_program(self):
 | 
			
		||||
        self.parent = self.object.program
 | 
			
		||||
        return self.object.program
 | 
			
		||||
 | 
			
		||||
    def get_sidebar_queryset(self):
 | 
			
		||||
        return super().get_sidebar_queryset().filter(parent=self.object)
 | 
			
		||||
        return super().get_sidebar_queryset().filter(parent=self.program)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramPageListView(ParentMixin, PageListView):
 | 
			
		||||
class ProgramPageListView(BaseProgramMixin, ParentMixin, PageListView):
 | 
			
		||||
    model = Page
 | 
			
		||||
    parent_model = Program
 | 
			
		||||
    queryset = Page.objects.select_subclasses()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ProgramDetailView(ProgramPageDetailView):
 | 
			
		||||
    model = Program
 | 
			
		||||
    def get_program(self):
 | 
			
		||||
        return self.parent
 | 
			
		||||
 | 
			
		||||
    def get_context_data(self, **kwargs):
 | 
			
		||||
        self.program = kwargs.setdefault('program', self.object)
 | 
			
		||||
        kwargs.setdefault('sidebar_url_parent', None)
 | 
			
		||||
        return super().get_context_data(**kwargs)
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,4 @@
 | 
			
		||||
 | 
			
		||||
// @import './bulmacolors';
 | 
			
		||||
 | 
			
		||||
.navbar {
 | 
			
		||||
    box-shadow: 0em 0em 0.6em rgba(0, 0, 0, 0.4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar .navbar-brand {
 | 
			
		||||
    padding-right: 1em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -26,6 +26,10 @@ export default {
 | 
			
		||||
                    for(var tag of item.value.split(splitReg))
 | 
			
		||||
                        counts[tag.trim()] = (counts[tag.trim()] || 0) + 1;
 | 
			
		||||
            this.counts = counts;
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        onclick(event) {
 | 
			
		||||
            // TODO: row click => check checkbox
 | 
			
		||||
        }
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -83,6 +83,7 @@ export default {
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
        toggle() {
 | 
			
		||||
            console.log('tooogle', this.paused, '-', this.$refs.audio.src)
 | 
			
		||||
            if(this.paused)
 | 
			
		||||
                this.play()
 | 
			
		||||
            else
 | 
			
		||||
 | 
			
		||||
@ -3,7 +3,7 @@
 | 
			
		||||
 | 
			
		||||
$body-background-color: $light;
 | 
			
		||||
 | 
			
		||||
@import "~bulma/bulma";
 | 
			
		||||
@import "~bulma";
 | 
			
		||||
 | 
			
		||||
//-- helpers/modifiers
 | 
			
		||||
.is-fullwidth { width: 100%; }
 | 
			
		||||
@ -58,6 +58,38 @@ a.navbar-item.is-active {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//-- cards
 | 
			
		||||
.card {
 | 
			
		||||
    .title {
 | 
			
		||||
        a {
 | 
			
		||||
            color: $dark;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        padding: 0.2em;
 | 
			
		||||
        font-size: $size-5;
 | 
			
		||||
        font-weight: $weight-medium;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    &.is-primary {
 | 
			
		||||
        box-shadow: 0em 0em 0.5em $black
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.card-super-title {
 | 
			
		||||
    position: absolute;
 | 
			
		||||
    z-index: 1000;
 | 
			
		||||
    font-size: 1.2em;
 | 
			
		||||
    font-weight: $weight-bold;
 | 
			
		||||
    padding: 0.2em;
 | 
			
		||||
    top: 1em;
 | 
			
		||||
    background-color: $white;
 | 
			
		||||
 | 
			
		||||
    .fas {
 | 
			
		||||
        padding: 0.1em;
 | 
			
		||||
        font-size: 0.8em;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//-- filters
 | 
			
		||||
.filters {
 | 
			
		||||
@ -77,18 +109,7 @@ a.navbar-item.is-active {
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
.navbar-brand img {
 | 
			
		||||
    min-height: 6em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.navbar-menu .navbar-item:not(:last-child) {
 | 
			
		||||
    border-right: 1px $grey solid;
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/** page **/
 | 
			
		||||
//-- page
 | 
			
		||||
.page {
 | 
			
		||||
    & > .cover {
 | 
			
		||||
        float: right;
 | 
			
		||||
@ -109,39 +130,33 @@ a.navbar-item.is-active {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section > .toolbar {
 | 
			
		||||
    background-color: rgba(0,0,0,0.05);
 | 
			
		||||
    padding: 1em;
 | 
			
		||||
    margin-bottom: 1.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.media.item .headline {
 | 
			
		||||
    line-height: 1.2em;
 | 
			
		||||
    max-height: calc(1.2em * 3);
 | 
			
		||||
    overflow: hidden;
 | 
			
		||||
 | 
			
		||||
main {
 | 
			
		||||
    .cover {
 | 
			
		||||
        margin: 1em 0em;
 | 
			
		||||
        border: 0.2em black solid;
 | 
			
		||||
    & + .headline-overflow {
 | 
			
		||||
        position: relative;
 | 
			
		||||
        width: 100%;
 | 
			
		||||
        height: 2em;
 | 
			
		||||
        margin-top: -2em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .small-cover {
 | 
			
		||||
        width: 10em;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
aside {
 | 
			
		||||
    .small-cover {
 | 
			
		||||
        width: 4em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .media .subtitle {
 | 
			
		||||
        font-size: 1em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .media .content {
 | 
			
		||||
        display: none;
 | 
			
		||||
    & + .headline-overflow:before {
 | 
			
		||||
        content:'';
 | 
			
		||||
        width:100%;
 | 
			
		||||
        height:100%;
 | 
			
		||||
        position:absolute;
 | 
			
		||||
        left:0;
 | 
			
		||||
        bottom:0;
 | 
			
		||||
        background:linear-gradient(transparent 1em, $body-background-color);
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
//-- player
 | 
			
		||||
.player {
 | 
			
		||||
    box-shadow: 0em 1.5em 2.5em rgba(0, 0, 0, 0.6);
 | 
			
		||||
 | 
			
		||||
@ -175,4 +190,57 @@ aside {
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//-- media
 | 
			
		||||
.media {
 | 
			
		||||
    .subtitle {
 | 
			
		||||
        margin-bottom: 0.4em;
 | 
			
		||||
    }
 | 
			
		||||
    .media-content .headline {
 | 
			
		||||
        font-size: 1em;
 | 
			
		||||
        font-weight: 400;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
//-- general
 | 
			
		||||
body {
 | 
			
		||||
    background-color: $body-background-color;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
section > .toolbar {
 | 
			
		||||
    background-color: rgba(0,0,0,0.05);
 | 
			
		||||
    padding: 1em;
 | 
			
		||||
    margin-bottom: 1.5em;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
main {
 | 
			
		||||
    .cover {
 | 
			
		||||
        margin: 1em 0em;
 | 
			
		||||
        border: 0.2em black solid;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .small-cover {
 | 
			
		||||
        width: 10em;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
aside {
 | 
			
		||||
    & > section {
 | 
			
		||||
        margin-bottom: 2em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .cover {
 | 
			
		||||
        margin-bottom: 2em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .small-cover {
 | 
			
		||||
        width: 4em;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    .media .subtitle {
 | 
			
		||||
        font-size: 1em;
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -22,9 +22,8 @@ import aircox.urls
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
    urlpatterns = [
 | 
			
		||||
    urlpatterns = aircox.urls.urls + [
 | 
			
		||||
        path('admin/', admin.site.urls),
 | 
			
		||||
        path('aircox/', include(aircox.urls.urls)),
 | 
			
		||||
    ]
 | 
			
		||||
 | 
			
		||||
    if settings.DEBUG:
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user