fix some memory leaks
This commit is contained in:
parent
c3570cb38e
commit
12fb18d902
@ -20,7 +20,7 @@
|
||||
<stop-details :stop="stop"></stop-details>
|
||||
</fold>
|
||||
|
||||
<popper reference="action-map" :visible="map" arrow class="popper--no-padding" style="width: 500px;">
|
||||
<popper reference="action-map" :visible="map" arrow class="popper--no-padding" style="width: 500px;" placement="right-start">
|
||||
<div style="height: 300px">
|
||||
<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='© <a href="//osm.org/copyright">OpenStreetMap</a> contributors'></l-tile-layer>
|
||||
|
@ -11,7 +11,7 @@ window['Popper'] = Popper;
|
||||
|
||||
// dependencies
|
||||
import Vue from "vue";
|
||||
import Vuex, { mapActions, mapState, Store } from 'vuex';
|
||||
import Vuex, { mapActions, mapMutations, mapState, Store } from 'vuex';
|
||||
|
||||
Vue.use(Vuex);
|
||||
|
||||
@ -25,12 +25,13 @@ Vue.use(Vuex);
|
||||
import('bootstrap'),
|
||||
]);
|
||||
|
||||
store.dispatch('messages/update');
|
||||
|
||||
// here goes "public" API
|
||||
window['czydojade'] = {
|
||||
window['czydojade'] = Object.assign({}, window['czydojade'], {
|
||||
components
|
||||
};
|
||||
});
|
||||
|
||||
store.dispatch('messages/update');
|
||||
store.dispatch('load', window['czydojade'].state);
|
||||
|
||||
let intervals = { messages: null, departures: null };
|
||||
|
||||
@ -38,7 +39,6 @@ Vue.use(Vuex);
|
||||
el: '#app',
|
||||
store: store,
|
||||
data: {
|
||||
stops: [],
|
||||
sections: {
|
||||
messages: true
|
||||
},
|
||||
@ -70,6 +70,14 @@ Vue.use(Vuex);
|
||||
return {
|
||||
state: this.$store.state.departures.state
|
||||
};
|
||||
},
|
||||
stops: {
|
||||
get(this: Vue) {
|
||||
return this.$store.state.stops;
|
||||
},
|
||||
set(this: Vue, value) {
|
||||
this.$store.commit('updateStops', value);
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -104,7 +112,13 @@ Vue.use(Vuex);
|
||||
...mapActions({
|
||||
updateMessages: 'messages/update',
|
||||
updateDepartures: 'departures/update'
|
||||
})
|
||||
}),
|
||||
...mapMutations({
|
||||
updateStops: 'updateStops'
|
||||
}),
|
||||
save(this: Vue) {
|
||||
this.$store.dispatch('save').then(x => console.log(x));
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.$el.classList.remove('not-ready');
|
||||
|
@ -68,7 +68,7 @@ export class PopperComponent extends Vue {
|
||||
window.dispatchEvent(new Event('resize'));
|
||||
}
|
||||
|
||||
destroyed() {
|
||||
beforeDestroy() {
|
||||
this._popper.destroy();
|
||||
}
|
||||
}
|
||||
@ -94,7 +94,7 @@ export class FoldComponent extends Vue {
|
||||
});
|
||||
}
|
||||
|
||||
destroyed() {
|
||||
beforeDestroy() {
|
||||
this.observer.disconnect();
|
||||
}
|
||||
|
||||
|
@ -4,55 +4,74 @@ import { condition } from "./decorators";
|
||||
|
||||
Vue.filter('signed', signed);
|
||||
|
||||
Vue.directive('hover', (el, binding, node) => {
|
||||
const update = (hovered: boolean, e: Event) => {
|
||||
if (typeof binding.value === 'function') {
|
||||
binding.value(hovered, e);
|
||||
}
|
||||
|
||||
if (typeof binding.value === 'boolean') {
|
||||
set(node.context, binding.expression, hovered);
|
||||
}
|
||||
|
||||
if (typeof binding.arg !== 'undefined') {
|
||||
set(node.context, binding.arg, hovered);
|
||||
}
|
||||
};
|
||||
|
||||
const activate = event => update(true, event);
|
||||
const deactivate = event => update(false, event);
|
||||
|
||||
el.addEventListener('mouseenter', activate);
|
||||
el.addEventListener('click', activate);
|
||||
el.addEventListener('keydown', condition.decorate(deactivate, e => e.keyCode == 27));
|
||||
el.addEventListener('mouseleave', deactivate);
|
||||
el.addEventListener('focusout', deactivate);
|
||||
});
|
||||
|
||||
Vue.directive('responsive', (el, binding) => {
|
||||
const breakpoints = typeof binding.value === 'object' ? binding.value : {
|
||||
'xs': 0,
|
||||
'sm': 576,
|
||||
'md': 768,
|
||||
'lg': 1024,
|
||||
'xl': 1200,
|
||||
};
|
||||
|
||||
const resize = () => {
|
||||
const width = el.scrollWidth;
|
||||
el.classList.remove(...Object.keys(breakpoints).map(breakpoint => `size-${breakpoint}`));
|
||||
|
||||
for (let [ breakpoint, size ] of Object.entries(breakpoints)) {
|
||||
if (width < size) {
|
||||
break;
|
||||
Vue.directive('hover', {
|
||||
bind(el, binding, node) {
|
||||
const update = (hovered: boolean, e: Event) => {
|
||||
if (typeof binding.value === 'function') {
|
||||
binding.value(hovered, e);
|
||||
}
|
||||
|
||||
el.classList.add(`size-${breakpoint}`);
|
||||
}
|
||||
};
|
||||
if (typeof binding.value === 'boolean') {
|
||||
set(node.context, binding.expression, hovered);
|
||||
}
|
||||
|
||||
resize();
|
||||
if (!binding.modifiers['once']) {
|
||||
window.addEventListener('resize', resize);
|
||||
if (typeof binding.arg !== 'undefined') {
|
||||
set(node.context, binding.arg, hovered);
|
||||
}
|
||||
};
|
||||
|
||||
const activate = event => update(true, event);
|
||||
const deactivate = event => update(false, event);
|
||||
const keyboard = condition.decorate(deactivate, e => e.keyCode == 27);
|
||||
|
||||
binding['events'] = { activate, deactivate, keyboard };
|
||||
|
||||
el.addEventListener('mouseenter', activate);
|
||||
el.addEventListener('click', activate);
|
||||
el.addEventListener('keydown', keyboard);
|
||||
el.addEventListener('mouseleave', deactivate);
|
||||
el.addEventListener('focusout', deactivate);
|
||||
},
|
||||
unbind(el, binding) {
|
||||
const { activate, deactivate, keyboard } = binding['events'];
|
||||
|
||||
el.removeEventListener('mouseenter', activate);
|
||||
el.removeEventListener('click', activate);
|
||||
el.removeEventListener('keydown', keyboard);
|
||||
el.removeEventListener('mouseleave', deactivate);
|
||||
el.removeEventListener('focusout', deactivate);
|
||||
}
|
||||
});
|
||||
|
||||
Vue.directive('responsive', {
|
||||
inserted(el, binding) {
|
||||
const breakpoints = typeof binding.value === 'object' ? binding.value : {
|
||||
'xs': 0,
|
||||
'sm': 576,
|
||||
'md': 768,
|
||||
'lg': 1024,
|
||||
'xl': 1200,
|
||||
};
|
||||
|
||||
const resize = binding['resize'] = () => {
|
||||
const width = el.scrollWidth;
|
||||
el.classList.remove(...Object.keys(breakpoints).map(breakpoint => `size-${breakpoint}`));
|
||||
|
||||
for (let [ breakpoint, size ] of Object.entries(breakpoints)) {
|
||||
if (width < size) {
|
||||
break;
|
||||
}
|
||||
|
||||
el.classList.add(`size-${breakpoint}`);
|
||||
}
|
||||
};
|
||||
resize();
|
||||
|
||||
if (!binding.modifiers['once']) {
|
||||
window.addEventListener('resize', resize);
|
||||
}
|
||||
},
|
||||
unbind(el, binding) {
|
||||
window.removeEventListener('resize', binding['resize']);
|
||||
}
|
||||
});
|
||||
|
@ -11,4 +11,4 @@ export type StopGroup = Stop[];
|
||||
|
||||
export type StopGroups = {
|
||||
[name: string]: StopGroup;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,9 @@ import Vuex from 'vuex';
|
||||
|
||||
import messages from './messages';
|
||||
import departures from './departures';
|
||||
import { state, mutations, actions } from "./root";
|
||||
|
||||
export default new Vuex.Store({
|
||||
state, mutations, actions,
|
||||
modules: { messages, departures }
|
||||
})
|
@ -1,9 +1,36 @@
|
||||
import { Module } from "vuex";
|
||||
import { Stop } from "../model";
|
||||
import { ActionTree, MutationTree } from "vuex";
|
||||
import urls from "../urls";
|
||||
|
||||
const state = { };
|
||||
export interface RootState {
|
||||
stops: Stop[],
|
||||
}
|
||||
|
||||
export type RootState = typeof state;
|
||||
export interface SavedState {
|
||||
version: 1,
|
||||
stops: string[],
|
||||
}
|
||||
|
||||
export default <Module<RootState, unknown>>{
|
||||
state
|
||||
}
|
||||
export const state: RootState = {
|
||||
stops: []
|
||||
};
|
||||
|
||||
export const mutations: MutationTree<RootState> = {
|
||||
updateStops: (state, stops) => state.stops = stops,
|
||||
};
|
||||
|
||||
export const actions: ActionTree<RootState, undefined> = {
|
||||
async load({ commit }, { stops }: SavedState) {
|
||||
if (stops.length > 0) {
|
||||
const response = await fetch(urls.prepare(urls.stops.all, { id: stops }));
|
||||
|
||||
if (response.ok) {
|
||||
commit('updateStops', await response.json());
|
||||
}
|
||||
}
|
||||
},
|
||||
save: async ({ state }): Promise<SavedState> => ({
|
||||
version: 1,
|
||||
stops: state.stops.map(stop => stop.id)
|
||||
})
|
||||
};
|
56
src/Provider/Dummy/DummyDepartureRepository.php
Normal file
56
src/Provider/Dummy/DummyDepartureRepository.php
Normal file
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
namespace App\Provider\Dummy;
|
||||
|
||||
use App\Model\Departure;
|
||||
use App\Model\Line;
|
||||
use App\Model\Stop;
|
||||
use App\Model\Vehicle;
|
||||
use App\Provider\DepartureRepository;
|
||||
use App\Service\Proxy\ReferenceFactory;
|
||||
use Carbon\Carbon;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
|
||||
class DummyDepartureRepository implements DepartureRepository
|
||||
{
|
||||
private $reference;
|
||||
|
||||
/**
|
||||
* DummyDepartureProviderRepository constructor.
|
||||
*
|
||||
* @param $reference
|
||||
*/
|
||||
public function __construct(ReferenceFactory $reference)
|
||||
{
|
||||
$this->reference = $reference;
|
||||
}
|
||||
|
||||
public function getForStop(Stop $stop): Collection
|
||||
{
|
||||
return collect([
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
[ 1, Line::TYPE_TRAM, 'lorem ipsum', 2137 ],
|
||||
])->map(function ($departure) use ($stop) {
|
||||
list($symbol, $type, $display, $vehicle) = $departure;
|
||||
$scheduled = new Carbon();
|
||||
$estimated = (clone $scheduled)->addSeconds(40);
|
||||
|
||||
return Departure::createFromArray([
|
||||
'scheduled' => $scheduled,
|
||||
'estimated' => $estimated,
|
||||
'stop' => $stop,
|
||||
'display' => $display,
|
||||
'vehicle' => $this->reference->get(Vehicle::class, $vehicle),
|
||||
'line' => Line::createFromArray(['symbol' => $symbol, 'type' => $type]),
|
||||
]);
|
||||
});
|
||||
}
|
||||
}
|
@ -12,9 +12,23 @@ use App\Provider\TrackRepository;
|
||||
|
||||
class DummyProvider implements Provider
|
||||
{
|
||||
private $departures;
|
||||
private $stops;
|
||||
|
||||
/**
|
||||
* DummyProvider constructor.
|
||||
*
|
||||
* @param $departures
|
||||
*/
|
||||
public function __construct(DummyDepartureRepository $departures, DummyStopRepository $stops)
|
||||
{
|
||||
$this->departures = $departures;
|
||||
$this->stops = $stops;
|
||||
}
|
||||
|
||||
public function getDepartureRepository(): DepartureRepository
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
return $this->departures;
|
||||
}
|
||||
|
||||
public function getLineRepository(): LineRepository
|
||||
@ -24,7 +38,7 @@ class DummyProvider implements Provider
|
||||
|
||||
public function getStopRepository(): StopRepository
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
return $this->stops;
|
||||
}
|
||||
|
||||
public function getMessageRepository(): MessageRepository
|
||||
|
49
src/Provider/Dummy/DummyStopRepository.php
Normal file
49
src/Provider/Dummy/DummyStopRepository.php
Normal file
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
namespace App\Provider\Dummy;
|
||||
|
||||
use App\Model\Stop;
|
||||
use App\Provider\StopRepository;
|
||||
use App\Service\Proxy\ReferenceFactory;
|
||||
use Tightenco\Collect\Support\Collection;
|
||||
use Kadet\Functional as f;
|
||||
|
||||
class DummyStopRepository implements StopRepository
|
||||
{
|
||||
private $reference;
|
||||
|
||||
/**
|
||||
* DummyDepartureProviderRepository constructor.
|
||||
*
|
||||
* @param $reference
|
||||
*/
|
||||
public function __construct(ReferenceFactory $reference)
|
||||
{
|
||||
$this->reference = $reference;
|
||||
}
|
||||
|
||||
public function getAll(): Collection
|
||||
{
|
||||
return collect();
|
||||
}
|
||||
|
||||
public function getAllGroups(): Collection
|
||||
{
|
||||
return collect();
|
||||
}
|
||||
|
||||
public function getById($id): ?Stop
|
||||
{
|
||||
return Stop::createFromArray(['id' => $id, 'name' => 'lorem']);
|
||||
}
|
||||
|
||||
public function getManyById($ids): Collection
|
||||
{
|
||||
return collect($ids)->map(f\ref([ $this, 'getById' ]));
|
||||
}
|
||||
|
||||
public function findGroupsByName(string $name): Collection
|
||||
{
|
||||
return collect();
|
||||
}
|
||||
}
|
@ -12,12 +12,12 @@
|
||||
Komunikaty <span class="ml-2 badge badge-pill badge-dark">{{ '{{ messages.count }}' }}</span>
|
||||
</h2>
|
||||
<button class="btn btn-action flex-space-left" ref="settings-messages" v-hover="settings.messages">
|
||||
<fa :icon="['fal', 'cog']"></fa>
|
||||
<fa :icon="['fal', 'cog']" fixed-width></fa>
|
||||
</button>
|
||||
<button class="btn btn-action" @click="updateMessages" ref="btn-messages-refresh">
|
||||
<fa :icon="['fal', 'sync']" :spin="messages.state === 'fetching'"></fa>
|
||||
<fa :icon="['fal', 'sync']" :spin="messages.state === 'fetching'" fixed-width></fa>
|
||||
</button>
|
||||
<button class="btn btn-action" @click="sections.messages = !sections.messages">
|
||||
<button class="btn btn-action" @click="sections.messages = !sections.messages" fixed-width>
|
||||
<fa :icon="['fal', sections.messages ? 'chevron-up' : 'chevron-down']" fixed-width/>
|
||||
</button>
|
||||
|
||||
@ -47,10 +47,10 @@
|
||||
<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>
|
||||
<fa :icon="['fal', 'cog']" fixed-width></fa>
|
||||
</button>
|
||||
<button class="btn btn-action" @click="updateDepartures({ stops })">
|
||||
<fa :icon="['fal', 'sync']" :spin="departures.state === 'fetching'"></fa>
|
||||
<fa :icon="['fal', 'sync']" :spin="departures.state === 'fetching'" fixed-width></fa>
|
||||
</button>
|
||||
|
||||
<popper reference="settings-departures" :visible="settings.departures" arrow placement="left-start">
|
||||
|
@ -35,6 +35,14 @@
|
||||
</footer>
|
||||
|
||||
{% block javascripts %}{% endblock %}
|
||||
<script>
|
||||
window.czydojade = {
|
||||
state: {{ {
|
||||
version: 1,
|
||||
stops: app.request.query.get('stop', [])
|
||||
}|json_encode|raw }}
|
||||
};
|
||||
</script>
|
||||
<script src="{{ asset('bundle.js') }}"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
Loading…
Reference in New Issue
Block a user