Improved www.ttss.krakow.pl
Jacek Kowalski
2019-02-09 d29c066873b348f79781093a2b3d4d107cde9f2d
Refactor panel component and make it collapsible
5 files modified
216 ■■■■■ changed files
lang_en.js 4 ●●●● patch | view | raw | blame | history
lang_pl.js 4 ●●●● patch | view | raw | blame | history
map.css 78 ●●●●● patch | view | raw | blame | history
map.html 8 ●●●● patch | view | raw | blame | history
map.js 122 ●●●●● patch | view | raw | blame | history
lang_en.js
@@ -5,6 +5,10 @@
    
    map: 'Map',
    
    action_close: 'Close',
    action_expand: 'Expand',
    action_collapse: 'Collapse',
    jquery_not_loaded: 'Required JavaScript jQuery library failed to load. You may try refreshing the page.',
    enter_stop_name_to_begin: 'Enter the stop name to begin.',
    select_stop_click_go: 'Select the stop and click "Go".',
lang_pl.js
@@ -5,6 +5,10 @@
    
    map: 'Mapa',
    
    action_close: 'Zamknij',
    action_expand: 'Rozwiń',
    action_collapse: 'Zwiń',
    jquery_not_loaded: 'Wymagana biblioteka jQuery nie została poprawnie załadowana. Spróbuj odświeżyć stronę.',
    enter_stop_name_to_begin: 'Zacznij wpisywać nazwę przystanku.',
    select_stop_click_go: 'Wyierz przystanek i kliknij "Dalej".',
map.css
@@ -17,42 +17,68 @@
    right: auto;
}
#popup {
.panel {
    opacity: .85;
    color: black;
    background: white;
    padding: 5px;
    border-left: 1px solid black;
    font-size: 14px;
    overflow-y: auto;
    transition: right .4s, width .4s;
    
    position: absolute;
    width: 350px;
    right: -365px;
    top: 0;
    bottom: 0;
    transition: right .4s, width .4s;
    opacity: .85;
    overflow-y: auto;
}
#popup.show {
.panel.expanded {
    right: 0;
}
.panel .hide {
    display: none;
}
.panel.enabled .hide {
    display: block;
    position: fixed;
    bottom: 20%;
    right: 0;
    opacity: .85;
    border: 1px solid black;
    border-right: 0;
    border-radius: 5px 0 0 5px;
    background: white;
    margin-right: 0px;
    padding: 1em 0.2em;
    padding-bottom: 1.2em;
    transition: right .4s, margin-right .4s;
}
.panel.expanded .hide {
    right: 360px;
}
@media (max-width: 600px) {
    #popup {
    .panel {
        width: 80%;
        right: -100%;
    }
    #popup.show {
    .panel.expanded {
        right: 0%;
    }
    .panel.enabled .hide {
        right: 80%;
        margin-right: 10px;
    }
}
.close {
.close, .hide {
    float: right;
    cursor: pointer;
    font-size: 20px;
@@ -62,50 +88,50 @@
    font-size: inherit;
    height: 1em;
}
#popup .type {
.panel .type {
    padding-bottom: 0;
    color: #444;
    font-size: 80%;
}
#popup p {
.panel p {
    margin: 0;
    padding: 5px;
}
#popup .name {
.panel .name {
    font-weight: bold;
}
#popup .vehicleInfo {
.panel .vehicleInfo {
    font-size: 21px;
    margin: -4px 0 -5px;
}
#popup table {
.panel table {
    margin-top: 3px;
    border-top: 1px solid gray;
    width: 100%;
    border-collapse: collapse;
}
#popup table th {
.panel table th {
    text-align: left;
    border-bottom: 1px solid #999;
    padding-top: 5px;
}
#popup table td {
.panel table td {
    vertical-align: top;
}
#popup .active {
.panel .active {
    background: #f5f5f5;
    color: gray;
}
#popup .success {
.panel .success {
    background: #dff0d8;
}
#popup .warning {
.panel .warning {
    background: #fcf8e3;
}
#popup .danger {
.panel .danger {
    background: #f2dede;
}
#popup table .vehicleInfo {
.panel table .vehicleInfo {
    float: right;
}
@@ -117,7 +143,7 @@
    background-color: rgba(255,255,255,.6);
}
#fail, #popup .error {
#fail, .panel .error {
    background: red;
    color: white;
    font-weight: bold;
map.html
@@ -5,7 +5,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="initial-scale=1.0, user-scalable=no, width=device-width" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v5.3.0/css/ol.css" integrity="sha384-C7SzZySesoxngSK5V0BaD1DUap0LPZGWZpnXQGoIwvBXFc8G21y4s1QYvyr84FNa" crossorigin="anonymous">
<link rel="stylesheet" href="map.css?v2" type="text/css" />
<link rel="stylesheet" href="map.css?v3" type="text/css" />
</head>
<body>
<div id="map">
@@ -20,12 +20,12 @@
</svg></button></div>
<div id="fail" class="ol-unselectable ol-control"><span></span> <span class="close">×</p></div>
</div>
<div id="popup"></div>
<div id="panel"></div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js" integrity="sha384-tsQFqpEReu7ZLhBV2VZlAu7zcOV+rXbYlF2cqB8txI/8aZajjp4Bqd+V6D5IgvKT" crossorigin="anonymous"></script>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=requestAnimationFrame,Element.prototype.classList"></script>
<script src="https://cdn.jsdelivr.net/gh/openlayers/openlayers.github.io@master/en/v5.3.0/build/ol.js" integrity="sha384-iQkGyyH4ioz3m+maM3s9MX1Oq67mACa4B9Z3ovUv3Sv37LJ96fx3WnZfLoiC3Wfl" crossorigin="anonymous"></script>
<script tyle="text/javascript" src="lang_pl.js?v4" id="lang_script"></script>
<script tyle="text/javascript" src="lang_pl.js?v5" id="lang_script"></script>
<script tyle="text/javascript" src="common.js?v6"></script>
<script tyle="text/javascript" src="map.js?v11"></script>
<script tyle="text/javascript" src="map.js?v12"></script>
</body>
</html>
map.js
@@ -46,20 +46,85 @@
var route_layer = null;
var map = null;
var popup_element = document.getElementById('popup');
var popup_close_callback;
var panel = null;
var fail_element = document.getElementById('fail');
var fail_text = document.querySelector('#fail span');
var ignore_hashchange = false;
function Panel(element) {
    this._element = element;
    this._element.classList.add('panel');
    this._hide = addParaWithText(this._element, '▶');
    this._hide.title = lang.action_collapse;
    this._hide.className = 'hide';
    this._hide.addEventListener('click', this.toggleExpanded.bind(this));
    this._close = addParaWithText(this._element, '×');
    this._close.title = lang.action_close;
    this._close.className = 'close';
    this._close.addEventListener('click', this.close.bind(this));
    this._content = document.createElement('div');
    this._element.appendChild(this._content);
};
Panel.prototype = {
    _element: null,
    _hide: null,
    _close: null,
    _content: null,
    _closeCallback: null,
    _runCallback: function() {
        var callback = this.closeCallback;
        this.closeCallback = null;
        if(callback) callback();
    },
    expand: function() {
        this._element.classList.add('expanded');
        setText(this._hide, '▶');
        this._hide.title = lang.action_collapse;
    },
    collapse: function() {
        this._element.classList.remove('expanded');
        setText(this._hide, '◀');
        this._hide.title = lang.action_expand;
    },
    toggleExpanded: function() {
        if(this._element.classList.contains('expanded')) {
            this.collapse();
        } else {
            this.expand();
        }
    },
    fail: function(message) {
        addParaWithText(this._content, message).className = 'error';
    },
    show: function(contents, closeCallback) {
        this._runCallback();
        this.closeCallback = closeCallback;
        deleteChildren(this._content);
        this._content.appendChild(contents);
        this._element.classList.add('enabled');
        setTimeout(this.expand.bind(this), 1);
    },
    close: function() {
        this._runCallback();
        this._element.classList.remove('expanded');
        this._element.classList.remove('enabled');
    },
};
function fail(msg) {
    setText(fail_text, msg);
    fail_element.style.top = '0.5em';
}
function fail_popup(msg) {
    addElementWithText(popup_element, 'p', msg).className = 'error';
}
function fail_ajax_generic(data, fnc) {
@@ -80,7 +145,7 @@
}
function fail_ajax_popup(data) {
    fail_ajax_generic(data, fail_popup);
    fail_ajax_generic(data, panel.fail.bind(panel));
}
function getGeometry(object) {
@@ -462,38 +527,13 @@
    }).fail(fail_ajax_popup);
}
function showPanel(contents, closeCallback) {
    var old_callback = popup_close_callback;
    popup_close_callback = null;
    if(old_callback) old_callback();
    popup_close_callback = closeCallback;
    deleteChildren(popup_element);
    var close = addParaWithText(popup_element, '×');
    close.className = 'close';
    close.addEventListener('click', function() { hidePanel(); });
    popup_element.appendChild(contents);
    $(popup_element).addClass('show');
}
function hidePanel() {
    var old_callback = popup_close_callback;
    popup_close_callback = null;
    if(old_callback) old_callback();
    $(popup_element).removeClass('show');
}
function featureClicked(feature) {
    if(feature && !feature.getId()) return;
    
    unstyleSelectedFeatures();
    
    if(!feature) {
        hidePanel();
        panel.close();
        return;
    }
    
@@ -611,13 +651,13 @@
    }) }, 10);
    
    
    showPanel(div, function() {
    panel.show(div, function() {
        if(!ignore_hashchange) {
            ignore_hashchange = true;
            window.location.hash = '';
            
            feature_clicked = null;
            unstyleSelectedFeatures();
            feature_clicked = null;
            
            if(feature_xhr) feature_xhr.abort();
            if(feature_timer) clearTimeout(feature_timer);
@@ -689,7 +729,7 @@
            div.appendChild(p);
        }
        
        showPanel(div);
        panel.show(div);
        
        return;
    }
@@ -724,14 +764,14 @@
}
function trackingStop() {
    geolocation_button.className = "";
    geolocation_button.classList.remove('clicked');
    geolocation.setTracking(false);
    
    geolocation_source.clear();
}
function trackingStart() {
    geolocation_set = 0;
    geolocation_button.className = "clicked";
    geolocation_button.classList.add('clicked');
    geolocation_feature.setGeometry(new ol.geom.Point(map.getView().getCenter()));
    geolocation_accuracy.setGeometry(new ol.geom.Circle(map.getView().getCenter(), 100000));
    
@@ -827,6 +867,8 @@
        dataType: 'json',
        timeout: 10000,
    });
    panel = new Panel(document.getElementById('panel'));
    
    stops_buses_source = new ol.source.Vector({
        features: [],
@@ -944,7 +986,7 @@
    });
    geolocation_button = document.querySelector('#track button');
    if(!navigator.geolocation) {
        geolocation_button.className = 'hidden';
        geolocation_button.classList.add('hidden');
    }
    
    geolocation = new ol.Geolocation({projection: 'EPSG:3857'});
@@ -969,7 +1011,7 @@
    geolocation.on('error', function(error) {
        fail(lang.error_location + ' ' + error.message);
        trackingStop();
        geolocation_button.className = 'hidden';
        geolocation_button.classList.add('hidden');
    });
    geolocation_button.addEventListener('click', trackingToggle);