autoupdate feature

This commit is contained in:
Kacper Donat 2018-09-30 21:30:12 +02:00
parent 82adf1139a
commit 1fe04718f9
10 changed files with 177 additions and 25 deletions

View File

@ -1,6 +1,6 @@
<div class="popper" :class="{ 'has-arrow': arrow, 'd-none': !visible }">
<div class="popper-arrow" ref="arrow" v-if="arrow"></div>
<lazy v-if="lazy" :activate="visible">
<div class="popper" :class="{ 'popper--arrow': arrow, 'd-none': !show }" v-hover="hovered">
<div class="popper__arrow" ref="arrow" v-if="arrow"></div>
<lazy v-if="lazy" :activate="show">
<slot></slot>
</lazy>
<slot v-else></slot>

View File

@ -20,7 +20,7 @@
<stop-details :stop="stop"></stop-details>
</fold>
<popper reference="action-map" :visible="map" arrow>
<popper reference="action-map" :visible="map" arrow class="popper--no-padding">
<div style="height: 300px; width: 500px">
<l-map :center="stop.location" :zoom=17 :options="{ zoomControl: false, dragging: false }">
<l-tile-layer url="//{s}.tile.osm.org/{z}/{x}/{y}.png" attribution='&copy; <a href="//osm.org/copyright">OpenStreetMap</a> contributors'></l-tile-layer>

View File

@ -44,6 +44,21 @@
.flex {
display: flex;
align-items: center;
> .text {
margin-left: .2rem;
margin-right: .2rem;
display: inline-block;
margin-bottom: 0;
&:last-child, & + .text {
margin-right: 0;
}
&:first-child {
margin-left: 0;
}
}
}
.section {
@ -53,6 +68,15 @@
@extend .alert;
@extend .alert-dark;
> * {
font-size: medium;
}
@include direct-headings {
@extend .flex;
margin-bottom: 0;
}
font-size: medium;
background: transparent;
padding-top: .5rem;

View File

@ -55,11 +55,11 @@
@mixin triangle-right($size, $color, $border: none) { @include triangle(right, $size, $color, $border); }
.popper {
$arrow-base: 10px;
$arrow-base: 8px;
$arrow-color: white;
$arrow-border: black;
$popper-padding: 2px;
$popper-padding: .5rem;
padding: $popper-padding;
background: white;
@ -73,12 +73,22 @@
border-radius: 2px;
.popper-arrow {
.popper__arrow {
position: absolute;
width: 0;
height: 0;
}
&.popper--no-padding {
padding: 0;
}
.popper__heading {
font-size: $font-size-sm;
font-weight: bold;
margin-bottom: .5rem;
}
@mixin placement($placement) {
$opposite: (
left: right,
@ -90,14 +100,14 @@
&[x-placement*="#{$placement}"] {
margin-#{map-get($opposite, $placement)}: $arrow-base;
.popper-arrow {
.popper__arrow {
#{map-get($opposite, $placement)}: 0;
@include triangle(map-get($opposite, $placement), $arrow-base, $arrow-color, $arrow-border);
}
}
}
&.has-arrow {
&.popper--arrow {
@include placement("left");
@include placement("right");
@include placement("top");

View File

@ -1,6 +1,7 @@
$border-radius: 0;
$border-radius-lg: $border-radius;
$border-radius-sm: $border-radius;
@import "~bootstrap/scss/functions";
@import "~bootstrap/scss/variables";
@ -24,6 +25,18 @@ $container-max-widths: map-merge($container-max-widths, ( xl: 1320px ));
@import "~bootstrap/scss/bootstrap";
@mixin headings {
h1, h2, h3, h4, h5, h6 {
@content
}
}
@mixin direct-headings {
> h1, > h2, > h3, > h4, > h5, > h6 {
@content
}
}
@import "common";
@import "stop";
@import "departure";

View File

@ -32,6 +32,8 @@ Vue.use(Vuex);
components
};
let intervals = { messages: null, departures: null };
window['app'] = new Vue({
el: '#app',
store: store,
@ -39,8 +41,23 @@ Vue.use(Vuex);
stops: [],
sections: {
messages: true
},
settings: {
messages: false,
departures: false
},
autorefresh: {
messages: {
active: true,
interval: 60
},
departures: {
active: true,
interval: 10
}
},
},
computed: {
messages(this: any) {
return {
@ -58,7 +75,26 @@ Vue.use(Vuex);
watch: {
stops(this: any, stops) {
this.updateDepartures({ stops });
},
autorefresh: { immediate: true, handler(this: any, settings) {
if (intervals.messages) {
clearInterval(intervals.messages);
intervals.messages = null;
}
if (intervals.departures) {
clearInterval(intervals.departures);
intervals.messages = null;
}
if (settings.messages.active) {
intervals.messages = setInterval(() => this.updateMessages(), Math.max(5, settings.messages.interval) * 1000);
}
if (settings.departures.active) {
intervals.departures = setInterval(() => this.updateDepartures({ stops: this.stops }), Math.max(5, settings.departures.interval) * 1000);
}
} }
},
methods: {
...mapActions({

View File

@ -19,8 +19,14 @@ export class PopperComponent extends Vue {
@Prop(Boolean)
public lazy: boolean;
public hovered: boolean = false;
private _popper;
get show() {
return this.visible || this.hovered;
}
mounted() {
const reference = this.$parent.$refs[this.reference] as HTMLElement;
@ -30,6 +36,12 @@ export class PopperComponent extends Vue {
arrow: { enabled: this.arrow, element: this.$refs['arrow'] as Element }
}
});
this.$nextTick(() => this._popper.update())
}
updated() {
this._popper.update();
}
@Watch('visible')
@ -68,6 +80,7 @@ export class FoldComponent extends Vue {
this.observer.disconnect();
}
@Watch('visible')
private resize() {
const inner = this.$refs['inner'] as HTMLDivElement;

View File

@ -1,4 +1,4 @@
import { signed } from "./utils";
import { set, signed } from "./utils";
import Vue from 'vue';
import { condition } from "./decorators";
@ -11,11 +11,11 @@ Vue.directive('hover', (el, binding, node) => {
}
if (typeof binding.value === 'boolean') {
node.context[binding.expression] = hovered;
set(node.context, binding.expression, hovered);
}
if (typeof binding.arg !== 'undefined') {
node.context[binding.arg] = hovered;
set(node.context, binding.arg, hovered);
}
};

View File

@ -41,3 +41,21 @@ export function signed(number: number): string {
export function ensureArray<T>(x: T[]|T): T[] {
return x instanceof Array ? x : [ x ];
}
export function set(object: any, path: string, value: any) {
const segments = path.split('.');
while (segments.length > 1) {
object = object[segments.shift()];
}
object[segments.shift()] = value;
}
export function get(object: any, path: string): any {
const segments = path.split('.');
while (segments.length > 1) {
object = object[segments.shift()];
}
return object[segments.shift()];
}

View File

@ -6,29 +6,67 @@
<div class="row">
<div class="col-md-8 order-md-last">
<section class="section messages" v-show="messages.count > 0">
<h2 class="section__title flex">
<header class="section__title flex">
<h2>
<fa :icon="['fal', 'bullhorn']" fixed-width class="mr-2"></fa>
Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span>
<button class="btn btn-action flex-space-left" @click="updateMessages">
</h2>
<button class="btn btn-action flex-space-left" ref="settings-messages" v-hover="settings.messages">
<fa :icon="['fal', 'cog']"></fa>
</button>
<button class="btn btn-action" @click="updateMessages" ref="btn-messages-refresh">
<fa :icon="['fal', 'sync']" :spin="messages.state === 'fetching'"></fa>
</button>
<button class="btn btn-action" @click="sections.messages = !sections.messages">
<fa :icon="['fal', sections.messages ? 'chevron-up' : 'chevron-down']" fixed-width/>
</button>
</h2>
<popper reference="settings-messages" :visible="settings.messages" arrow placement="left-start">
<h3 class="popper__heading flex">
<fa :icon="['far', 'cog']"></fa>
<label class="text" for="messages-auto-refresh">autoodświeżanie</label>
<input type="checkbox" class="flex-space-left" id="messages-auto-refresh" v-model="autorefresh.messages.active"/>
</h3>
<div class="flex" v-show="autorefresh.messages.active">
<span class="text">co</span>
<label class="sr-only" for="messages-auto-refresh-interval">częstotliwość odświeżania</label>
<input type="text" class="form-control form-control-sm" id="messages-auto-refresh-interval" v-model="autorefresh.messages.interval"/>
<span class="text">s</span>
</div>
</popper>
</header>
<fold :visible="sections.messages">
<messages></messages>
</fold>
</section>
<section class="section">
<h2 class="section__title flex">
<fa :icon="['fal', 'clock']" fixed-width class="mr-1"></fa>
Odjazdy
<button class="btn btn-action flex-space-left" @click="updateDepartures({ stops })">
<header class="section__title flex">
<h2>
<fa :icon="['fal', 'clock']" fixed-width></fa>
<span class="text">Odjazdy</span>
</h2>
<button class="btn btn-action flex-space-left" ref="settings-departures" v-hover="settings.departures">
<fa :icon="['fal', 'cog']"></fa>
</button>
<button class="btn btn-action" @click="updateDepartures({ stops })">
<fa :icon="['fal', 'sync']" :spin="departures.state === 'fetching'"></fa>
</button>
</h2>
<popper reference="settings-departures" :visible="settings.departures" arrow placement="left-start">
<h3 class="popper__heading flex">
<fa :icon="['far', 'cog']"></fa>
<label class="text" for="messages-auto-refresh">autoodświeżanie</label>
<input type="checkbox" class="flex-space-left" id="messages-auto-refresh" v-model="autorefresh.departures.active"/>
</h3>
<div class="flex" v-show="autorefresh.messages.active">
<span class="text">co</span>
<label class="sr-only" for="messages-auto-refresh-interval">częstotliwość odświeżania</label>
<input type="text" class="form-control form-control-sm" id="messages-auto-refresh-interval" v-model="autorefresh.departures.interval"/>
<span class="text">s</span>
</div>
</popper>
</header>
<departures :stops="stops"></departures>
{% if provider.attribution %}
<div class="attribution">