fix: synchro repository with production
7
dist/bootstrap/bootstrap.min.css
vendored
Normal file
7
dist/bootstrap/bootstrap.min.js
vendored
Normal file
584
dist/bootstrap/bootstrap3-typeahead.js
vendored
Normal file
@ -0,0 +1,584 @@
|
||||
/* =============================================================
|
||||
* bootstrap3-typeahead.js v4.0.2
|
||||
* https://github.com/bassjobsen/Bootstrap-3-Typeahead
|
||||
* =============================================================
|
||||
* Original written by @mdo and @fat
|
||||
* =============================================================
|
||||
* Copyright 2014 Bass Jobsen @bassjobsen
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the 'License');
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an 'AS IS' BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
* ============================================================ */
|
||||
|
||||
|
||||
(function (root, factory) {
|
||||
|
||||
'use strict';
|
||||
|
||||
// CommonJS module is defined
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
module.exports = factory(require('jquery'));
|
||||
}
|
||||
// AMD module is defined
|
||||
else if (typeof define === 'function' && define.amd) {
|
||||
define(['jquery'], function ($) {
|
||||
return factory ($);
|
||||
});
|
||||
} else {
|
||||
factory(root.jQuery);
|
||||
}
|
||||
|
||||
}(this, function ($) {
|
||||
|
||||
'use strict';
|
||||
// jshint laxcomma: true
|
||||
|
||||
|
||||
/* TYPEAHEAD PUBLIC CLASS DEFINITION
|
||||
* ================================= */
|
||||
|
||||
var Typeahead = function (element, options) {
|
||||
this.$element = $(element);
|
||||
this.options = $.extend({}, $.fn.typeahead.defaults, options);
|
||||
this.matcher = this.options.matcher || this.matcher;
|
||||
this.sorter = this.options.sorter || this.sorter;
|
||||
this.select = this.options.select || this.select;
|
||||
this.autoSelect = typeof this.options.autoSelect == 'boolean' ? this.options.autoSelect : true;
|
||||
this.highlighter = this.options.highlighter || this.highlighter;
|
||||
this.render = this.options.render || this.render;
|
||||
this.updater = this.options.updater || this.updater;
|
||||
this.displayText = this.options.displayText || this.displayText;
|
||||
this.source = this.options.source;
|
||||
this.delay = this.options.delay;
|
||||
this.$menu = $(this.options.menu);
|
||||
this.$appendTo = this.options.appendTo ? $(this.options.appendTo) : null;
|
||||
this.fitToElement = typeof this.options.fitToElement == 'boolean' ? this.options.fitToElement : false;
|
||||
this.shown = false;
|
||||
this.listen();
|
||||
this.showHintOnFocus = typeof this.options.showHintOnFocus == 'boolean' || this.options.showHintOnFocus === "all" ? this.options.showHintOnFocus : false;
|
||||
this.afterSelect = this.options.afterSelect;
|
||||
this.addItem = false;
|
||||
this.value = this.$element.val() || this.$element.text();
|
||||
};
|
||||
|
||||
Typeahead.prototype = {
|
||||
|
||||
constructor: Typeahead,
|
||||
|
||||
select: function () {
|
||||
var val = this.$menu.find('.active').data('value');
|
||||
this.$element.data('active', val);
|
||||
if (this.autoSelect || val) {
|
||||
var newVal = this.updater(val);
|
||||
// Updater can be set to any random functions via "options" parameter in constructor above.
|
||||
// Add null check for cases when updater returns void or undefined.
|
||||
if (!newVal) {
|
||||
newVal = '';
|
||||
}
|
||||
this.$element
|
||||
.val(this.displayText(newVal) || newVal)
|
||||
.text(this.displayText(newVal) || newVal)
|
||||
.change();
|
||||
this.afterSelect(newVal);
|
||||
}
|
||||
return this.hide();
|
||||
},
|
||||
|
||||
updater: function (item) {
|
||||
return item;
|
||||
},
|
||||
|
||||
setSource: function (source) {
|
||||
this.source = source;
|
||||
},
|
||||
|
||||
show: function () {
|
||||
var pos = $.extend({}, this.$element.position(), {
|
||||
height: this.$element[0].offsetHeight
|
||||
});
|
||||
|
||||
var scrollHeight = typeof this.options.scrollHeight == 'function' ?
|
||||
this.options.scrollHeight.call() :
|
||||
this.options.scrollHeight;
|
||||
|
||||
var element;
|
||||
if (this.shown) {
|
||||
element = this.$menu;
|
||||
} else if (this.$appendTo) {
|
||||
element = this.$menu.appendTo(this.$appendTo);
|
||||
this.hasSameParent = this.$appendTo.is(this.$element.parent());
|
||||
} else {
|
||||
element = this.$menu.insertAfter(this.$element);
|
||||
this.hasSameParent = true;
|
||||
}
|
||||
|
||||
if (!this.hasSameParent) {
|
||||
// We cannot rely on the element position, need to position relative to the window
|
||||
element.css("position", "fixed");
|
||||
var offset = this.$element.offset();
|
||||
pos.top = offset.top;
|
||||
pos.left = offset.left;
|
||||
}
|
||||
// The rules for bootstrap are: 'dropup' in the parent and 'dropdown-menu-right' in the element.
|
||||
// Note that to get right alignment, you'll need to specify `menu` in the options to be:
|
||||
// '<ul class="typeahead dropdown-menu" role="listbox"></ul>'
|
||||
var dropup = $(element).parent().hasClass('dropup');
|
||||
var newTop = dropup ? 'auto' : (pos.top + pos.height + scrollHeight);
|
||||
var right = $(element).hasClass('dropdown-menu-right');
|
||||
var newLeft = right ? 'auto' : pos.left;
|
||||
// it seems like setting the css is a bad idea (just let Bootstrap do it), but I'll keep the old
|
||||
// logic in place except for the dropup/right-align cases.
|
||||
element.css({ top: newTop, left: newLeft }).show();
|
||||
|
||||
if (this.options.fitToElement === true) {
|
||||
element.css("width", this.$element.outerWidth() + "px");
|
||||
}
|
||||
|
||||
this.shown = true;
|
||||
return this;
|
||||
},
|
||||
|
||||
hide: function () {
|
||||
this.$menu.hide();
|
||||
this.shown = false;
|
||||
return this;
|
||||
},
|
||||
|
||||
lookup: function (query) {
|
||||
var items;
|
||||
if (typeof(query) != 'undefined' && query !== null) {
|
||||
this.query = query;
|
||||
} else {
|
||||
this.query = this.$element.val() || this.$element.text() || '';
|
||||
}
|
||||
|
||||
if (this.query.length < this.options.minLength && !this.options.showHintOnFocus) {
|
||||
return this.shown ? this.hide() : this;
|
||||
}
|
||||
|
||||
var worker = $.proxy(function () {
|
||||
|
||||
if ($.isFunction(this.source)) {
|
||||
this.source(this.query, $.proxy(this.process, this));
|
||||
} else if (this.source) {
|
||||
this.process(this.source);
|
||||
}
|
||||
}, this);
|
||||
|
||||
clearTimeout(this.lookupWorker);
|
||||
this.lookupWorker = setTimeout(worker, this.delay);
|
||||
},
|
||||
|
||||
process: function (items) {
|
||||
var that = this;
|
||||
|
||||
items = $.grep(items, function (item) {
|
||||
return that.matcher(item);
|
||||
});
|
||||
|
||||
items = this.sorter(items);
|
||||
|
||||
if (!items.length && !this.options.addItem) {
|
||||
return this.shown ? this.hide() : this;
|
||||
}
|
||||
|
||||
if (items.length > 0) {
|
||||
this.$element.data('active', items[0]);
|
||||
} else {
|
||||
this.$element.data('active', null);
|
||||
}
|
||||
|
||||
// Add item
|
||||
if (this.options.addItem){
|
||||
items.push(this.options.addItem);
|
||||
}
|
||||
|
||||
if (this.options.items == 'all') {
|
||||
return this.render(items).show();
|
||||
} else {
|
||||
return this.render(items.slice(0, this.options.items)).show();
|
||||
}
|
||||
},
|
||||
|
||||
matcher: function (item) {
|
||||
var it = this.displayText(item);
|
||||
return ~it.toLowerCase().indexOf(this.query.toLowerCase());
|
||||
},
|
||||
|
||||
sorter: function (items) {
|
||||
var beginswith = [];
|
||||
var caseSensitive = [];
|
||||
var caseInsensitive = [];
|
||||
var item;
|
||||
|
||||
while ((item = items.shift())) {
|
||||
var it = this.displayText(item);
|
||||
if (!it.toLowerCase().indexOf(this.query.toLowerCase())) beginswith.push(item);
|
||||
else if (~it.indexOf(this.query)) caseSensitive.push(item);
|
||||
else caseInsensitive.push(item);
|
||||
}
|
||||
|
||||
return beginswith.concat(caseSensitive, caseInsensitive);
|
||||
},
|
||||
|
||||
highlighter: function (item) {
|
||||
var html = $('<div></div>');
|
||||
var query = this.query;
|
||||
var i = item.toLowerCase().indexOf(query.toLowerCase());
|
||||
var len = query.length;
|
||||
var leftPart;
|
||||
var middlePart;
|
||||
var rightPart;
|
||||
var strong;
|
||||
if (len === 0) {
|
||||
return html.text(item).html();
|
||||
}
|
||||
while (i > -1) {
|
||||
leftPart = item.substr(0, i);
|
||||
middlePart = item.substr(i, len);
|
||||
rightPart = item.substr(i + len);
|
||||
strong = $('<strong></strong>').text(middlePart);
|
||||
html
|
||||
.append(document.createTextNode(leftPart))
|
||||
.append(strong);
|
||||
item = rightPart;
|
||||
i = item.toLowerCase().indexOf(query.toLowerCase());
|
||||
}
|
||||
return html.append(document.createTextNode(item)).html();
|
||||
},
|
||||
|
||||
render: function (items) {
|
||||
var that = this;
|
||||
var self = this;
|
||||
var activeFound = false;
|
||||
var data = [];
|
||||
var _category = that.options.separator;
|
||||
|
||||
$.each(items, function (key,value) {
|
||||
// inject separator
|
||||
if (key > 0 && value[_category] !== items[key - 1][_category]){
|
||||
data.push({
|
||||
__type: 'divider'
|
||||
});
|
||||
}
|
||||
|
||||
// inject category header
|
||||
if (value[_category] && (key === 0 || value[_category] !== items[key - 1][_category])){
|
||||
data.push({
|
||||
__type: 'category',
|
||||
name: value[_category]
|
||||
});
|
||||
}
|
||||
data.push(value);
|
||||
});
|
||||
|
||||
items = $(data).map(function (i, item) {
|
||||
if ((item.__type || false) == 'category'){
|
||||
return $(that.options.headerHtml).text(item.name)[0];
|
||||
}
|
||||
|
||||
if ((item.__type || false) == 'divider'){
|
||||
return $(that.options.headerDivider)[0];
|
||||
}
|
||||
|
||||
var text = self.displayText(item);
|
||||
i = $(that.options.item).data('value', item);
|
||||
i.find('a').html(that.highlighter(text, item));
|
||||
if (text == self.$element.val()) {
|
||||
i.addClass('active');
|
||||
self.$element.data('active', item);
|
||||
activeFound = true;
|
||||
}
|
||||
return i[0];
|
||||
});
|
||||
|
||||
if (this.autoSelect && !activeFound) {
|
||||
items.filter(':not(.dropdown-header)').first().addClass('active');
|
||||
this.$element.data('active', items.first().data('value'));
|
||||
}
|
||||
this.$menu.html(items);
|
||||
return this;
|
||||
},
|
||||
|
||||
displayText: function (item) {
|
||||
return typeof item !== 'undefined' && typeof item.name != 'undefined' && item.name || item;
|
||||
},
|
||||
|
||||
next: function (event) {
|
||||
var active = this.$menu.find('.active').removeClass('active');
|
||||
var next = active.next();
|
||||
|
||||
if (!next.length) {
|
||||
next = $(this.$menu.find('li')[0]);
|
||||
}
|
||||
|
||||
next.addClass('active');
|
||||
},
|
||||
|
||||
prev: function (event) {
|
||||
var active = this.$menu.find('.active').removeClass('active');
|
||||
var prev = active.prev();
|
||||
|
||||
if (!prev.length) {
|
||||
prev = this.$menu.find('li').last();
|
||||
}
|
||||
|
||||
prev.addClass('active');
|
||||
},
|
||||
|
||||
listen: function () {
|
||||
this.$element
|
||||
.on('focus', $.proxy(this.focus, this))
|
||||
.on('blur', $.proxy(this.blur, this))
|
||||
.on('keypress', $.proxy(this.keypress, this))
|
||||
.on('input', $.proxy(this.input, this))
|
||||
.on('keyup', $.proxy(this.keyup, this));
|
||||
|
||||
if (this.eventSupported('keydown')) {
|
||||
this.$element.on('keydown', $.proxy(this.keydown, this));
|
||||
}
|
||||
|
||||
this.$menu
|
||||
.on('click', $.proxy(this.click, this))
|
||||
.on('mouseenter', 'li', $.proxy(this.mouseenter, this))
|
||||
.on('mouseleave', 'li', $.proxy(this.mouseleave, this))
|
||||
.on('mousedown', $.proxy(this.mousedown,this));
|
||||
},
|
||||
|
||||
destroy : function () {
|
||||
this.$element.data('typeahead',null);
|
||||
this.$element.data('active',null);
|
||||
this.$element
|
||||
.off('focus')
|
||||
.off('blur')
|
||||
.off('keypress')
|
||||
.off('input')
|
||||
.off('keyup');
|
||||
|
||||
if (this.eventSupported('keydown')) {
|
||||
this.$element.off('keydown');
|
||||
}
|
||||
|
||||
this.$menu.remove();
|
||||
this.destroyed = true;
|
||||
},
|
||||
|
||||
eventSupported: function (eventName) {
|
||||
var isSupported = eventName in this.$element;
|
||||
if (!isSupported) {
|
||||
this.$element.setAttribute(eventName, 'return;');
|
||||
isSupported = typeof this.$element[eventName] === 'function';
|
||||
}
|
||||
return isSupported;
|
||||
},
|
||||
|
||||
move: function (e) {
|
||||
if (!this.shown) return;
|
||||
|
||||
switch (e.keyCode) {
|
||||
case 9: // tab
|
||||
case 13: // enter
|
||||
case 27: // escape
|
||||
e.preventDefault();
|
||||
break;
|
||||
|
||||
case 38: // up arrow
|
||||
// with the shiftKey (this is actually the left parenthesis)
|
||||
if (e.shiftKey) return;
|
||||
e.preventDefault();
|
||||
this.prev();
|
||||
break;
|
||||
|
||||
case 40: // down arrow
|
||||
// with the shiftKey (this is actually the right parenthesis)
|
||||
if (e.shiftKey) return;
|
||||
e.preventDefault();
|
||||
this.next();
|
||||
break;
|
||||
}
|
||||
},
|
||||
|
||||
keydown: function (e) {
|
||||
this.suppressKeyPressRepeat = ~$.inArray(e.keyCode, [40,38,9,13,27]);
|
||||
if (!this.shown && e.keyCode == 40) {
|
||||
this.lookup();
|
||||
} else {
|
||||
this.move(e);
|
||||
}
|
||||
},
|
||||
|
||||
keypress: function (e) {
|
||||
if (this.suppressKeyPressRepeat) return;
|
||||
this.move(e);
|
||||
},
|
||||
|
||||
input: function (e) {
|
||||
// This is a fixed for IE10/11 that fires the input event when a placehoder is changed
|
||||
// (https://connect.microsoft.com/IE/feedback/details/810538/ie-11-fires-input-event-on-focus)
|
||||
var currentValue = this.$element.val() || this.$element.text();
|
||||
if (this.value !== currentValue) {
|
||||
this.value = currentValue;
|
||||
this.lookup();
|
||||
}
|
||||
},
|
||||
|
||||
keyup: function (e) {
|
||||
if (this.destroyed) {
|
||||
return;
|
||||
}
|
||||
switch (e.keyCode) {
|
||||
case 40: // down arrow
|
||||
case 38: // up arrow
|
||||
case 16: // shift
|
||||
case 17: // ctrl
|
||||
case 18: // alt
|
||||
break;
|
||||
|
||||
case 9: // tab
|
||||
case 13: // enter
|
||||
if (!this.shown) return;
|
||||
this.select();
|
||||
break;
|
||||
|
||||
case 27: // escape
|
||||
if (!this.shown) return;
|
||||
this.hide();
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
},
|
||||
|
||||
focus: function (e) {
|
||||
if (!this.focused) {
|
||||
this.focused = true;
|
||||
if (this.options.showHintOnFocus && this.skipShowHintOnFocus !== true) {
|
||||
if(this.options.showHintOnFocus === "all") {
|
||||
this.lookup("");
|
||||
} else {
|
||||
this.lookup();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.skipShowHintOnFocus) {
|
||||
this.skipShowHintOnFocus = false;
|
||||
}
|
||||
},
|
||||
|
||||
blur: function (e) {
|
||||
if (!this.mousedover && !this.mouseddown && this.shown) {
|
||||
this.hide();
|
||||
this.focused = false;
|
||||
} else if (this.mouseddown) {
|
||||
// This is for IE that blurs the input when user clicks on scroll.
|
||||
// We set the focus back on the input and prevent the lookup to occur again
|
||||
this.skipShowHintOnFocus = true;
|
||||
this.$element.focus();
|
||||
this.mouseddown = false;
|
||||
}
|
||||
},
|
||||
|
||||
click: function (e) {
|
||||
e.preventDefault();
|
||||
this.skipShowHintOnFocus = true;
|
||||
this.select();
|
||||
this.$element.focus();
|
||||
this.hide();
|
||||
},
|
||||
|
||||
mouseenter: function (e) {
|
||||
this.mousedover = true;
|
||||
this.$menu.find('.active').removeClass('active');
|
||||
$(e.currentTarget).addClass('active');
|
||||
},
|
||||
|
||||
mouseleave: function (e) {
|
||||
this.mousedover = false;
|
||||
if (!this.focused && this.shown) this.hide();
|
||||
},
|
||||
|
||||
/**
|
||||
* We track the mousedown for IE. When clicking on the menu scrollbar, IE makes the input blur thus hiding the menu.
|
||||
*/
|
||||
mousedown: function (e) {
|
||||
this.mouseddown = true;
|
||||
this.$menu.one("mouseup", function(e){
|
||||
// IE won't fire this, but FF and Chrome will so we reset our flag for them here
|
||||
this.mouseddown = false;
|
||||
}.bind(this));
|
||||
},
|
||||
|
||||
};
|
||||
|
||||
|
||||
/* TYPEAHEAD PLUGIN DEFINITION
|
||||
* =========================== */
|
||||
|
||||
var old = $.fn.typeahead;
|
||||
|
||||
$.fn.typeahead = function (option) {
|
||||
var arg = arguments;
|
||||
if (typeof option == 'string' && option == 'getActive') {
|
||||
return this.data('active');
|
||||
}
|
||||
return this.each(function () {
|
||||
var $this = $(this);
|
||||
var data = $this.data('typeahead');
|
||||
var options = typeof option == 'object' && option;
|
||||
if (!data) $this.data('typeahead', (data = new Typeahead(this, options)));
|
||||
if (typeof option == 'string' && data[option]) {
|
||||
if (arg.length > 1) {
|
||||
data[option].apply(data, Array.prototype.slice.call(arg, 1));
|
||||
} else {
|
||||
data[option]();
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
$.fn.typeahead.defaults = {
|
||||
source: [],
|
||||
items: 8,
|
||||
menu: '<ul class="typeahead dropdown-menu" role="listbox"></ul>',
|
||||
item: '<li><a class="dropdown-item" href="#" role="option"></a></li>',
|
||||
minLength: 1,
|
||||
scrollHeight: 0,
|
||||
autoSelect: true,
|
||||
afterSelect: $.noop,
|
||||
addItem: false,
|
||||
delay: 0,
|
||||
separator: 'category',
|
||||
headerHtml: '<li class="dropdown-header"></li>',
|
||||
headerDivider: '<li class="divider" role="separator"></li>'
|
||||
};
|
||||
|
||||
$.fn.typeahead.Constructor = Typeahead;
|
||||
|
||||
/* TYPEAHEAD NO CONFLICT
|
||||
* =================== */
|
||||
|
||||
$.fn.typeahead.noConflict = function () {
|
||||
$.fn.typeahead = old;
|
||||
return this;
|
||||
};
|
||||
|
||||
|
||||
/* TYPEAHEAD DATA-API
|
||||
* ================== */
|
||||
|
||||
$(document).on('focus.typeahead.data-api', '[data-provide="typeahead"]', function (e) {
|
||||
var $this = $(this);
|
||||
if ($this.data('typeahead')) return;
|
||||
$this.typeahead($this.data());
|
||||
});
|
||||
|
||||
}));
|
228
dist/glify-browser.js
vendored
Normal file
1
dist/glify-browser.js.map
vendored
Normal file
2
dist/jquery/jquery-3.6.0.min.js
vendored
Normal file
1
dist/leaflet-fullscreen/Leaflet.fullscreen.min.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
L.Control.Fullscreen=L.Control.extend({options:{position:"topleft",title:{"false":"View Fullscreen","true":"Exit Fullscreen"}},onAdd:function(map){var container=L.DomUtil.create("div","leaflet-control-fullscreen leaflet-bar leaflet-control");this.link=L.DomUtil.create("a","leaflet-control-fullscreen-button leaflet-bar-part",container);this.link.href="#";this._map=map;this._map.on("fullscreenchange",this._toggleTitle,this);this._toggleTitle();L.DomEvent.on(this.link,"click",this._click,this);return container},_click:function(e){L.DomEvent.stopPropagation(e);L.DomEvent.preventDefault(e);this._map.toggleFullscreen(this.options)},_toggleTitle:function(){this.link.title=this.options.title[this._map.isFullscreen()]}});L.Map.include({isFullscreen:function(){return this._isFullscreen||false},toggleFullscreen:function(options){var container=this.getContainer();if(this.isFullscreen()){if(options&&options.pseudoFullscreen){this._disablePseudoFullscreen(container)}else if(document.exitFullscreen){document.exitFullscreen()}else if(document.mozCancelFullScreen){document.mozCancelFullScreen()}else if(document.webkitCancelFullScreen){document.webkitCancelFullScreen()}else if(document.msExitFullscreen){document.msExitFullscreen()}else{this._disablePseudoFullscreen(container)}}else{if(options&&options.pseudoFullscreen){this._enablePseudoFullscreen(container)}else if(container.requestFullscreen){container.requestFullscreen()}else if(container.mozRequestFullScreen){container.mozRequestFullScreen()}else if(container.webkitRequestFullscreen){container.webkitRequestFullscreen(Element.ALLOW_KEYBOARD_INPUT)}else if(container.msRequestFullscreen){container.msRequestFullscreen()}else{this._enablePseudoFullscreen(container)}}},_enablePseudoFullscreen:function(container){L.DomUtil.addClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(true);this.invalidateSize();this.fire("fullscreenchange")},_disablePseudoFullscreen:function(container){L.DomUtil.removeClass(container,"leaflet-pseudo-fullscreen");this._setFullscreen(false);this.invalidateSize();this.fire("fullscreenchange")},_setFullscreen:function(fullscreen){this._isFullscreen=fullscreen;var container=this.getContainer();if(fullscreen){L.DomUtil.addClass(container,"leaflet-fullscreen-on")}else{L.DomUtil.removeClass(container,"leaflet-fullscreen-on")}},_onFullscreenChange:function(e){var fullscreenElement=document.fullscreenElement||document.mozFullScreenElement||document.webkitFullscreenElement||document.msFullscreenElement;if(fullscreenElement===this.getContainer()&&!this._isFullscreen){this._setFullscreen(true);this.fire("fullscreenchange")}else if(fullscreenElement!==this.getContainer()&&this._isFullscreen){this._setFullscreen(false);this.fire("fullscreenchange")}}});L.Map.mergeOptions({fullscreenControl:false});L.Map.addInitHook(function(){if(this.options.fullscreenControl){this.fullscreenControl=new L.Control.Fullscreen(this.options.fullscreenControl);this.addControl(this.fullscreenControl)}var fullscreenchange;if("onfullscreenchange"in document){fullscreenchange="fullscreenchange"}else if("onmozfullscreenchange"in document){fullscreenchange="mozfullscreenchange"}else if("onwebkitfullscreenchange"in document){fullscreenchange="webkitfullscreenchange"}else if("onmsfullscreenchange"in document){fullscreenchange="MSFullscreenChange"}if(fullscreenchange){var onFullscreenChange=L.bind(this._onFullscreenChange,this);this.whenReady(function(){L.DomEvent.on(document,fullscreenchange,onFullscreenChange)});this.on("unload",function(){L.DomEvent.off(document,fullscreenchange,onFullscreenChange)})}});L.control.fullscreen=function(options){return new L.Control.Fullscreen(options)};
|
BIN
dist/leaflet-fullscreen/fullscreen.png
vendored
Normal file
After Width: | Height: | Size: 299 B |
BIN
dist/leaflet-fullscreen/fullscreen@2x.png
vendored
Normal file
After Width: | Height: | Size: 420 B |
40
dist/leaflet-fullscreen/leaflet.fullscreen.css
vendored
Normal file
@ -0,0 +1,40 @@
|
||||
.leaflet-control-fullscreen a {
|
||||
background:#fff url(fullscreen.png) no-repeat 0 0;
|
||||
background-size:26px 52px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-fullscreen a {
|
||||
background-position: 2px 2px;
|
||||
}
|
||||
.leaflet-fullscreen-on .leaflet-control-fullscreen a {
|
||||
background-position:0 -26px;
|
||||
}
|
||||
.leaflet-touch.leaflet-fullscreen-on .leaflet-control-fullscreen a {
|
||||
background-position: 2px -24px;
|
||||
}
|
||||
|
||||
/* Do not combine these two rules; IE will break. */
|
||||
.leaflet-container:-webkit-full-screen {
|
||||
width:100%!important;
|
||||
height:100%!important;
|
||||
}
|
||||
.leaflet-container.leaflet-fullscreen-on {
|
||||
width:100%!important;
|
||||
height:100%!important;
|
||||
}
|
||||
|
||||
.leaflet-pseudo-fullscreen {
|
||||
position:fixed!important;
|
||||
width:100%!important;
|
||||
height:100%!important;
|
||||
top:0!important;
|
||||
left:0!important;
|
||||
z-index:99999;
|
||||
}
|
||||
|
||||
@media
|
||||
(-webkit-min-device-pixel-ratio:2),
|
||||
(min-resolution:192dpi) {
|
||||
.leaflet-control-fullscreen a {
|
||||
background-image:url(fullscreen@2x.png);
|
||||
}
|
||||
}
|
2
dist/leaflet-locatecontrol/L.Control.Locate.min.css
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
.leaflet-control-locate a{font-size:1.4em;color:#444;cursor:pointer}.leaflet-control-locate.active a{color:#2074b6}.leaflet-control-locate.active.following a{color:#fc8428}.leaflet-control-locate-location circle{animation:leaflet-control-locate-throb 4s ease infinite}@keyframes leaflet-control-locate-throb{0%{stroke-width:1}50%{stroke-width:3;transform:scale(0.8, 0.8)}100%{stroke-width:1}}
|
||||
/*# sourceMappingURL=L.Control.Locate.min.css.map */
|
5
dist/leaflet-locatecontrol/L.Control.Locate.min.js
vendored
Normal file
1
dist/leaflet-pixi-overlay/L.PixiOverlay.min.js
vendored
Normal file
148
dist/leaflet-terminator/L.Terminator.js
vendored
Normal file
@ -0,0 +1,148 @@
|
||||
(function (global, factory) {
|
||||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('leaflet')) :
|
||||
typeof define === 'function' && define.amd ? define(['leaflet'], factory) :
|
||||
(global.L = global.L || {}, global.L.terminator = factory(global.L));
|
||||
}(this, (function (L) { 'use strict';
|
||||
|
||||
L = L && L.hasOwnProperty('default') ? L['default'] : L;
|
||||
|
||||
/* Terminator.js -- Overlay day/night region on a Leaflet map */
|
||||
|
||||
function julian(date) {
|
||||
/* Calculate the present UTC Julian Date. Function is valid after
|
||||
* the beginning of the UNIX epoch 1970-01-01 and ignores leap
|
||||
* seconds. */
|
||||
return (date / 86400000) + 2440587.5;
|
||||
}
|
||||
|
||||
function GMST(julianDay) {
|
||||
/* Calculate Greenwich Mean Sidereal Time according to
|
||||
http://aa.usno.navy.mil/faq/docs/GAST.php */
|
||||
var d = julianDay - 2451545.0;
|
||||
// Low precision equation is good enough for our purposes.
|
||||
return (18.697374558 + 24.06570982441908 * d) % 24;
|
||||
}
|
||||
|
||||
var Terminator = L.Polygon.extend({
|
||||
options: {
|
||||
color: '#00',
|
||||
opacity: 0.5,
|
||||
fillColor: '#00',
|
||||
fillOpacity: 0.5,
|
||||
resolution: 2
|
||||
},
|
||||
|
||||
initialize: function (options) {
|
||||
this.version = '0.1.0';
|
||||
this._R2D = 180 / Math.PI;
|
||||
this._D2R = Math.PI / 180;
|
||||
L.Util.setOptions(this, options);
|
||||
var latLng = this._compute(this.options.time);
|
||||
this.setLatLngs(latLng);
|
||||
},
|
||||
|
||||
setTime: function (date) {
|
||||
this.options.time = date;
|
||||
var latLng = this._compute(date);
|
||||
this.setLatLngs(latLng);
|
||||
},
|
||||
|
||||
_sunEclipticPosition: function (julianDay) {
|
||||
/* Compute the position of the Sun in ecliptic coordinates at
|
||||
julianDay. Following
|
||||
http://en.wikipedia.org/wiki/Position_of_the_Sun */
|
||||
// Days since start of J2000.0
|
||||
var n = julianDay - 2451545.0;
|
||||
// mean longitude of the Sun
|
||||
var L$$1 = 280.460 + 0.9856474 * n;
|
||||
L$$1 %= 360;
|
||||
// mean anomaly of the Sun
|
||||
var g = 357.528 + 0.9856003 * n;
|
||||
g %= 360;
|
||||
// ecliptic longitude of Sun
|
||||
var lambda = L$$1 + 1.915 * Math.sin(g * this._D2R) +
|
||||
0.02 * Math.sin(2 * g * this._D2R);
|
||||
// distance from Sun in AU
|
||||
var R = 1.00014 - 0.01671 * Math.cos(g * this._D2R) -
|
||||
0.0014 * Math.cos(2 * g * this._D2R);
|
||||
return {lambda: lambda, R: R};
|
||||
},
|
||||
|
||||
_eclipticObliquity: function (julianDay) {
|
||||
// Following the short term expression in
|
||||
// http://en.wikipedia.org/wiki/Axial_tilt#Obliquity_of_the_ecliptic_.28Earth.27s_axial_tilt.29
|
||||
var n = julianDay - 2451545.0;
|
||||
// Julian centuries since J2000.0
|
||||
var T = n / 36525;
|
||||
var epsilon = 23.43929111 -
|
||||
T * (46.836769 / 3600
|
||||
- T * (0.0001831 / 3600
|
||||
+ T * (0.00200340 / 3600
|
||||
- T * (0.576e-6 / 3600
|
||||
- T * 4.34e-8 / 3600))));
|
||||
return epsilon;
|
||||
},
|
||||
|
||||
_sunEquatorialPosition: function (sunEclLng, eclObliq) {
|
||||
/* Compute the Sun's equatorial position from its ecliptic
|
||||
* position. Inputs are expected in degrees. Outputs are in
|
||||
* degrees as well. */
|
||||
var alpha = Math.atan(Math.cos(eclObliq * this._D2R)
|
||||
* Math.tan(sunEclLng * this._D2R)) * this._R2D;
|
||||
var delta = Math.asin(Math.sin(eclObliq * this._D2R)
|
||||
* Math.sin(sunEclLng * this._D2R)) * this._R2D;
|
||||
|
||||
var lQuadrant = Math.floor(sunEclLng / 90) * 90;
|
||||
var raQuadrant = Math.floor(alpha / 90) * 90;
|
||||
alpha = alpha + (lQuadrant - raQuadrant);
|
||||
|
||||
return {alpha: alpha, delta: delta};
|
||||
},
|
||||
|
||||
_hourAngle: function (lng, sunPos, gst) {
|
||||
/* Compute the hour angle of the sun for a longitude on
|
||||
* Earth. Return the hour angle in degrees. */
|
||||
var lst = gst + lng / 15;
|
||||
return lst * 15 - sunPos.alpha;
|
||||
},
|
||||
|
||||
_latitude: function (ha, sunPos) {
|
||||
/* For a given hour angle and sun position, compute the
|
||||
* latitude of the terminator in degrees. */
|
||||
var lat = Math.atan(-Math.cos(ha * this._D2R) /
|
||||
Math.tan(sunPos.delta * this._D2R)) * this._R2D;
|
||||
return lat;
|
||||
},
|
||||
|
||||
_compute: function (time) {
|
||||
var today = time ? new Date(time) : new Date();
|
||||
var julianDay = julian(today);
|
||||
var gst = GMST(julianDay);
|
||||
var latLng = [];
|
||||
|
||||
var sunEclPos = this._sunEclipticPosition(julianDay);
|
||||
var eclObliq = this._eclipticObliquity(julianDay);
|
||||
var sunEqPos = this._sunEquatorialPosition(sunEclPos.lambda, eclObliq);
|
||||
for (var i = 0; i <= 720 * this.options.resolution; i++) {
|
||||
var lng = -360 + i / this.options.resolution;
|
||||
var ha = this._hourAngle(lng, sunEqPos, gst);
|
||||
latLng[i + 1] = [this._latitude(ha, sunEqPos), lng];
|
||||
}
|
||||
if (sunEqPos.delta < 0) {
|
||||
latLng[0] = [90, -360];
|
||||
latLng[latLng.length] = [90, 360];
|
||||
} else {
|
||||
latLng[0] = [-90, -360];
|
||||
latLng[latLng.length] = [-90, 360];
|
||||
}
|
||||
return latLng;
|
||||
}
|
||||
});
|
||||
|
||||
function terminator(options) {
|
||||
return new Terminator(options);
|
||||
}
|
||||
|
||||
return terminator;
|
||||
|
||||
})));
|
640
dist/leaflet/leaflet.css
vendored
Normal file
@ -0,0 +1,640 @@
|
||||
/* required styles */
|
||||
|
||||
.leaflet-pane,
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-tile-container,
|
||||
.leaflet-pane > svg,
|
||||
.leaflet-pane > canvas,
|
||||
.leaflet-zoom-box,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-layer {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-container {
|
||||
overflow: hidden;
|
||||
}
|
||||
.leaflet-tile,
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
user-select: none;
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
/* Prevents IE11 from highlighting tiles in blue */
|
||||
.leaflet-tile::selection {
|
||||
background: transparent;
|
||||
}
|
||||
/* Safari renders non-retina tile on retina better with this, but Chrome is worse */
|
||||
.leaflet-safari .leaflet-tile {
|
||||
image-rendering: -webkit-optimize-contrast;
|
||||
}
|
||||
/* hack that prevents hw layers "stretching" when loading new tiles */
|
||||
.leaflet-safari .leaflet-tile-container {
|
||||
width: 1600px;
|
||||
height: 1600px;
|
||||
-webkit-transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow {
|
||||
display: block;
|
||||
}
|
||||
/* .leaflet-container svg: reset svg max-width decleration shipped in Joomla! (joomla.org) 3.x */
|
||||
/* .leaflet-container img: map is broken in FF if you have max-width: 100% on tiles */
|
||||
.leaflet-container .leaflet-overlay-pane svg,
|
||||
.leaflet-container .leaflet-marker-pane img,
|
||||
.leaflet-container .leaflet-shadow-pane img,
|
||||
.leaflet-container .leaflet-tile-pane img,
|
||||
.leaflet-container img.leaflet-image-layer,
|
||||
.leaflet-container .leaflet-tile {
|
||||
max-width: none !important;
|
||||
max-height: none !important;
|
||||
}
|
||||
|
||||
.leaflet-container.leaflet-touch-zoom {
|
||||
-ms-touch-action: pan-x pan-y;
|
||||
touch-action: pan-x pan-y;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag {
|
||||
-ms-touch-action: pinch-zoom;
|
||||
/* Fallback for FF which doesn't support pinch-zoom */
|
||||
touch-action: none;
|
||||
touch-action: pinch-zoom;
|
||||
}
|
||||
.leaflet-container.leaflet-touch-drag.leaflet-touch-zoom {
|
||||
-ms-touch-action: none;
|
||||
touch-action: none;
|
||||
}
|
||||
.leaflet-container {
|
||||
-webkit-tap-highlight-color: transparent;
|
||||
}
|
||||
.leaflet-container a {
|
||||
-webkit-tap-highlight-color: rgba(51, 181, 229, 0.4);
|
||||
}
|
||||
.leaflet-tile {
|
||||
filter: inherit;
|
||||
visibility: hidden;
|
||||
}
|
||||
.leaflet-tile-loaded {
|
||||
visibility: inherit;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
width: 0;
|
||||
height: 0;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
z-index: 800;
|
||||
}
|
||||
/* workaround for https://bugzilla.mozilla.org/show_bug.cgi?id=888319 */
|
||||
.leaflet-overlay-pane svg {
|
||||
-moz-user-select: none;
|
||||
}
|
||||
|
||||
.leaflet-pane { z-index: 400; }
|
||||
|
||||
.leaflet-tile-pane { z-index: 200; }
|
||||
.leaflet-overlay-pane { z-index: 400; }
|
||||
.leaflet-shadow-pane { z-index: 500; }
|
||||
.leaflet-marker-pane { z-index: 600; }
|
||||
.leaflet-tooltip-pane { z-index: 650; }
|
||||
.leaflet-popup-pane { z-index: 700; }
|
||||
|
||||
.leaflet-map-pane canvas { z-index: 100; }
|
||||
.leaflet-map-pane svg { z-index: 200; }
|
||||
|
||||
.leaflet-vml-shape {
|
||||
width: 1px;
|
||||
height: 1px;
|
||||
}
|
||||
.lvml {
|
||||
behavior: url(#default#VML);
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
|
||||
/* control positioning */
|
||||
|
||||
.leaflet-control {
|
||||
position: relative;
|
||||
z-index: 800;
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-top,
|
||||
.leaflet-bottom {
|
||||
position: absolute;
|
||||
z-index: 1000;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-top {
|
||||
top: 0;
|
||||
}
|
||||
.leaflet-right {
|
||||
right: 0;
|
||||
}
|
||||
.leaflet-bottom {
|
||||
bottom: 0;
|
||||
}
|
||||
.leaflet-left {
|
||||
left: 0;
|
||||
}
|
||||
.leaflet-control {
|
||||
float: left;
|
||||
clear: both;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
float: right;
|
||||
}
|
||||
.leaflet-top .leaflet-control {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
.leaflet-left .leaflet-control {
|
||||
margin-left: 10px;
|
||||
}
|
||||
.leaflet-right .leaflet-control {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
||||
/* zoom and fade animations */
|
||||
|
||||
.leaflet-fade-anim .leaflet-tile {
|
||||
will-change: opacity;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-popup {
|
||||
opacity: 0;
|
||||
-webkit-transition: opacity 0.2s linear;
|
||||
-moz-transition: opacity 0.2s linear;
|
||||
transition: opacity 0.2s linear;
|
||||
}
|
||||
.leaflet-fade-anim .leaflet-map-pane .leaflet-popup {
|
||||
opacity: 1;
|
||||
}
|
||||
.leaflet-zoom-animated {
|
||||
-webkit-transform-origin: 0 0;
|
||||
-ms-transform-origin: 0 0;
|
||||
transform-origin: 0 0;
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
will-change: transform;
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-zoom-animated {
|
||||
-webkit-transition: -webkit-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
-moz-transition: -moz-transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
transition: transform 0.25s cubic-bezier(0,0,0.25,1);
|
||||
}
|
||||
.leaflet-zoom-anim .leaflet-tile,
|
||||
.leaflet-pan-anim .leaflet-tile {
|
||||
-webkit-transition: none;
|
||||
-moz-transition: none;
|
||||
transition: none;
|
||||
}
|
||||
|
||||
.leaflet-zoom-anim .leaflet-zoom-hide {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
|
||||
/* cursors */
|
||||
|
||||
.leaflet-interactive {
|
||||
cursor: pointer;
|
||||
}
|
||||
.leaflet-grab {
|
||||
cursor: -webkit-grab;
|
||||
cursor: -moz-grab;
|
||||
cursor: grab;
|
||||
}
|
||||
.leaflet-crosshair,
|
||||
.leaflet-crosshair .leaflet-interactive {
|
||||
cursor: crosshair;
|
||||
}
|
||||
.leaflet-popup-pane,
|
||||
.leaflet-control {
|
||||
cursor: auto;
|
||||
}
|
||||
.leaflet-dragging .leaflet-grab,
|
||||
.leaflet-dragging .leaflet-grab .leaflet-interactive,
|
||||
.leaflet-dragging .leaflet-marker-draggable {
|
||||
cursor: move;
|
||||
cursor: -webkit-grabbing;
|
||||
cursor: -moz-grabbing;
|
||||
cursor: grabbing;
|
||||
}
|
||||
|
||||
/* marker & overlays interactivity */
|
||||
.leaflet-marker-icon,
|
||||
.leaflet-marker-shadow,
|
||||
.leaflet-image-layer,
|
||||
.leaflet-pane > svg path,
|
||||
.leaflet-tile-container {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.leaflet-marker-icon.leaflet-interactive,
|
||||
.leaflet-image-layer.leaflet-interactive,
|
||||
.leaflet-pane > svg path.leaflet-interactive,
|
||||
svg.leaflet-image-layer.leaflet-interactive path {
|
||||
pointer-events: visiblePainted; /* IE 9-10 doesn't have auto */
|
||||
pointer-events: auto;
|
||||
}
|
||||
|
||||
/* visual tweaks */
|
||||
|
||||
.leaflet-container {
|
||||
background: #ddd;
|
||||
outline: 0;
|
||||
}
|
||||
.leaflet-container a {
|
||||
color: #0078A8;
|
||||
}
|
||||
.leaflet-container a.leaflet-active {
|
||||
outline: 2px solid orange;
|
||||
}
|
||||
.leaflet-zoom-box {
|
||||
border: 2px dotted #38f;
|
||||
background: rgba(255,255,255,0.5);
|
||||
}
|
||||
|
||||
|
||||
/* general typography */
|
||||
.leaflet-container {
|
||||
font: 12px/1.5 "Helvetica Neue", Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
|
||||
/* general toolbar styles */
|
||||
|
||||
.leaflet-bar {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.65);
|
||||
border-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #fff;
|
||||
border-bottom: 1px solid #ccc;
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
line-height: 26px;
|
||||
display: block;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
color: black;
|
||||
}
|
||||
.leaflet-bar a,
|
||||
.leaflet-control-layers-toggle {
|
||||
background-position: 50% 50%;
|
||||
background-repeat: no-repeat;
|
||||
display: block;
|
||||
}
|
||||
.leaflet-bar a:hover {
|
||||
background-color: #f4f4f4;
|
||||
}
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
border-bottom: none;
|
||||
}
|
||||
.leaflet-bar a.leaflet-disabled {
|
||||
cursor: default;
|
||||
background-color: #f4f4f4;
|
||||
color: #bbb;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-bar a {
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
line-height: 30px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:first-child {
|
||||
border-top-left-radius: 2px;
|
||||
border-top-right-radius: 2px;
|
||||
}
|
||||
.leaflet-touch .leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 2px;
|
||||
border-bottom-right-radius: 2px;
|
||||
}
|
||||
|
||||
/* zoom control */
|
||||
|
||||
.leaflet-control-zoom-in,
|
||||
.leaflet-control-zoom-out {
|
||||
font: bold 18px 'Lucida Console', Monaco, monospace;
|
||||
text-indent: 1px;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-zoom-in, .leaflet-touch .leaflet-control-zoom-out {
|
||||
font-size: 22px;
|
||||
}
|
||||
|
||||
|
||||
/* layers control */
|
||||
|
||||
.leaflet-control-layers {
|
||||
box-shadow: 0 1px 5px rgba(0,0,0,0.4);
|
||||
background: #fff;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers.png);
|
||||
width: 36px;
|
||||
height: 36px;
|
||||
}
|
||||
.leaflet-retina .leaflet-control-layers-toggle {
|
||||
background-image: url(images/layers-2x.png);
|
||||
background-size: 26px 26px;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers-toggle {
|
||||
width: 44px;
|
||||
height: 44px;
|
||||
}
|
||||
.leaflet-control-layers .leaflet-control-layers-list,
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-toggle {
|
||||
display: none;
|
||||
}
|
||||
.leaflet-control-layers-expanded .leaflet-control-layers-list {
|
||||
display: block;
|
||||
position: relative;
|
||||
}
|
||||
.leaflet-control-layers-expanded {
|
||||
padding: 6px 10px 6px 6px;
|
||||
color: #333;
|
||||
background: #fff;
|
||||
}
|
||||
.leaflet-control-layers-scrollbar {
|
||||
overflow-y: scroll;
|
||||
overflow-x: hidden;
|
||||
padding-right: 5px;
|
||||
}
|
||||
.leaflet-control-layers-selector {
|
||||
margin-top: 2px;
|
||||
position: relative;
|
||||
top: 1px;
|
||||
}
|
||||
.leaflet-control-layers label {
|
||||
display: block;
|
||||
}
|
||||
.leaflet-control-layers-separator {
|
||||
height: 0;
|
||||
border-top: 1px solid #ddd;
|
||||
margin: 5px -10px 5px -6px;
|
||||
}
|
||||
|
||||
/* Default icon URLs */
|
||||
.leaflet-default-icon-path {
|
||||
background-image: url(images/marker-icon.png);
|
||||
}
|
||||
|
||||
|
||||
/* attribution and scale controls */
|
||||
|
||||
.leaflet-container .leaflet-control-attribution {
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.7);
|
||||
margin: 0;
|
||||
}
|
||||
.leaflet-control-attribution,
|
||||
.leaflet-control-scale-line {
|
||||
padding: 0 5px;
|
||||
color: #333;
|
||||
}
|
||||
.leaflet-control-attribution a {
|
||||
text-decoration: none;
|
||||
}
|
||||
.leaflet-control-attribution a:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.leaflet-container .leaflet-control-attribution,
|
||||
.leaflet-container .leaflet-control-scale {
|
||||
font-size: 11px;
|
||||
}
|
||||
.leaflet-left .leaflet-control-scale {
|
||||
margin-left: 5px;
|
||||
}
|
||||
.leaflet-bottom .leaflet-control-scale {
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
.leaflet-control-scale-line {
|
||||
border: 2px solid #777;
|
||||
border-top: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
|
||||
background: #fff;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: 2px solid #777;
|
||||
border-bottom: none;
|
||||
margin-top: -2px;
|
||||
}
|
||||
.leaflet-control-scale-line:not(:first-child):not(:last-child) {
|
||||
border-bottom: 2px solid #777;
|
||||
}
|
||||
|
||||
.leaflet-touch .leaflet-control-attribution,
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
box-shadow: none;
|
||||
}
|
||||
.leaflet-touch .leaflet-control-layers,
|
||||
.leaflet-touch .leaflet-bar {
|
||||
border: 2px solid rgba(0,0,0,0.2);
|
||||
background-clip: padding-box;
|
||||
}
|
||||
|
||||
|
||||
/* popup */
|
||||
|
||||
.leaflet-popup {
|
||||
position: absolute;
|
||||
text-align: center;
|
||||
margin-bottom: 20px;
|
||||
}
|
||||
.leaflet-popup-content-wrapper {
|
||||
padding: 1px;
|
||||
text-align: left;
|
||||
border-radius: 12px;
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 13px 19px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
.leaflet-popup-content p {
|
||||
margin: 18px 0;
|
||||
}
|
||||
.leaflet-popup-tip-container {
|
||||
width: 40px;
|
||||
height: 20px;
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
margin-left: -20px;
|
||||
overflow: hidden;
|
||||
pointer-events: none;
|
||||
}
|
||||
.leaflet-popup-tip {
|
||||
width: 17px;
|
||||
height: 17px;
|
||||
padding: 1px;
|
||||
|
||||
margin: -10px auto 0;
|
||||
|
||||
-webkit-transform: rotate(45deg);
|
||||
-moz-transform: rotate(45deg);
|
||||
-ms-transform: rotate(45deg);
|
||||
transform: rotate(45deg);
|
||||
}
|
||||
.leaflet-popup-content-wrapper,
|
||||
.leaflet-popup-tip {
|
||||
background: white;
|
||||
color: #333;
|
||||
box-shadow: 0 3px 14px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
padding: 4px 4px 0 0;
|
||||
border: none;
|
||||
text-align: center;
|
||||
width: 18px;
|
||||
height: 14px;
|
||||
font: 16px/14px Tahoma, Verdana, sans-serif;
|
||||
color: #c3c3c3;
|
||||
text-decoration: none;
|
||||
font-weight: bold;
|
||||
background: transparent;
|
||||
}
|
||||
.leaflet-container a.leaflet-popup-close-button:hover {
|
||||
color: #999;
|
||||
}
|
||||
.leaflet-popup-scrolled {
|
||||
overflow: auto;
|
||||
border-bottom: 1px solid #ddd;
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper {
|
||||
-ms-zoom: 1;
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
width: 24px;
|
||||
margin: 0 auto;
|
||||
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678)";
|
||||
filter: progid:DXImageTransform.Microsoft.Matrix(M11=0.70710678, M12=0.70710678, M21=-0.70710678, M22=0.70710678);
|
||||
}
|
||||
.leaflet-oldie .leaflet-popup-tip-container {
|
||||
margin-top: -1px;
|
||||
}
|
||||
|
||||
.leaflet-oldie .leaflet-control-zoom,
|
||||
.leaflet-oldie .leaflet-control-layers,
|
||||
.leaflet-oldie .leaflet-popup-content-wrapper,
|
||||
.leaflet-oldie .leaflet-popup-tip {
|
||||
border: 1px solid #999;
|
||||
}
|
||||
|
||||
|
||||
/* div icon */
|
||||
|
||||
.leaflet-div-icon {
|
||||
background: #fff;
|
||||
border: 1px solid #666;
|
||||
}
|
||||
|
||||
|
||||
/* Tooltip */
|
||||
/* Base styles for the element that has a tooltip */
|
||||
.leaflet-tooltip {
|
||||
position: absolute;
|
||||
padding: 6px;
|
||||
background-color: #fff;
|
||||
border: 1px solid #fff;
|
||||
border-radius: 3px;
|
||||
color: #222;
|
||||
white-space: nowrap;
|
||||
-webkit-user-select: none;
|
||||
-moz-user-select: none;
|
||||
-ms-user-select: none;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
box-shadow: 0 1px 3px rgba(0,0,0,0.4);
|
||||
}
|
||||
.leaflet-tooltip.leaflet-clickable {
|
||||
cursor: pointer;
|
||||
pointer-events: auto;
|
||||
}
|
||||
.leaflet-tooltip-top:before,
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
position: absolute;
|
||||
pointer-events: none;
|
||||
border: 6px solid transparent;
|
||||
background: transparent;
|
||||
content: "";
|
||||
}
|
||||
|
||||
/* Directions */
|
||||
|
||||
.leaflet-tooltip-bottom {
|
||||
margin-top: 6px;
|
||||
}
|
||||
.leaflet-tooltip-top {
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before,
|
||||
.leaflet-tooltip-top:before {
|
||||
left: 50%;
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-top:before {
|
||||
bottom: 0;
|
||||
margin-bottom: -12px;
|
||||
border-top-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-bottom:before {
|
||||
top: 0;
|
||||
margin-top: -12px;
|
||||
margin-left: -6px;
|
||||
border-bottom-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-left {
|
||||
margin-left: -6px;
|
||||
}
|
||||
.leaflet-tooltip-right {
|
||||
margin-left: 6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before,
|
||||
.leaflet-tooltip-right:before {
|
||||
top: 50%;
|
||||
margin-top: -6px;
|
||||
}
|
||||
.leaflet-tooltip-left:before {
|
||||
right: 0;
|
||||
margin-right: -12px;
|
||||
border-left-color: #fff;
|
||||
}
|
||||
.leaflet-tooltip-right:before {
|
||||
left: 0;
|
||||
margin-left: -12px;
|
||||
border-right-color: #fff;
|
||||
}
|
6
dist/leaflet/leaflet.js
vendored
Normal file
1
dist/leaflet/leaflet.js.map
vendored
Normal file
55
dist/leaflet/touch-fix.js
vendored
Normal file
@ -0,0 +1,55 @@
|
||||
// FIX for mobile https://github.com/Leaflet/Leaflet/issues/1542
|
||||
L.Map.mergeOptions({
|
||||
touchExtend: true
|
||||
});
|
||||
|
||||
L.Map.TouchExtend = L.Handler.extend({
|
||||
|
||||
initialize: function (map) {
|
||||
this._map = map;
|
||||
this._container = map._container;
|
||||
this._pane = map._panes.overlayPane;
|
||||
},
|
||||
|
||||
addHooks: function () {
|
||||
L.DomEvent.on(this._container, 'touchstart', this._onTouchStart, this);
|
||||
L.DomEvent.on(this._container, 'touchend', this._onTouchEnd, this);
|
||||
},
|
||||
|
||||
removeHooks: function () {
|
||||
L.DomEvent.off(this._container, 'touchstart', this._onTouchStart);
|
||||
L.DomEvent.off(this._container, 'touchend', this._onTouchEnd);
|
||||
},
|
||||
|
||||
_onTouchStart: function (e) {
|
||||
if (!this._map._loaded) { return; }
|
||||
|
||||
var type = 'touchstart';
|
||||
|
||||
var containerPoint = this._map.mouseEventToContainerPoint(e),
|
||||
layerPoint = this._map.containerPointToLayerPoint(containerPoint),
|
||||
latlng = this._map.layerPointToLatLng(layerPoint);
|
||||
|
||||
this._map.fire(type, {
|
||||
latlng: latlng,
|
||||
layerPoint: layerPoint,
|
||||
containerPoint: containerPoint,
|
||||
originalEvent: e
|
||||
});
|
||||
},
|
||||
|
||||
_onTouchEnd: function (e) {
|
||||
if (!this._map._loaded) { return; }
|
||||
|
||||
var type = 'touchend';
|
||||
|
||||
this._map.fire(type, {
|
||||
originalEvent: e
|
||||
});
|
||||
}
|
||||
});
|
||||
L.Map.addInitHook('addHandler', 'touchExtend', L.Map.TouchExtend);
|
||||
|
||||
|
||||
|
||||
//
|
1545
dist/moment/moment-timezone-with-data.js
vendored
Normal file
2
dist/moment/moment-with-locales.min.js
vendored
Normal file
9
dist/pixi/pixi.min.js
vendored
Normal file
5
dist/popper/popper.min.js
vendored
Normal file
10576
dist/quill/quill.js
vendored
Normal file
899
dist/quill/quill.snow.css
vendored
Normal file
@ -0,0 +1,899 @@
|
||||
/*!
|
||||
* Quill Editor v1.1.9
|
||||
* https://quilljs.com/
|
||||
* Copyright (c) 2014, Jason Chen
|
||||
* Copyright (c) 2013, salesforce.com
|
||||
*/
|
||||
.ql-container {
|
||||
box-sizing: border-box;
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
height: 100%;
|
||||
margin: 0px;
|
||||
position: relative;
|
||||
}
|
||||
.ql-container.ql-disabled .ql-tooltip {
|
||||
visibility: hidden;
|
||||
}
|
||||
.ql-clipboard {
|
||||
left: -100000px;
|
||||
height: 1px;
|
||||
overflow-y: hidden;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
}
|
||||
.ql-clipboard p {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
.ql-editor {
|
||||
box-sizing: border-box;
|
||||
cursor: text;
|
||||
line-height: 1.42;
|
||||
height: 100%;
|
||||
outline: none;
|
||||
overflow-y: auto;
|
||||
padding: 12px 15px;
|
||||
tab-size: 4;
|
||||
-moz-tab-size: 4;
|
||||
text-align: left;
|
||||
white-space: pre-wrap;
|
||||
word-wrap: break-word;
|
||||
}
|
||||
.ql-editor p,
|
||||
.ql-editor ol,
|
||||
.ql-editor ul,
|
||||
.ql-editor pre,
|
||||
.ql-editor blockquote,
|
||||
.ql-editor h1,
|
||||
.ql-editor h2,
|
||||
.ql-editor h3,
|
||||
.ql-editor h4,
|
||||
.ql-editor h5,
|
||||
.ql-editor h6 {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
|
||||
}
|
||||
.ql-editor ol,
|
||||
.ql-editor ul {
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
.ql-editor ol > li,
|
||||
.ql-editor ul > li {
|
||||
list-style-type: none;
|
||||
}
|
||||
.ql-editor ul > li::before {
|
||||
content: '\25CF';
|
||||
}
|
||||
.ql-editor ul[data-checked=true] > li::before,
|
||||
.ql-editor ul[data-checked=false] > li::before {
|
||||
color: #777;
|
||||
cursor: pointer;
|
||||
}
|
||||
.ql-editor ul[data-checked=true] > li::before {
|
||||
content: '\2611';
|
||||
}
|
||||
.ql-editor ul[data-checked=false] > li::before {
|
||||
content: '\2610';
|
||||
}
|
||||
.ql-editor li::before {
|
||||
display: inline-block;
|
||||
margin-right: 0.3em;
|
||||
text-align: right;
|
||||
white-space: nowrap;
|
||||
width: 1.2em;
|
||||
}
|
||||
.ql-editor li:not(.ql-direction-rtl)::before {
|
||||
margin-left: -1.5em;
|
||||
}
|
||||
.ql-editor ol li,
|
||||
.ql-editor ul li {
|
||||
padding-left: 1.5em;
|
||||
}
|
||||
.ql-editor ol li {
|
||||
counter-reset: list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
|
||||
counter-increment: list-num;
|
||||
}
|
||||
.ql-editor ol li:before {
|
||||
content: counter(list-num, decimal) '. ';
|
||||
}
|
||||
.ql-editor ol li.ql-indent-1 {
|
||||
counter-increment: list-1;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-1:before {
|
||||
content: counter(list-1, lower-alpha) '. ';
|
||||
}
|
||||
.ql-editor ol li.ql-indent-1 {
|
||||
counter-reset: list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-2 {
|
||||
counter-increment: list-2;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-2:before {
|
||||
content: counter(list-2, lower-roman) '. ';
|
||||
}
|
||||
.ql-editor ol li.ql-indent-2 {
|
||||
counter-reset: list-3 list-4 list-5 list-6 list-7 list-8 list-9;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-3 {
|
||||
counter-increment: list-3;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-3:before {
|
||||
content: counter(list-3, decimal) '. ';
|
||||
}
|
||||
.ql-editor ol li.ql-indent-3 {
|
||||
counter-reset: list-4 list-5 list-6 list-7 list-8 list-9;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-4 {
|
||||
counter-increment: list-4;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-4:before {
|
||||
content: counter(list-4, lower-alpha) '. ';
|
||||
}
|
||||
.ql-editor ol li.ql-indent-4 {
|
||||
counter-reset: list-5 list-6 list-7 list-8 list-9;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-5 {
|
||||
counter-increment: list-5;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-5:before {
|
||||
content: counter(list-5, lower-roman) '. ';
|
||||
}
|
||||
.ql-editor ol li.ql-indent-5 {
|
||||
counter-reset: list-6 list-7 list-8 list-9;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-6 {
|
||||
counter-increment: list-6;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-6:before {
|
||||
content: counter(list-6, decimal) '. ';
|
||||
}
|
||||
.ql-editor ol li.ql-indent-6 {
|
||||
counter-reset: list-7 list-8 list-9;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-7 {
|
||||
counter-increment: list-7;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-7:before {
|
||||
content: counter(list-7, lower-alpha) '. ';
|
||||
}
|
||||
.ql-editor ol li.ql-indent-7 {
|
||||
counter-reset: list-8 list-9;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-8 {
|
||||
counter-increment: list-8;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-8:before {
|
||||
content: counter(list-8, lower-roman) '. ';
|
||||
}
|
||||
.ql-editor ol li.ql-indent-8 {
|
||||
counter-reset: list-9;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-9 {
|
||||
counter-increment: list-9;
|
||||
}
|
||||
.ql-editor ol li.ql-indent-9:before {
|
||||
content: counter(list-9, decimal) '. ';
|
||||
}
|
||||
.ql-editor .ql-indent-1:not(.ql-direction-rtl) {
|
||||
padding-left: 3em;
|
||||
}
|
||||
.ql-editor li.ql-indent-1:not(.ql-direction-rtl) {
|
||||
padding-left: 4.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 3em;
|
||||
}
|
||||
.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 4.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-2:not(.ql-direction-rtl) {
|
||||
padding-left: 6em;
|
||||
}
|
||||
.ql-editor li.ql-indent-2:not(.ql-direction-rtl) {
|
||||
padding-left: 7.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 6em;
|
||||
}
|
||||
.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 7.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-3:not(.ql-direction-rtl) {
|
||||
padding-left: 9em;
|
||||
}
|
||||
.ql-editor li.ql-indent-3:not(.ql-direction-rtl) {
|
||||
padding-left: 10.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 9em;
|
||||
}
|
||||
.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 10.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-4:not(.ql-direction-rtl) {
|
||||
padding-left: 12em;
|
||||
}
|
||||
.ql-editor li.ql-indent-4:not(.ql-direction-rtl) {
|
||||
padding-left: 13.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 12em;
|
||||
}
|
||||
.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 13.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-5:not(.ql-direction-rtl) {
|
||||
padding-left: 15em;
|
||||
}
|
||||
.ql-editor li.ql-indent-5:not(.ql-direction-rtl) {
|
||||
padding-left: 16.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 15em;
|
||||
}
|
||||
.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 16.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-6:not(.ql-direction-rtl) {
|
||||
padding-left: 18em;
|
||||
}
|
||||
.ql-editor li.ql-indent-6:not(.ql-direction-rtl) {
|
||||
padding-left: 19.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 18em;
|
||||
}
|
||||
.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 19.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-7:not(.ql-direction-rtl) {
|
||||
padding-left: 21em;
|
||||
}
|
||||
.ql-editor li.ql-indent-7:not(.ql-direction-rtl) {
|
||||
padding-left: 22.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 21em;
|
||||
}
|
||||
.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 22.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-8:not(.ql-direction-rtl) {
|
||||
padding-left: 24em;
|
||||
}
|
||||
.ql-editor li.ql-indent-8:not(.ql-direction-rtl) {
|
||||
padding-left: 25.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 24em;
|
||||
}
|
||||
.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 25.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-9:not(.ql-direction-rtl) {
|
||||
padding-left: 27em;
|
||||
}
|
||||
.ql-editor li.ql-indent-9:not(.ql-direction-rtl) {
|
||||
padding-left: 28.5em;
|
||||
}
|
||||
.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 27em;
|
||||
}
|
||||
.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right {
|
||||
padding-right: 28.5em;
|
||||
}
|
||||
.ql-editor .ql-video {
|
||||
display: block;
|
||||
max-width: 100%;
|
||||
}
|
||||
.ql-editor .ql-video.ql-align-center {
|
||||
margin: 0 auto;
|
||||
}
|
||||
.ql-editor .ql-video.ql-align-right {
|
||||
margin: 0 0 0 auto;
|
||||
}
|
||||
.ql-editor .ql-bg-black {
|
||||
background-color: #000;
|
||||
}
|
||||
.ql-editor .ql-bg-red {
|
||||
background-color: #e60000;
|
||||
}
|
||||
.ql-editor .ql-bg-orange {
|
||||
background-color: #f90;
|
||||
}
|
||||
.ql-editor .ql-bg-yellow {
|
||||
background-color: #ff0;
|
||||
}
|
||||
.ql-editor .ql-bg-green {
|
||||
background-color: #008a00;
|
||||
}
|
||||
.ql-editor .ql-bg-blue {
|
||||
background-color: #06c;
|
||||
}
|
||||
.ql-editor .ql-bg-purple {
|
||||
background-color: #93f;
|
||||
}
|
||||
.ql-editor .ql-color-white {
|
||||
color: #fff;
|
||||
}
|
||||
.ql-editor .ql-color-red {
|
||||
color: #e60000;
|
||||
}
|
||||
.ql-editor .ql-color-orange {
|
||||
color: #f90;
|
||||
}
|
||||
.ql-editor .ql-color-yellow {
|
||||
color: #ff0;
|
||||
}
|
||||
.ql-editor .ql-color-green {
|
||||
color: #008a00;
|
||||
}
|
||||
.ql-editor .ql-color-blue {
|
||||
color: #06c;
|
||||
}
|
||||
.ql-editor .ql-color-purple {
|
||||
color: #93f;
|
||||
}
|
||||
.ql-editor .ql-font-serif {
|
||||
font-family: Georgia, Times New Roman, serif;
|
||||
}
|
||||
.ql-editor .ql-font-monospace {
|
||||
font-family: Monaco, Courier New, monospace;
|
||||
}
|
||||
.ql-editor .ql-size-small {
|
||||
font-size: 0.75em;
|
||||
}
|
||||
.ql-editor .ql-size-large {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.ql-editor .ql-size-huge {
|
||||
font-size: 2.5em;
|
||||
}
|
||||
.ql-editor .ql-direction-rtl {
|
||||
direction: rtl;
|
||||
text-align: inherit;
|
||||
}
|
||||
.ql-editor .ql-align-center {
|
||||
text-align: center;
|
||||
}
|
||||
.ql-editor .ql-align-justify {
|
||||
text-align: justify;
|
||||
}
|
||||
.ql-editor .ql-align-right {
|
||||
text-align: right;
|
||||
}
|
||||
.ql-editor.ql-blank::before {
|
||||
color: rgba(0,0,0,0.6);
|
||||
content: attr(data-placeholder);
|
||||
font-style: italic;
|
||||
pointer-events: none;
|
||||
position: absolute;
|
||||
}
|
||||
.ql-snow.ql-toolbar:after,
|
||||
.ql-snow .ql-toolbar:after {
|
||||
clear: both;
|
||||
content: '';
|
||||
display: table;
|
||||
}
|
||||
.ql-snow.ql-toolbar button,
|
||||
.ql-snow .ql-toolbar button {
|
||||
background: none;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
height: 24px;
|
||||
padding: 3px 5px;
|
||||
width: 28px;
|
||||
}
|
||||
.ql-snow.ql-toolbar button svg,
|
||||
.ql-snow .ql-toolbar button svg {
|
||||
float: left;
|
||||
height: 100%;
|
||||
}
|
||||
.ql-snow.ql-toolbar button:active:hover,
|
||||
.ql-snow .ql-toolbar button:active:hover {
|
||||
outline: none;
|
||||
}
|
||||
.ql-snow.ql-toolbar input.ql-image[type=file],
|
||||
.ql-snow .ql-toolbar input.ql-image[type=file] {
|
||||
display: none;
|
||||
}
|
||||
.ql-snow.ql-toolbar button:hover,
|
||||
.ql-snow .ql-toolbar button:hover,
|
||||
.ql-snow.ql-toolbar button.ql-active,
|
||||
.ql-snow .ql-toolbar button.ql-active,
|
||||
.ql-snow.ql-toolbar .ql-picker-label:hover,
|
||||
.ql-snow .ql-toolbar .ql-picker-label:hover,
|
||||
.ql-snow.ql-toolbar .ql-picker-label.ql-active,
|
||||
.ql-snow .ql-toolbar .ql-picker-label.ql-active,
|
||||
.ql-snow.ql-toolbar .ql-picker-item:hover,
|
||||
.ql-snow .ql-toolbar .ql-picker-item:hover,
|
||||
.ql-snow.ql-toolbar .ql-picker-item.ql-selected,
|
||||
.ql-snow .ql-toolbar .ql-picker-item.ql-selected {
|
||||
color: #06c;
|
||||
}
|
||||
.ql-snow.ql-toolbar button:hover .ql-fill,
|
||||
.ql-snow .ql-toolbar button:hover .ql-fill,
|
||||
.ql-snow.ql-toolbar button.ql-active .ql-fill,
|
||||
.ql-snow .ql-toolbar button.ql-active .ql-fill,
|
||||
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-fill,
|
||||
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-fill,
|
||||
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-fill,
|
||||
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-fill,
|
||||
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-fill,
|
||||
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-fill,
|
||||
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-fill,
|
||||
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-fill,
|
||||
.ql-snow.ql-toolbar button:hover .ql-stroke.ql-fill,
|
||||
.ql-snow .ql-toolbar button:hover .ql-stroke.ql-fill,
|
||||
.ql-snow.ql-toolbar button.ql-active .ql-stroke.ql-fill,
|
||||
.ql-snow .ql-toolbar button.ql-active .ql-stroke.ql-fill,
|
||||
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
|
||||
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,
|
||||
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
|
||||
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,
|
||||
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
|
||||
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,
|
||||
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,
|
||||
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill {
|
||||
fill: #06c;
|
||||
}
|
||||
.ql-snow.ql-toolbar button:hover .ql-stroke,
|
||||
.ql-snow .ql-toolbar button:hover .ql-stroke,
|
||||
.ql-snow.ql-toolbar button.ql-active .ql-stroke,
|
||||
.ql-snow .ql-toolbar button.ql-active .ql-stroke,
|
||||
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke,
|
||||
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke,
|
||||
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke,
|
||||
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke,
|
||||
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke,
|
||||
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke,
|
||||
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
|
||||
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,
|
||||
.ql-snow.ql-toolbar button:hover .ql-stroke-miter,
|
||||
.ql-snow .ql-toolbar button:hover .ql-stroke-miter,
|
||||
.ql-snow.ql-toolbar button.ql-active .ql-stroke-miter,
|
||||
.ql-snow .ql-toolbar button.ql-active .ql-stroke-miter,
|
||||
.ql-snow.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
|
||||
.ql-snow .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,
|
||||
.ql-snow.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
|
||||
.ql-snow .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,
|
||||
.ql-snow.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
|
||||
.ql-snow .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,
|
||||
.ql-snow.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,
|
||||
.ql-snow .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter {
|
||||
stroke: #06c;
|
||||
}
|
||||
.ql-snow {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ql-snow * {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
.ql-snow .ql-hidden {
|
||||
display: none;
|
||||
}
|
||||
.ql-snow .ql-out-bottom,
|
||||
.ql-snow .ql-out-top {
|
||||
visibility: hidden;
|
||||
}
|
||||
.ql-snow .ql-tooltip {
|
||||
position: absolute;
|
||||
transform: translateY(10px);
|
||||
}
|
||||
.ql-snow .ql-tooltip a {
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
}
|
||||
.ql-snow .ql-tooltip.ql-flip {
|
||||
transform: translateY(-10px);
|
||||
}
|
||||
.ql-snow .ql-formats {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.ql-snow .ql-formats:after {
|
||||
clear: both;
|
||||
content: '';
|
||||
display: table;
|
||||
}
|
||||
.ql-snow .ql-stroke {
|
||||
fill: none;
|
||||
stroke: #444;
|
||||
stroke-linecap: round;
|
||||
stroke-linejoin: round;
|
||||
stroke-width: 2;
|
||||
}
|
||||
.ql-snow .ql-stroke-miter {
|
||||
fill: none;
|
||||
stroke: #444;
|
||||
stroke-miterlimit: 10;
|
||||
stroke-width: 2;
|
||||
}
|
||||
.ql-snow .ql-fill,
|
||||
.ql-snow .ql-stroke.ql-fill {
|
||||
fill: #444;
|
||||
}
|
||||
.ql-snow .ql-empty {
|
||||
fill: none;
|
||||
}
|
||||
.ql-snow .ql-even {
|
||||
fill-rule: evenodd;
|
||||
}
|
||||
.ql-snow .ql-thin,
|
||||
.ql-snow .ql-stroke.ql-thin {
|
||||
stroke-width: 1;
|
||||
}
|
||||
.ql-snow .ql-transparent {
|
||||
opacity: 0.4;
|
||||
}
|
||||
.ql-snow .ql-direction svg:last-child {
|
||||
display: none;
|
||||
}
|
||||
.ql-snow .ql-direction.ql-active svg:last-child {
|
||||
display: inline;
|
||||
}
|
||||
.ql-snow .ql-direction.ql-active svg:first-child {
|
||||
display: none;
|
||||
}
|
||||
.ql-snow .ql-editor h1 {
|
||||
font-size: 2em;
|
||||
}
|
||||
.ql-snow .ql-editor h2 {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.ql-snow .ql-editor h3 {
|
||||
font-size: 1.17em;
|
||||
}
|
||||
.ql-snow .ql-editor h4 {
|
||||
font-size: 1em;
|
||||
}
|
||||
.ql-snow .ql-editor h5 {
|
||||
font-size: 0.83em;
|
||||
}
|
||||
.ql-snow .ql-editor h6 {
|
||||
font-size: 0.67em;
|
||||
}
|
||||
.ql-snow .ql-editor a {
|
||||
text-decoration: underline;
|
||||
}
|
||||
.ql-snow .ql-editor blockquote {
|
||||
border-left: 4px solid #ccc;
|
||||
margin-bottom: 5px;
|
||||
margin-top: 5px;
|
||||
padding-left: 16px;
|
||||
}
|
||||
.ql-snow .ql-editor code,
|
||||
.ql-snow .ql-editor pre {
|
||||
background-color: #f0f0f0;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.ql-snow .ql-editor pre {
|
||||
white-space: pre-wrap;
|
||||
margin-bottom: 5px;
|
||||
margin-top: 5px;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
.ql-snow .ql-editor code {
|
||||
font-size: 85%;
|
||||
padding-bottom: 2px;
|
||||
padding-top: 2px;
|
||||
}
|
||||
.ql-snow .ql-editor code:before,
|
||||
.ql-snow .ql-editor code:after {
|
||||
content: "\A0";
|
||||
letter-spacing: -2px;
|
||||
}
|
||||
.ql-snow .ql-editor pre.ql-syntax {
|
||||
background-color: #23241f;
|
||||
color: #f8f8f2;
|
||||
overflow: visible;
|
||||
}
|
||||
.ql-snow .ql-editor img {
|
||||
max-width: 100%;
|
||||
}
|
||||
.ql-snow .ql-picker {
|
||||
color: #444;
|
||||
display: inline-block;
|
||||
float: left;
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
height: 24px;
|
||||
position: relative;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.ql-snow .ql-picker-label {
|
||||
cursor: pointer;
|
||||
display: inline-block;
|
||||
height: 100%;
|
||||
padding-left: 8px;
|
||||
padding-right: 2px;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
}
|
||||
.ql-snow .ql-picker-label::before {
|
||||
display: inline-block;
|
||||
line-height: 22px;
|
||||
}
|
||||
.ql-snow .ql-picker-options {
|
||||
background-color: #fff;
|
||||
display: none;
|
||||
min-width: 100%;
|
||||
padding: 4px 8px;
|
||||
position: absolute;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ql-snow .ql-picker-options .ql-picker-item {
|
||||
cursor: pointer;
|
||||
display: block;
|
||||
padding-bottom: 5px;
|
||||
padding-top: 5px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-expanded .ql-picker-label {
|
||||
color: #ccc;
|
||||
z-index: 2;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-fill {
|
||||
fill: #ccc;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-expanded .ql-picker-label .ql-stroke {
|
||||
stroke: #ccc;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-expanded .ql-picker-options {
|
||||
display: block;
|
||||
margin-top: -1px;
|
||||
top: 100%;
|
||||
z-index: 1;
|
||||
}
|
||||
.ql-snow .ql-color-picker,
|
||||
.ql-snow .ql-icon-picker {
|
||||
width: 28px;
|
||||
}
|
||||
.ql-snow .ql-color-picker .ql-picker-label,
|
||||
.ql-snow .ql-icon-picker .ql-picker-label {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
.ql-snow .ql-color-picker .ql-picker-label svg,
|
||||
.ql-snow .ql-icon-picker .ql-picker-label svg {
|
||||
right: 4px;
|
||||
}
|
||||
.ql-snow .ql-icon-picker .ql-picker-options {
|
||||
padding: 4px 0px;
|
||||
}
|
||||
.ql-snow .ql-icon-picker .ql-picker-item {
|
||||
height: 24px;
|
||||
width: 24px;
|
||||
padding: 2px 4px;
|
||||
}
|
||||
.ql-snow .ql-color-picker .ql-picker-options {
|
||||
padding: 3px 5px;
|
||||
width: 152px;
|
||||
}
|
||||
.ql-snow .ql-color-picker .ql-picker-item {
|
||||
border: 1px solid transparent;
|
||||
float: left;
|
||||
height: 16px;
|
||||
margin: 2px;
|
||||
padding: 0px;
|
||||
width: 16px;
|
||||
}
|
||||
.ql-snow .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg {
|
||||
position: absolute;
|
||||
margin-top: -9px;
|
||||
right: 0;
|
||||
top: 50%;
|
||||
width: 18px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=''])::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=''])::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=''])::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=''])::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=''])::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=''])::before {
|
||||
content: attr(data-label);
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header {
|
||||
width: 98px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item::before {
|
||||
content: 'Normal';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
||||
content: 'Heading 1';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
||||
content: 'Heading 2';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
||||
content: 'Heading 3';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
||||
content: 'Heading 4';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
||||
content: 'Heading 5';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
||||
content: 'Heading 6';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
|
||||
font-size: 2em;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
|
||||
font-size: 1.17em;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
|
||||
font-size: 1em;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
|
||||
font-size: 0.83em;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
|
||||
font-size: 0.67em;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font {
|
||||
width: 108px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item::before {
|
||||
content: 'Sans Serif';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=serif]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
|
||||
content: 'Serif';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-label[data-value=monospace]::before,
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
|
||||
content: 'Monospace';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=serif]::before {
|
||||
font-family: Georgia, Times New Roman, serif;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-font .ql-picker-item[data-value=monospace]::before {
|
||||
font-family: Monaco, Courier New, monospace;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size {
|
||||
width: 98px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item::before {
|
||||
content: 'Normal';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=small]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
|
||||
content: 'Small';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=large]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
|
||||
content: 'Large';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-label[data-value=huge]::before,
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
|
||||
content: 'Huge';
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=small]::before {
|
||||
font-size: 10px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=large]::before {
|
||||
font-size: 18px;
|
||||
}
|
||||
.ql-snow .ql-picker.ql-size .ql-picker-item[data-value=huge]::before {
|
||||
font-size: 32px;
|
||||
}
|
||||
.ql-snow .ql-color-picker.ql-background .ql-picker-item {
|
||||
background-color: #fff;
|
||||
}
|
||||
.ql-snow .ql-color-picker.ql-color .ql-picker-item {
|
||||
background-color: #000;
|
||||
}
|
||||
.ql-toolbar.ql-snow {
|
||||
border: 1px solid #ccc;
|
||||
box-sizing: border-box;
|
||||
font-family: 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
|
||||
padding: 8px;
|
||||
}
|
||||
.ql-toolbar.ql-snow .ql-formats {
|
||||
margin-right: 15px;
|
||||
}
|
||||
.ql-toolbar.ql-snow .ql-picker-label {
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.ql-toolbar.ql-snow .ql-picker-options {
|
||||
border: 1px solid transparent;
|
||||
box-shadow: rgba(0,0,0,0.2) 0 2px 8px;
|
||||
}
|
||||
.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-label {
|
||||
border-color: #ccc;
|
||||
}
|
||||
.ql-toolbar.ql-snow .ql-picker.ql-expanded .ql-picker-options {
|
||||
border-color: #ccc;
|
||||
}
|
||||
.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item.ql-selected,
|
||||
.ql-toolbar.ql-snow .ql-color-picker .ql-picker-item:hover {
|
||||
border-color: #000;
|
||||
}
|
||||
.ql-toolbar.ql-snow + .ql-container.ql-snow {
|
||||
border-top: 0px;
|
||||
}
|
||||
.ql-snow .ql-tooltip {
|
||||
background-color: #fff;
|
||||
border: 1px solid #ccc;
|
||||
box-shadow: 0px 0px 5px #ddd;
|
||||
color: #444;
|
||||
padding: 5px 12px;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.ql-snow .ql-tooltip::before {
|
||||
content: "Visit URL:";
|
||||
line-height: 26px;
|
||||
margin-right: 8px;
|
||||
}
|
||||
.ql-snow .ql-tooltip input[type=text] {
|
||||
display: none;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 13px;
|
||||
height: 26px;
|
||||
margin: 0px;
|
||||
padding: 3px 5px;
|
||||
width: 170px;
|
||||
}
|
||||
.ql-snow .ql-tooltip a.ql-preview {
|
||||
display: inline-block;
|
||||
max-width: 200px;
|
||||
overflow-x: hidden;
|
||||
text-overflow: ellipsis;
|
||||
vertical-align: top;
|
||||
}
|
||||
.ql-snow .ql-tooltip a.ql-action::after {
|
||||
border-right: 1px solid #ccc;
|
||||
content: 'Edit';
|
||||
margin-left: 16px;
|
||||
padding-right: 8px;
|
||||
}
|
||||
.ql-snow .ql-tooltip a.ql-remove::before {
|
||||
content: 'Remove';
|
||||
margin-left: 8px;
|
||||
}
|
||||
.ql-snow .ql-tooltip a {
|
||||
line-height: 26px;
|
||||
}
|
||||
.ql-snow .ql-tooltip.ql-editing a.ql-preview,
|
||||
.ql-snow .ql-tooltip.ql-editing a.ql-remove {
|
||||
display: none;
|
||||
}
|
||||
.ql-snow .ql-tooltip.ql-editing input[type=text] {
|
||||
display: inline-block;
|
||||
}
|
||||
.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
|
||||
border-right: 0px;
|
||||
content: 'Save';
|
||||
padding-right: 0px;
|
||||
}
|
||||
.ql-snow .ql-tooltip[data-mode=link]::before {
|
||||
content: "Enter link:";
|
||||
}
|
||||
.ql-snow .ql-tooltip[data-mode=formula]::before {
|
||||
content: "Enter formula:";
|
||||
}
|
||||
.ql-snow .ql-tooltip[data-mode=video]::before {
|
||||
content: "Enter video:";
|
||||
}
|
||||
.ql-snow a {
|
||||
color: #06c;
|
||||
}
|
||||
.ql-container.ql-snow {
|
||||
border: 1px solid #ccc;
|
||||
}
|
13
dist/rasterizeHTML/rasterizeHTML.allinone.js
vendored
Normal file
1369
dist/swal/sweetalert2.css
vendored
Normal file
1
dist/swal/sweetalert2.min.js
vendored
Normal file
96
dist/turf/turf.min.js
vendored
Normal file
280
index.html
@ -2,113 +2,64 @@
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>app</title>
|
||||
<title>Avion-poème</title>
|
||||
<link rel="icon" href="src/img/icon.png">
|
||||
<meta name="viewport" content="initial-scale=1,maximum-scale=1,user-scalable=no">
|
||||
<!-- CSS -->
|
||||
<!-- Bootstrap -->
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
<!-- leaflet -->
|
||||
<link rel="stylesheet" href="https://unpkg.com/leaflet@1.7.1/dist/leaflet.css"
|
||||
integrity="sha512-xodZBNTC5n17Xt2atTPuE1HxjVMSvLVW9ocqUKLsCC5CXdbqCmblAshOMAS6/keqq/sMZMZ19scR4PsZChSR7A=="
|
||||
crossorigin=""/>
|
||||
<!-- SWAL -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/10.15.5/sweetalert2.css" integrity="sha512-WfDqlW1EF2lMNxzzSID+Tp1TTEHeZ2DK+IHFzbbCHqLJGf2RyIjNFgQCRNuIa8tzHka19sUJYBO+qyvX8YBYEg==" crossorigin="anonymous" />
|
||||
<!-- quill -->
|
||||
<link href="https://cdn.quilljs.com/1.1.9/quill.snow.css" rel="stylesheet">
|
||||
<!-- font awesome -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css">
|
||||
<!-- leaflet locate user -->
|
||||
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/leaflet-locatecontrol/0.73.0/L.Control.Locate.min.css" integrity="sha512-61KpOy3DnpOq3pZlp54eyUdvq9ub53e2ETbksuRlQCMNiAkqyB2Iz8a6ggg61e9zlvPImPz+7A0tgvNGaoVLZg==" crossorigin="anonymous" />
|
||||
<!-- leaflet fullscreen -->
|
||||
<link href='https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/leaflet.fullscreen.css' rel='stylesheet' />
|
||||
<!-- leaflet pulse -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/leaflet-pulse-icon@0.1.0/src/L.Icon.Pulse.css">
|
||||
<!-- google fonts -->
|
||||
<!-- CSS -->
|
||||
<link rel="stylesheet" href="dist/bootstrap/bootstrap.min.css">
|
||||
<link rel="stylesheet" href="dist/leaflet/leaflet.css"/>
|
||||
<link rel="stylesheet" href="dist/quill/quill.snow.css">
|
||||
<link rel="stylesheet" href="https://pro.fontawesome.com/releases/v5.10.0/css/all.css">
|
||||
<link rel="stylesheet" href="dist/leaflet-locatecontrol/L.Control.Locate.min.css"/>
|
||||
<link rel='stylesheet' href="dist/leaflet-fullscreen/leaflet.fullscreen.css"/>
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com">
|
||||
<link href="https://fonts.googleapis.com/css2?family=PT+Mono&family=Special+Elite&display=swap" rel="stylesheet">
|
||||
<!-- App -->
|
||||
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=PT+Mono&family=Special+Elite&display=swap">
|
||||
<link href="src/app.css" rel="stylesheet">
|
||||
|
||||
<!-- JS -->
|
||||
<!-- jquery -->
|
||||
<script src="https://code.jquery.com/jquery-3.6.0.min.js" integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
|
||||
<!-- leaflet -->
|
||||
<script src="https://unpkg.com/leaflet@1.7.1/dist/leaflet.js"
|
||||
integrity="sha512-XQoYMqMTK8LvdxXYG3nZ448hOEQiglfqkJs1NOQV44cWnUrBc8PkAOcXy20w0vlaXaVUearIOBhiXZ5V3ynxwA=="
|
||||
crossorigin=""></script>
|
||||
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script> -->
|
||||
<!-- bootstrap -->
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
<!-- typehead -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/bootstrap-3-typeahead/4.0.2/bootstrap3-typeahead.js"></script>
|
||||
<!-- turf -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/Turf.js/6.3.0/turf.min.js" integrity="sha512-UNb2hkE/KkMe2ZBw0CWxpenoO0uudaEkJ0PT4cfGxCdL3sRSwaW7XyveNc9ZO0PQEq28FduAv8VvHaAjPbboBw==" crossorigin="anonymous"></script>
|
||||
<!-- moment -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment-with-locales.min.js" integrity="sha512-LGXaggshOkD/at6PFNcp2V2unf9LzFq6LE+sChH7ceMTDP0g2kn6Vxwgg7wkPP7AAtX+lmPqPdxB47A0Nz0cMQ==" crossorigin="anonymous"></script>
|
||||
<!-- moment TZ -->
|
||||
<script src="https://momentjs.com/downloads/moment-timezone-with-data.js" crossorigin="anonymous"></script>
|
||||
<!-- swal -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/limonte-sweetalert2/10.15.5/sweetalert2.min.js" integrity="sha512-+uGHdpCaEymD6EqvUR4H/PBuwqm3JTZmRh3gT0Lq52VGDAlywdXPBEiLiZUg6D1ViLonuNSUFdbL2tH9djAP8g==" crossorigin="anonymous"></script>
|
||||
<!-- quill -->
|
||||
<script src="https://cdn.quilljs.com/1.1.9/quill.js"></script>
|
||||
<!-- pixy -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/pixi.js/6.0.0/browser/pixi.min.js" integrity="sha512-shL+cXMf3XmoQtrHnCoyS7X/H/k5qKir6pQWj7Q12Lqj9SfuU6i13agrBxbKzDBg7qIEm6C17LVoFPzFSgyQ7Q==" crossorigin="anonymous"></script>
|
||||
<!-- leaflet pixy overlay -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/leaflet-pixi-overlay@1.8.1/L.PixiOverlay.min.js"></script>
|
||||
<!-- leaflet terminator -->
|
||||
<script src="https://unpkg.com/@joergdietrich/leaflet.terminator"></script>
|
||||
<!-- rasterize html -->
|
||||
<script src="http://cburgmer.github.io/rasterizeHTML.js/rasterizeHTML.allinone.js"></script>
|
||||
<!-- leaflet locate user -->
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/leaflet-locatecontrol/0.73.0/L.Control.Locate.min.js" integrity="sha512-taGzWgtN8FsSonl7SSrfPQBvTm/omZEf9p0s64IomW39xQZx8bSmP+aUyzeqig61ojVlMUwW5Moyo87HNQxliw==" crossorigin="anonymous"></script>
|
||||
<!-- leaflet fullscreen -->
|
||||
<script src='https://api.mapbox.com/mapbox.js/plugins/leaflet-fullscreen/v1.0.1/Leaflet.fullscreen.min.js'></script>
|
||||
<!-- leaflet pulse -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/leaflet-pulse-icon@0.1.0/src/L.Icon.Pulse.js"></script>
|
||||
<!-- JS -->
|
||||
<script src="dist/jquery/jquery-3.6.0.min.js"></script>
|
||||
<script src="dist/leaflet/leaflet.js"></script>
|
||||
<script src="dist/leaflet/touch-fix.js"></script>
|
||||
<script src="dist/popper/popper.min.js"></script>
|
||||
<script src="dist/bootstrap/bootstrap.min.js"></script>
|
||||
<script src="dist/bootstrap/bootstrap3-typeahead.js"></script>
|
||||
<script src="dist/turf/turf.min.js"></script>
|
||||
<script src="dist/moment/moment-with-locales.min.js"></script>
|
||||
<script src="dist/moment/moment-timezone-with-data.js"></script>
|
||||
<script src="dist/quill/quill.js"></script>
|
||||
<script src="dist/pixi/pixi.min.js"></script>
|
||||
<script src="dist/leaflet-pixi-overlay/L.PixiOverlay.min.js"></script>
|
||||
<script src="dist/leaflet-terminator/L.Terminator.js"></script>
|
||||
<script src="dist/rasterizeHTML/rasterizeHTML.allinone.js"></script>
|
||||
<script src="dist/leaflet-locatecontrol/L.Control.Locate.min.js"></script>
|
||||
<script src='dist/leaflet-fullscreen/Leaflet.fullscreen.min.js'></script>
|
||||
</head>
|
||||
<body>
|
||||
<!-- The core Firebase JS SDK is always required and must be listed first -->
|
||||
<script src="https://www.gstatic.com/firebasejs/8.2.10/firebase-app.js"></script>
|
||||
|
||||
<!-- TODO: Add SDKs for Firebase products that you want to use -->
|
||||
<script src="https://www.gstatic.com/firebasejs/8.2.10/firebase-firestore.js"></script>
|
||||
|
||||
<script>
|
||||
// Your web app's Firebase configuration
|
||||
var firebaseConfig = {
|
||||
apiKey: "AIzaSyD82Nx-gXXaPZq2Pl_JqvE0tQjABFNqdZA",
|
||||
authDomain: "avions-poemes.firebaseapp.com",
|
||||
databaseURL: "https://avions-poemes-default-rtdb.europe-west1.firebasedatabase.app",
|
||||
projectId: "avions-poemes",
|
||||
storageBucket: "avions-poemes.appspot.com",
|
||||
messagingSenderId: "355611894383",
|
||||
appId: "1:355611894383:web:c258c73f76581fac7fa39a"
|
||||
};
|
||||
// Initialize Firebase
|
||||
firebase.initializeApp(firebaseConfig);
|
||||
var db = firebase.firestore();
|
||||
</script>
|
||||
<!-- navbar -->
|
||||
<nav class="navbar navbar-expand-md fixed-top navbar-light bg-light">
|
||||
<a class="navbar-brand" href="#">Avions-Poèmes</a>
|
||||
<a id="navTitle" class="navbar-brand" href="#">Avion-Poème</a>
|
||||
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-label="Toggle navigation">
|
||||
<span class="fa fa-paper-plane"></span>
|
||||
<span class="fas fa-bars"></span>
|
||||
</button>
|
||||
<div class="collapse navbar-collapse" id="navbarCollapse">
|
||||
<ul class="navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#" data-toggle="modal" data-target="#langModal" >Français</a>
|
||||
<ul class="nav-menus navbar-nav mr-auto">
|
||||
<li class="nav-item">
|
||||
<a id="buttonAnthology" class="nav-link" href="#">Anthologie</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#">Anthologie</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" href="#" data-toggle="modal" data-target="#aboutModal" >À propos</a>
|
||||
<a id="buttonAbout" class="nav-link" href="#">À propos</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" href="#" id="navbarDropdownLang" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<img id="langIcon" src="src/img/lang.png" height="18px">
|
||||
</a>
|
||||
<div id="langChoices" class="dropdown-menu" aria-labelledby="navbarDropdownLang">
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<form class="form-inline mt-2 mt-md-0">
|
||||
<input type="button" class="btn btn-warning my-2 my-sm-0" data-toggle="modal" data-target="#newPlaneModal" value='Envoyer un avion'>
|
||||
</input>
|
||||
<form class="nav-button form-inline mt-2 mt-md-0">
|
||||
<input id="buttonNewPlane" type="button" class="btn btn-warning my-2 my-sm-0" data-toggle="modal" data-target="#newPlaneModal" value='Envoyer un avion'>
|
||||
</input>
|
||||
<i id="planeLimitTooltip" class="fas fa-question-circle" data-toggle="tooltip" data-placement="auto" title="coucou"></i>
|
||||
</form>
|
||||
</div>
|
||||
</nav>
|
||||
@ -119,8 +70,8 @@
|
||||
<canvas id="blankCanvas1" width="400" height="400" style="border:1px solid #d3d3d3; display:none"></canvas>
|
||||
<canvas id="blankCanvas2" width="400" height="400" style="border:1px solid #d3d3d3; display:none"></canvas>
|
||||
<img style="display:none;" id="front" src="src/img/front.jpg"/>
|
||||
<img style="display:none;" id="back" src="src/img/back.jpg"/>
|
||||
<script id="planeFoldScript.txt" type="not-javascript">
|
||||
<img style="display:none;" id="back" src="src/img/back-FF5555.jpg"/>
|
||||
<script id="planeFoldScript.txt" type="not-javascript"> <!-- From https://github.com/RemiKoutcherawy/OriSim3D-JS was fun to code -->
|
||||
d -200 200 -200 -200 200 -200 200 200
|
||||
c 0 1 c 0 3 c 0 2 c 1 3
|
||||
c 0 8 c 8 3 c 0 4 c 4 1
|
||||
@ -133,14 +84,39 @@
|
||||
t 500 r 23 -80 0 21 4 24 1 a 0)
|
||||
t 1000 tx -35 z 0 0 0 il 100 100)
|
||||
</script>
|
||||
|
||||
<!-- Anthology -->
|
||||
<div id="anthology">
|
||||
<h3 id="anthologyTitle" style="text-align:center">Anthologie</h3>
|
||||
<br><br>
|
||||
<small><em id="anthologyDisclaimer" >Si vous souhaitez supprimer un message/poème public, merci de le faire savoir à <a href="mailto:contact@avion-poe.me">contact@avion-poe.me</a></em></small>
|
||||
<br><br><br><br>
|
||||
<div id="anthologyItems">
|
||||
</div>
|
||||
</div>
|
||||
<!-- About -->
|
||||
<div id="about">
|
||||
<h3 id="aboutTitle" style="text-align:center">A propos</h3><br><br>
|
||||
<p id="aboutText">Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
||||
<p><b id="librairies">Librairies utilisées</b></p>
|
||||
<p><small><a href="https://getbootstrap.com/">Bootstrap</a> | <a href="https://jquery.com/">jQuery</a> | <a href="https://leafletjs.com/">Leaflet</a> | <a href="https://github.com/Leaflet/Leaflet.fullscreen">Leaflet.fullscreen</a> | <a href="https://github.com/domoritz/leaflet-locatecontrol">Leaflet-locatecontrol</a> | <a href="https://github.com/manubb/Leaflet.PixiOverlay">Leaflet.PixiOverlay</a> | <a href="https://github.com/joergdietrich/Leaflet.Terminator">Leaflet.Terminator</a> | <a href="https://momentjs.com/">Moment.js</a> | <a href="https://www.pixijs.com/">PixiJS</a> | <a href="https://popper.js.org/">Popper</a> | <a href="https://quilljs.com/">Quill</a> | <a href="https://cburgmer.github.io/rasterizeHTML.js/">RasterizeHTML.js</a> | <a href="https://turfjs.org/">Turf.js</a> | <a href="https://github.com/RemiKoutcherawy/OriSim3D-JS">OriSim3D-JS</a> | <a href="https://www.geonames.org/export/web-services.html">Geonames</a></small></p>
|
||||
<p><b id="mapSources">Sources de la carte</b></p>
|
||||
<ul>
|
||||
<li><span id="mapBackground">Fond de carte </span>:<small> <a href="https://www.arcgis.com/home/item.html?id=10df2279f9684e4a9f6a7f08febac2a9">World Imagery</a> Tiles © Esri — Source: Esri, i-cubed, USDA, USGS, AEX, GeoEye, Getmapping, Aerogrid, IGN, IGP, UPR-EGP, and the GIS User Community.</small></li>
|
||||
<li><span id="clouds">Nuages </span>:<small> Imagery provided by services from the Global Imagery Browse Services (GIBS), operated by the NASA/GSFC/Earth Science Data and Information System (<a href="https://earthdata.nasa.gov">ESDIS</a>) with funding provided by NASA/HQ.</small></li>
|
||||
</ul>
|
||||
<br>
|
||||
<br>
|
||||
</div>
|
||||
<div id="backToMap">
|
||||
<p style="text-align:center"><a id="closeAnthologyAbout" href="#" >Retour à la carte</a></p>
|
||||
</div>
|
||||
<!-- Modal new plane-->
|
||||
<div class="modal fade" id="newPlaneModal" tabindex="-1" role="dialog" aria-labelledby="newPlaneModal" aria-hidden="true">
|
||||
<div class="modal-dialog modal-lg" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">Envoyer un avion</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<h5 class="modal-title" id="newPlaneModalTitle">Lancer un avion-poème</h5>
|
||||
<button type="button" id="closeModal" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
@ -148,100 +124,72 @@
|
||||
<form>
|
||||
<div class="row">
|
||||
<div class="col-md-6">
|
||||
|
||||
|
||||
<div class="form-group">
|
||||
<label class="bold" for="selectTime">Temps de vol</label>
|
||||
<select class="form-control" id="selectTime">
|
||||
<option value="random">Aléatoire</option>
|
||||
<option value="3days">3,14 jours</option>
|
||||
<option value="7days">7 jours</option>
|
||||
<option value="30days">30 jours</option>
|
||||
<option value="365days">365 jours</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input type="checkbox" class="form-check-input" id="publicMessage">
|
||||
<label class="form-check-label" for="publicMessage">Message public</label>
|
||||
</div>
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<label class="bold" for="messageTextArea">Message</label>
|
||||
<div class="form-control rounded-0" id="messageTextArea"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<b class="bold" id="newPlaneModalMessage">Message</b>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="prive" value="prive" checked>
|
||||
<label class="form-check-label" for="prive" id="newPlaneModalPrive">privé</label>
|
||||
</div>
|
||||
<div class="form-check form-check-inline">
|
||||
<input class="form-check-input" type="radio" name="inlineRadioOptions" id="public" value="public">
|
||||
<label class="form-check-label" for="public" id="newPlaneModalPublic">public</label> <i id="publicTooltip" class="fas fa-question-circle" data-toggle="tooltip" data-placement="auto" title="Message publié dans l’Anthologie une fois l’avion-poème arrivé"></i>
|
||||
</div>
|
||||
<br>
|
||||
<br>
|
||||
<div class="form-control rounded-0" id="messageTextArea"></div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label class="bold" for="selectTime" id="flightTime" >Temps de vol</label>
|
||||
<select class="form-control" id="selectTime">
|
||||
<option id="newPlaneModalRandom" value="random">Aléatoire</option>
|
||||
<option id="newPlaneModal3j" value="3days">3,14 jours</option>
|
||||
<option id="newPlaneModal7j" value="7days">7 jours</option>
|
||||
<option id="newPlaneModal30j" value="30days">30 jours</option>
|
||||
<option id="newPlaneModal365j" value="365days">365 jours</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-6">
|
||||
<div class="form-group">
|
||||
<b class="bold">Expediteur</b>
|
||||
<input type="checkbox" class="form-check-input" id="expeKnown">
|
||||
<label class="form-check-label" for="expeKnown">Envoi anonyme</label>
|
||||
|
||||
<b class="bold" id="newPlaneModalExpediteur" >Expediteur</b>
|
||||
<input type="checkbox" class="form-check-input" id="expeKnown">
|
||||
<label class="form-check-label" for="expeKnown" id="newPlaneModalAnonyme">envoi anonyme</label> <i id="anonymeTooltip" class="fas fa-question-circle" data-toggle="tooltip" data-placement="auto" title="Votre adresse électronique ne sera communiquée au destinataire qu’à l’arrivée de l’avion-poème"></i>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="email" autocomplete="off" class="form-control" id="expeMail" aria-describedby="emailHelp" placeholder="Addresse mail">
|
||||
<!-- <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small> -->
|
||||
<input type="email" autocomplete="off" class="form-control" id="expeMail" aria-describedby="emailHelp" placeholder="Insérer votre adresse électronique">
|
||||
</div>
|
||||
<input type="text" autocomplete="off" class="form-control typeahead" id="expeGeocoderPhoton" placeholder="Localisation" data-provide="typeahead">
|
||||
<input type="text" autocomplete="off" class="form-control typeahead" id="expeGeocoderPhoton" placeholder="Choisissez un point de départ" data-provide="typeahead">
|
||||
<br>
|
||||
<div class="form-group">
|
||||
<label class="bold" for="destMail">Destinataire</label>
|
||||
<input type="email" autocomplete="off" class="form-control" id="destMail" aria-describedby="emailHelp" placeholder="Addresse mail">
|
||||
<!-- <small id="emailHelp" class="form-text text-muted">We'll never share your email with anyone else.</small> -->
|
||||
<label class="bold" id="newPlaneModalDestinataire" for="destMail">Destinataire</label>
|
||||
<input type="email" autocomplete="off" class="form-control" id="destMail" aria-describedby="emailHelp" placeholder="Insérer l'adresse électronique du destinataire">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="text" autocomplete="off" class="form-control typeahead" id="destGeocoderPhoton" placeholder="Localisation" data-provide="typeahead">
|
||||
<input type="text" autocomplete="off" class="form-control typeahead" id="destGeocoderPhoton" placeholder="Choisissez une destination" data-provide="typeahead">
|
||||
</div>
|
||||
<div class="form-group form-inline">
|
||||
<label for="selectDestLang">Langue parlée par le destinataire: </label>
|
||||
<select class="form-control form-control-sm" id="selectDestLang">
|
||||
<option value="fr">Français</option>
|
||||
<option value="en">English</option>
|
||||
<option value="de">Deutsch</option>
|
||||
<option value="it">Italiano</option>
|
||||
</select>
|
||||
<label for="selectDestLang" id="destLang">Langue parlée par le destinataire:</label>
|
||||
<select class="form-control form-control-sm" id="selectDestLang">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal">Annuler</button>
|
||||
<button type="button" class="btn btn-warning" id="sendNewPlane" disabled>Envoyer</button>
|
||||
<button type="button" class="btn btn-light" id="newPlaneModalCancel" data-dismiss="modal">Annuler</button>
|
||||
<button type="button" class="btn btn-warning" id="sendNewPlane" disabled>Lancer</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Modal About -->
|
||||
<div class="modal fade" id="aboutModal" tabindex="-1" role="dialog" aria-labelledby="aboutModal" aria-hidden="true">
|
||||
<div class="modal-dialog" role="document">
|
||||
<div class="modal-content">
|
||||
<div class="modal-header">
|
||||
<h5 class="modal-title">À propos</h5>
|
||||
<button type="button" class="close" data-dismiss="modal" aria-label="Close">
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="modal-body">
|
||||
<p>Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.</p>
|
||||
</div>
|
||||
<div class="modal-footer">
|
||||
<button type="button" class="btn btn-light" data-dismiss="modal">Retour</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!-- Footer -->
|
||||
<!-- <footer class="footer"> -->
|
||||
<!-- <div class="container-fluid"> -->
|
||||
<!-- Site open source dédié à l'envoi d'avions-poèmes. -->
|
||||
<!-- </div> -->
|
||||
<!-- </footer> -->
|
||||
<script src="src/translation.js"></script>
|
||||
<script src="src/about.js"></script>
|
||||
<script src="src/map.js"></script>
|
||||
<script src="src/geocoder.js"></script>
|
||||
<script src="src/paperPlaneAnimation.js"></script>
|
||||
<script src="src/formValidation.js"></script>
|
||||
<script src="src/newPlane.js"></script>
|
||||
<script src="src/translation.js"></script>
|
||||
<script src="src/anthology.js"></script>
|
||||
</body>
|
||||
</html>
|
7
lang/about.json
Normal file
@ -0,0 +1,7 @@
|
||||
[
|
||||
{
|
||||
"fr": "<p align=\"center\" style=\"border: 1px solid black; padding-top:50px; padding-bottom:50px; border-radius: 10px;\"><em>Cher·e·s semblables<br><br>Nous ne sommes pas comme vos milles et un prétendants<br><br>Si d’autres que nous vous offrent l’instantané,<br>Nous vous offrirons le temps et l’attente<br><br>S’ils vous offrent une lettre<br>Nous vous offrirons un poème<br><br>S’ils vous offrent une certitude<br>Nous vous offrirons les aléas et l’inconnu<br><br>S’ils vous offrent l’abondance<br>Nous vous offrirons le partage<br><br>Et s’ils vous offrent un message<br>Nous vous offrirons le voyage<br><br>Librement,<br><br>L’équipe d’avion-poe.me</em></p><br><br><p><b>En quelques mots</b><br><ul><li>Cette œuvre a été conçue par Maxime Sténuit (créateur), <a href=\"https://github.com/martinedoesgis\">martinedoesgis</a> (développeur front-end), et Daniel Tartavel (développeur back-end).</li><li>L’œuvre est sous licence <a href=\"https://creativecommons.org/licenses/by-nc-sa/2.0/fr/\">Creative Commons BY-NC-SA 2.0 FR</a> et le code source sous licence <a href=\"http://www.gnu.org/licenses/gpl-3.0.en.html\">GPLv3</a>.</li><li>Nous souhaitons que cette application mise librement à votre disposition soit utilisée à des fins excluant tous types de violences, qu’elles soient verbales ou physiques.</li><li>Les messages privés sont supprimés physiquement de notre serveur une fois arrivés, ainsi que l’ensemble des adresses électroniques. Ce site ne contient pas de traceurs.</li><li>Pour en savoir davantage sur <a href=\"https://lalis69.ddns.net:10443/laliscloud/index.php/s/Jf7BkZCWFpEF9tJ\">l’origine des avions-poèmes</a>.</li></ul><br>N’hésitez pas à nous faire part de vos commentaires et vos idées à <a href=\"mailto:contact@avion-poe.me\">contact@avion-poe.me</a>.<br><br>",
|
||||
"en": "<p align=\"center\" style=\"border: 1px solid black; padding-top:50px; padding-bottom:50px; border-radius: 10px;\"><em>Dear fellow,<br><br>We do not resemble your sycophants and suitors<br><br>Should others offer you the instant,<br>We shall offer you the time and the wait<br><br>Should they offer you a letter<br>We shall offer you a poem<br><br>Should they offer you certainty<br>We shall offer you the vagaries and the unknown<br><br>Should they offer you abundance<br>We shall offer you sharing<br><br>And should they offer you a valley<br>We shall offer you the journey<br><br>Freely,<br><br>The team of avion-poe.me</em></p><br><br><p><b>In a few words :</b><br><ul><li>Avion-poe.me was created by Maxime Sténuit, <a href=\"https://github.com/martinedoesgis\">martinedoesgis</a> (front-end developer), and Daniel Tartavel (back-end developer).</li><li>The work is under the <a href=\"https://creativecommons.org/licenses/by-nc-sa/2.0/fr/\">Creative Commons BY-NC-SA 2.0 FR</a> license and the source code under the <a href=\"http://www.gnu.org/licenses/gpl-3.0.en.html\">GPLv3</a> licence.</li><li>We wish this application, made freely available to you, to be used for purposes that exclude all types of violence, whether verbal or physical.</li><li>Private messages are physically deleted from our server when they arrive. This site does not contain cookies.</li><li>To learn more about <a href=\"https://lalis69.ddns.net:10443/laliscloud/index.php/s/Jf7BkZCWFpEF9tJ\">the origin of the flight-poem</a>.</li></ul><br>Please feel free to share your comments and ideas with us at <a href=\"mailto:contact@avion-poe.me\">contact@avion-poe.me</a>.<br><br>",
|
||||
"de": "<p align=\"center\" style=\"border: 1px solid black; padding-top:50px; padding-bottom:50px; border-radius: 10px;\"><em>Liebe Freunde<br><br>Wir gleichen euren Liebhabern nicht.<br><br>Bieten sie euch das Unmittelbare an<br>Schenken wir euch Zeit und Warten<br><br>Schreiben sie euch einen Brief<br>Überreichen wir euch ein Gedicht<br><br>Geben sie euch Gewissheit<br>bieten wir euch Launen und das Unbekannte<br><br>Überhäufen sie euch mit Überfluss<br>Lehren wir euch das Teilen<br><br>Und schicken sie euch eine Nachricht,<br>Dann schenken wir euch eine Reise.<br><br>Frei,<br><br>Das Team von avion-poe.me</em></p><br><br><p><b>In wenigen Worten:</b><br><ul><li>Diese Arbeit wurde von Maxime Sténuit (Schöpfer), <a href=\"https://github.com/martinedoesgis\">martinedoesgis</a> (Front-End-Entwickler) und Daniel Tartavel (Back-End-Entwickler) entworfen.</li><li>Die Arbeit ist unter der <a href=\"https://creativecommons.org/licenses/by-nc-sa/2.0/fr/\">Creative Commons BY-NC-SA 2.0 FR</a>-Lizenz und der Quellcode unter der <a href=\"http://www.gnu.org/licenses/gpl-3.0.en.html\">GPLv3</a>-Lizenz.</li><li>Wir möchten, dass diese Anwendung, die Ihnen frei zur Verfügung gestellt wird, für Zwecke verwendet wird, die alle Arten von verbaler oder physischer Gewalt ausschließen.</li><li>Private Nachrichten werden bei ihrem Eintreffen zusammen mit allen E-Mail-Adressen physisch von unserem Server gelöscht. Diese Seite enthält keine Cookies.</li><li>Um mehr <a href=\"https://lalis69.ddns.net:10443/laliscloud/index.php/s/Jf7BkZCWFpEF9tJ\">über den Ursprung von Gedicht-Flieger</a> zu erfahren.</li></ul><br>Bitte zögern Sie nicht, uns Ihre Kommentare und Ideen an <a href=\"mailto:contact@avion-poe.me\">contact@avion-poe.me</a> zu senden.<br><br>"
|
||||
}
|
||||
]
|
BIN
lang/about.ods
Normal file
1
lang/lang.json
Normal file
@ -0,0 +1 @@
|
||||
{"fr":"Français","en":"English","de":"Deutsch","bg":"български","zh":"中文","ja":"日本語","es":"español","pt":"português","ar":"اللغة العربية"}
|
33
src/about.js
Normal file
@ -0,0 +1,33 @@
|
||||
//open / close
|
||||
var aboutOpen = 0
|
||||
|
||||
$('#buttonAbout').on('click',function(){
|
||||
//hiding navbar
|
||||
$('.navbar-collapse').collapse('hide');
|
||||
if (aboutOpen > 0){
|
||||
$('#about').css('visibility','hidden');
|
||||
$('#about').css('opacity','0')
|
||||
$('#backToMap').css('visibility','hidden');
|
||||
$('#backToMap').css('opacity','0')
|
||||
aboutOpen = 0
|
||||
}
|
||||
else{
|
||||
$('#about').css('visibility','visible')
|
||||
$('#about').css('opacity','1')
|
||||
$('#backToMap').css('visibility','visible');
|
||||
$('#backToMap').css('opacity','1')
|
||||
aboutOpen = 1
|
||||
}
|
||||
//closing anthology
|
||||
$('#anthology').css('opacity','0')
|
||||
$('#anthology').css('visibility','hidden')
|
||||
anthologyOpen = 0
|
||||
})
|
||||
|
||||
$('#closeAnthologyAbout').on('click',function(){
|
||||
$('#about').css('opacity','0')
|
||||
$('#about').css('visibility','hidden')
|
||||
$('#backToMap').css('opacity','0')
|
||||
$('#backToMap').css('visibility','hidden')
|
||||
aboutOpen = 0
|
||||
})
|
130
src/anthology.js
Normal file
@ -0,0 +1,130 @@
|
||||
//open / close
|
||||
var anthologyOpen = 0
|
||||
|
||||
$('#buttonAnthology').on('click',function(){
|
||||
//hiding navbar
|
||||
$('.navbar-collapse').collapse('hide');
|
||||
if (anthologyOpen > 0){
|
||||
$('#anthology').css('visibility','hidden');
|
||||
$('#anthology').css('opacity','0')
|
||||
$('#backToMap').css('visibility','hidden');
|
||||
$('#backToMap').css('opacity','0')
|
||||
anthologyOpen = 0
|
||||
}
|
||||
else{
|
||||
$('#anthology').css('visibility','visible')
|
||||
$('#anthology').css('opacity','1')
|
||||
$('#backToMap').css('visibility','visible');
|
||||
$('#backToMap').css('opacity','1')
|
||||
anthologyOpen = 1
|
||||
displayAnthology()
|
||||
|
||||
}
|
||||
//closing about
|
||||
$('#about').css('visibility','hidden');
|
||||
$('#about').css('opacity','0')
|
||||
aboutOpen = 0
|
||||
})
|
||||
|
||||
$('#closeAnthologyAbout').on('click',function(){
|
||||
$('#anthology').css('opacity','0')
|
||||
$('#anthology').css('visibility','hidden')
|
||||
$('#backToMap').css('opacity','0')
|
||||
$('#backToMap').css('visibility','hidden')
|
||||
anthologyOpen = 0
|
||||
})
|
||||
|
||||
$('#navTitle').on('click',function(){
|
||||
$('#anthology').css('opacity','0')
|
||||
$('#anthology').css('visibility','hidden')
|
||||
$('#backToMap').css('opacity','0')
|
||||
$('#backToMap').css('visibility','hidden')
|
||||
$('#about').css('opacity','0')
|
||||
$('#about').css('visibility','hidden')
|
||||
aboutOpen = 0
|
||||
anthologyOpen = 0
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function flightTime(a,b){
|
||||
var days = Math.round((b-a)/86400 * 100) / 100
|
||||
var months = Math.round(days/30)
|
||||
var years = Math.round(months/12)
|
||||
if (days < 30){
|
||||
return ""+days+" "+dictionnary.jours
|
||||
}
|
||||
else if (days >= 30 && days < 365){
|
||||
if(months>1){
|
||||
return ""+months+" "+dictionnary.mois_pluriel
|
||||
}
|
||||
else{
|
||||
return ""+months+" "+dictionnary.mois
|
||||
}
|
||||
}
|
||||
else if (days >= 365){
|
||||
if(years>1){
|
||||
return ""+years+" "+dictionnary.ans
|
||||
}
|
||||
else{
|
||||
return ""+years+" "+dictionnary.an
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//load
|
||||
var nPages;
|
||||
var nPagesLoaded = 1
|
||||
$.post( "getAnthology.php", function(pages) {
|
||||
pages = $.parseJSON(pages)
|
||||
nPages = Number(pages.nPages)
|
||||
})
|
||||
|
||||
function displayAnthology(){ // clean and display first page
|
||||
$("#anthologyItems").html('')
|
||||
nPagesLoaded = 1
|
||||
$.post( "getAnthology.php?page=1", function(result) {
|
||||
results = $.parseJSON(result)
|
||||
var momentLocale = lang;
|
||||
if (momentLocale == 'zh'){momentLocale = 'zh-cn'} //troubleshot for chinese
|
||||
moment.locale(momentLocale)
|
||||
for (var i in results){
|
||||
addAnthologyLine(results[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
$( "#anthology" ).scroll(function() {
|
||||
if($("#anthology").scrollTop() + 700 > $("#anthologyItems").height()){
|
||||
if (nPagesLoaded < nPages){
|
||||
nPagesLoaded++
|
||||
console.log('Loading anthology page '+nPagesLoaded+'/'+nPages)
|
||||
$.post( "getAnthology.php?page="+nPagesLoaded+"", function(result) {
|
||||
results = $.parseJSON(result)
|
||||
var momentLocale = lang;
|
||||
if (momentLocale == 'zh'){momentLocale = 'zh-cn'} //troubleshot for chinese
|
||||
moment.locale(momentLocale)
|
||||
for (var i in results){
|
||||
addAnthologyLine(results[i])
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
function addAnthologyLine(results){
|
||||
if (lang == 'ar'){ // arabic : rtl + add <br>
|
||||
$("#anthologyItems").append(
|
||||
'<small style="float:right">'+dictionnary.origine+': <b>'+results.startName+'</b> • '+dictionnary.destination+': <b>'+results.destName+'</b> • '+dictionnary.date_arrivee+': <b>'+moment(Number(results.deliveryTime)*1000).format('LL')+'</b> • '+dictionnary.temps_de_vol+': <b>'+flightTime(Number(results.startTime),Number(results.deliveryTime))+'</b></small><br><br>'+results.message+'<br><hr><br>'
|
||||
)
|
||||
}
|
||||
else{
|
||||
$("#anthologyItems").append(
|
||||
'<small>'+dictionnary.origine+': <b>'+results.startName+'</b> • '+dictionnary.destination+': <b>'+results.destName+'</b> • '+dictionnary.date_arrivee+': <b>'+moment(Number(results.deliveryTime)*1000).format('LL')+'</b> • '+dictionnary.temps_de_vol+': <b>'+flightTime(Number(results.startTime),Number(results.deliveryTime))+'</b></small><br><br>'+results.message+'<br><hr><br>'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
227
src/app.css
@ -1,14 +1,21 @@
|
||||
html,
|
||||
body {
|
||||
overflow-x: hidden;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
body {
|
||||
position: relative;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'PT Mono', monospace;
|
||||
/* font-family: 'Special Elite', cursive !important */
|
||||
}
|
||||
|
||||
#map {
|
||||
position: absolute;
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
height:100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
@ -23,28 +30,12 @@ body {
|
||||
font-size: 12px
|
||||
}
|
||||
|
||||
/* removing footer on mobile */
|
||||
@media screen and (max-width: 400px) {
|
||||
.footer {
|
||||
display:none
|
||||
}
|
||||
}
|
||||
|
||||
/* big modal */
|
||||
.modal-lg {
|
||||
max-width:1140px !important;
|
||||
}
|
||||
|
||||
.mapboxgl-map{
|
||||
font-family: 'PT Mono', monospace;
|
||||
/* font-family: 'Special Elite', cursive !important */
|
||||
}
|
||||
|
||||
.mapboxgl-ctrl-logo{
|
||||
display: none !important;
|
||||
}
|
||||
|
||||
|
||||
/* paper plane animation */
|
||||
#canvas3d{
|
||||
display:none;
|
||||
@ -70,4 +61,204 @@ body {
|
||||
border-radius: .25em .25em 0px 0px !important;
|
||||
border-color: #ced4da !important
|
||||
}
|
||||
/* make the pixi overlay on top of the arc lines */
|
||||
.leaflet-pixi-overlay {
|
||||
position: absolute !important;
|
||||
z-index: 201 !important;
|
||||
}
|
||||
|
||||
.bold{
|
||||
font-weight:bold !important
|
||||
}
|
||||
|
||||
/* Anthology */
|
||||
#anthology{
|
||||
visibility:hidden;
|
||||
opacity:0;
|
||||
transition:visibility 0.2s linear,opacity 0.2s linear;
|
||||
position:absolute;
|
||||
z-index:1029;
|
||||
padding-top:66px;
|
||||
padding-bottom:35px;
|
||||
padding-left:30%;
|
||||
padding-right:30%;
|
||||
overflow-x:hidden;
|
||||
height:100vh;
|
||||
width:100vw;
|
||||
background-color:rgba(255,255,255,0.9)
|
||||
}
|
||||
|
||||
/* About */
|
||||
#about{
|
||||
visibility:hidden;
|
||||
opacity:0;
|
||||
transition:visibility 0.2s linear,opacity 0.2s linear;
|
||||
position:absolute;
|
||||
z-index:1029;
|
||||
padding-top:66px;
|
||||
padding-bottom:35px;
|
||||
padding-left:30%;
|
||||
padding-right:30%;
|
||||
overflow-x:hidden;
|
||||
height:100vh;
|
||||
width:100vw;
|
||||
background-color:rgba(255,255,255,0.9)
|
||||
}
|
||||
|
||||
#backToMap{
|
||||
visibility:hidden;
|
||||
opacity:0;
|
||||
transition:visibility 0.2s linear,opacity 0.2s linear;
|
||||
position:fixed;
|
||||
z-index:1035;
|
||||
padding-left:10%;
|
||||
padding-right:10%;
|
||||
overflow-x:hidden;
|
||||
width:100vw;
|
||||
bottom:0px;
|
||||
background-color:rgba(255,255,255,1);
|
||||
border-top: 1px solid #ddd;
|
||||
}
|
||||
|
||||
#backToMap a{
|
||||
color:#070707
|
||||
}
|
||||
|
||||
#backToMap p{
|
||||
margin-bottom:5px;
|
||||
padding-top:3px;
|
||||
}
|
||||
|
||||
#backToMap a:hover{
|
||||
color:black
|
||||
}
|
||||
|
||||
.leaflet-popup-content-wrapper{
|
||||
font-family: 'PT Mono', monospace;
|
||||
border-radius: 1px;
|
||||
/* font-family: 'Special Elite', cursive !important */
|
||||
}
|
||||
|
||||
.leaflet-popup-content{
|
||||
/* min-width:280px; */
|
||||
margin-left: 10px;
|
||||
margin-right: 21px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.leaflet-popup-content hr{
|
||||
width: 267px;
|
||||
margin-top: 10px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.leaflet-control-scale-line:not(:first-child) {
|
||||
border-top: none;
|
||||
border-bottom: 1px solid;
|
||||
margin-top: 0px;
|
||||
}
|
||||
|
||||
.leaflet-control-scale-line {
|
||||
FONT-WEIGHT: 100;
|
||||
font-family: 'PT Mono', monospace;
|
||||
border: 1px solid #fff;
|
||||
border-right: none;
|
||||
border-top: none;
|
||||
border-left: none;
|
||||
line-height: 1.1;
|
||||
padding: 2px 5px 1px;
|
||||
font-size: 11px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
color: white;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
/* background: #fff; */
|
||||
background: rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
.leaflet-bar a:last-child {
|
||||
border-bottom-left-radius: 1px !important;
|
||||
border-bottom-right-radius: 1px !important;
|
||||
}
|
||||
|
||||
.leaflet-bar a:first-child {
|
||||
border-top-left-radius: 1px !important;
|
||||
border-top-right-radius: 1px !important;
|
||||
}
|
||||
|
||||
/* pulsating marker */
|
||||
|
||||
.pulse-icon-anim {
|
||||
margin-top:2px;
|
||||
margin-left:2px;
|
||||
border: 3px solid;
|
||||
-webkit-border-radius: 30px;
|
||||
height: 18px;
|
||||
width: 18px;
|
||||
-webkit-animation: pulsate 1s ease-out;
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
/*opacity: 0.0*/
|
||||
}
|
||||
|
||||
@-webkit-keyframes pulsate {
|
||||
0% {-webkit-transform: scale(0.1, 0.1); opacity: 0.0;}
|
||||
50% {opacity: 1.0;}
|
||||
100% {-webkit-transform: scale(1.2, 1.2); opacity: 0.0;}
|
||||
}
|
||||
|
||||
a#navbarDropdownLang.nav-link.dropdown-toggle::after{
|
||||
margin-left:0px !important
|
||||
}
|
||||
|
||||
.nav-item{
|
||||
margin-right:10px
|
||||
}
|
||||
|
||||
.dropdown-menu{
|
||||
font-size:0.9em !important;
|
||||
padding: 0px !important
|
||||
}
|
||||
|
||||
.ql-editor {
|
||||
min-height:170px !important;
|
||||
width: 100% !important
|
||||
}
|
||||
|
||||
.ql-editor p {
|
||||
font-size:1.25em !important;
|
||||
|
||||
}
|
||||
|
||||
.ql-editor .ql-size-small {
|
||||
font-size: 0.9em !important;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 600px) {
|
||||
.modal-body {
|
||||
font-size:0.9rem
|
||||
}
|
||||
.modal-body .form-control{
|
||||
font-size:0.8rem
|
||||
}
|
||||
.leaflet-popup-content {
|
||||
margin: 10px 10px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
#anthologyItems{
|
||||
font-size:0.8rem
|
||||
}
|
||||
#about{
|
||||
padding-left:5% !important;
|
||||
padding-right:5% !important;
|
||||
}
|
||||
#anthology{
|
||||
padding-left:5% !important;
|
||||
padding-right:5% !important;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
var config = {
|
||||
mapboxKey: 'pk.eyJ1IjoibGVvLWlnYSIsImEiOiJjazY2bGV3MTYxMjV3M25sMmdtNWluM2wzIn0.2THSqD6nz9OhE0Xsjnbw1g',
|
||||
mapboxKey: 'pk.eyJ1IjoiYXZpb25wb2VtZSIsImEiOiJja20yY28xaWQyNnRiMnBvNm1kdjF4M3A5In0.gbs_ozL4rwh7KNsLmph-yQ',
|
||||
owmKey: "39d5c3be709ba4f5b6230cdffdedd2ac",
|
||||
}
|
25
src/formValidation.js
Normal file
@ -0,0 +1,25 @@
|
||||
var validExpeMail = false
|
||||
var validExpeLoc = false //turned to true in geocoder.js
|
||||
var validDestMail = false
|
||||
var validDestLoc = false //turned to true in geocoder.js
|
||||
|
||||
function validateEmail(email) { //from https://stackoverflow.com/questions/46155/how-to-validate-an-email-address-in-javascript
|
||||
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
|
||||
return re.test(String(email).toLowerCase());
|
||||
}
|
||||
|
||||
$("#expeMail").change(function() {
|
||||
validExpeMail = validateEmail($("#expeMail").val())
|
||||
checkFormValid()
|
||||
})
|
||||
|
||||
$("#destMail").change(function() {
|
||||
validDestMail = validateEmail($("#destMail").val())
|
||||
checkFormValid()
|
||||
})
|
||||
|
||||
function checkFormValid(){
|
||||
if(validExpeMail && validExpeLoc && validDestMail && validDestLoc){
|
||||
$('#sendNewPlane').prop("disabled", false)
|
||||
}
|
||||
}
|
120
src/geocoder.js
@ -1,24 +1,56 @@
|
||||
let langGeocoder = "fr"
|
||||
function langGeocoder(lang){
|
||||
if (lang == 'fr' || lang == 'en' || lang == 'de' || lang == 'it'){ //photon only supports fr en de it, the rest will be en by default
|
||||
return lang
|
||||
}
|
||||
else return "en"
|
||||
}
|
||||
|
||||
// Expediteur
|
||||
var expeLocList = []
|
||||
var expeLoc;
|
||||
$('#expeGeocoderPhoton').typeahead({
|
||||
source: function (query, process) {
|
||||
expeLocList = []
|
||||
var url = "https://photon.komoot.io/api?q="+query+"&lang="+langGeocoder+"&limit=4&osm_tag=place:city&osm_tag=place:town&osm_tag=place:village&osm_tag=place:municipality";
|
||||
var res = []
|
||||
return $.getJSON(url,function(data){
|
||||
for (var i in data.features){
|
||||
res.push(data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")")
|
||||
expeLocList.push({
|
||||
name: data.features[i].properties.name,
|
||||
center: data.features[i].geometry.coordinates,
|
||||
fullname: data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")"
|
||||
})
|
||||
}
|
||||
return process(res)
|
||||
})
|
||||
var timer;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function() { // using a timer of 400 ms to troubleshot people typing super fast
|
||||
expeLocList = []
|
||||
var l = langGeocoder(lang)
|
||||
var url = "https://photon.komoot.io/api?q="+query+"&lang="+l+"&limit=4&osm_tag=place:city&osm_tag=place:town&osm_tag=place:village&osm_tag=place:municipality&osm_tag=place:suburb&osm_tag=place:neighbourhood&osm_tag=place:hamlet&osm_tag=highway";
|
||||
//var url = "https://photon.komoot.io/api?q="+query+"&lang="+l+"&limit=4";
|
||||
var res = []
|
||||
return $.getJSON(url,function(data){
|
||||
for (var i in data.features){
|
||||
if(data.features[i].properties.type == "street"){
|
||||
res.push(data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")")
|
||||
expeLocList.push({
|
||||
name: data.features[i].properties.city,
|
||||
center: data.features[i].geometry.coordinates,
|
||||
fullname: data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")"
|
||||
})
|
||||
}
|
||||
else if(data.features[i].properties.osm_value == "suburb" || data.features[i].properties.osm_value == "neighbourhood"){
|
||||
res.push(data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")")
|
||||
expeLocList.push({
|
||||
name: data.features[i].properties.city,
|
||||
center: data.features[i].geometry.coordinates,
|
||||
fullname: data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")"
|
||||
})
|
||||
}
|
||||
else{
|
||||
res.push(data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")")
|
||||
expeLocList.push({
|
||||
name: data.features[i].properties.name,
|
||||
center: data.features[i].geometry.coordinates,
|
||||
fullname: data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")"
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
return process(res)
|
||||
})
|
||||
},
|
||||
400
|
||||
)
|
||||
},
|
||||
matcher: function(item){ //needed when spelling not exact
|
||||
return true
|
||||
@ -28,6 +60,8 @@ $('#expeGeocoderPhoton').typeahead({
|
||||
for (var i in expeLocList){
|
||||
if (expeLocList[i].fullname == obj){
|
||||
expeLoc = expeLocList[i]
|
||||
validExpeLoc = true
|
||||
checkFormValid()
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -38,20 +72,46 @@ var destLocList = []
|
||||
var destLoc;
|
||||
$('#destGeocoderPhoton').typeahead({
|
||||
source: function (query, process) {
|
||||
destLocList = []
|
||||
var url = "https://photon.komoot.io/api?q="+query+"&lang="+langGeocoder+"&limit=4&osm_tag=place:city&osm_tag=place:town&osm_tag=place:village&osm_tag=place:municipality";
|
||||
var res = []
|
||||
return $.getJSON(url,function(data){
|
||||
for (var i in data.features){
|
||||
res.push(data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")")
|
||||
destLocList.push({
|
||||
name: data.features[i].properties.name,
|
||||
center: data.features[i].geometry.coordinates,
|
||||
fullname: data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")"
|
||||
})
|
||||
}
|
||||
return process(res)
|
||||
})
|
||||
var timer;
|
||||
clearTimeout(timer);
|
||||
timer = setTimeout(function() { // using a timer of 400 ms to troubleshot people typing super fast
|
||||
destLocList = []
|
||||
var l = langGeocoder(lang)
|
||||
var url = "https://photon.komoot.io/api?q="+query+"&lang="+l+"&limit=4&osm_tag=place:city&osm_tag=place:town&osm_tag=place:village&osm_tag=place:municipality&osm_tag=place:suburb&osm_tag=place:neighbourhood&osm_tag=place:hamlet&osm_tag=highway";
|
||||
var res = []
|
||||
return $.getJSON(url,function(data){
|
||||
for (var i in data.features){
|
||||
if(data.features[i].properties.type == "street"){
|
||||
res.push(data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")")
|
||||
destLocList.push({
|
||||
name: data.features[i].properties.city,
|
||||
center: data.features[i].geometry.coordinates,
|
||||
fullname: data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")"
|
||||
})
|
||||
}
|
||||
else if(data.features[i].properties.osm_value == "suburb" || data.features[i].properties.osm_value == "neighbourhood"){
|
||||
res.push(data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")")
|
||||
destLocList.push({
|
||||
name: data.features[i].properties.city,
|
||||
center: data.features[i].geometry.coordinates,
|
||||
fullname: data.features[i].properties.name+" ("+data.features[i].properties.city+", "+data.features[i].properties.country+")"
|
||||
})
|
||||
}
|
||||
else{
|
||||
res.push(data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")")
|
||||
destLocList.push({
|
||||
name: data.features[i].properties.name,
|
||||
center: data.features[i].geometry.coordinates,
|
||||
fullname: data.features[i].properties.name+" ("+data.features[i].properties.state+", "+data.features[i].properties.country+")"
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
return process(res)
|
||||
})
|
||||
},
|
||||
400
|
||||
)
|
||||
},
|
||||
matcher: function(item){ //needed when spelling not exact
|
||||
return true
|
||||
@ -61,6 +121,8 @@ $('#destGeocoderPhoton').typeahead({
|
||||
for (var i in destLocList){
|
||||
if (destLocList[i].fullname == obj){
|
||||
destLoc = destLocList[i]
|
||||
validDestLoc = true
|
||||
checkFormValid()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
BIN
src/img/back-2A7FFF.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-66FF00.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-BC5FD3.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-C8AB37.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-ECECEC.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-FF5555.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-FF6600.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back-FFE419.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/back.jpg
Normal file
After Width: | Height: | Size: 75 KiB |
BIN
src/img/front.jpg
Normal file
After Width: | Height: | Size: 3.8 KiB |
BIN
src/img/icon.png
Normal file
After Width: | Height: | Size: 3.9 KiB |
BIN
src/img/lang-hover.png
Normal file
After Width: | Height: | Size: 23 KiB |
BIN
src/img/lang.png
Normal file
After Width: | Height: | Size: 40 KiB |
71
src/img/licence.svg
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
src/img/plane-2A7FFF.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
src/img/plane-66FF00.png
Normal file
After Width: | Height: | Size: 42 KiB |
BIN
src/img/plane-BC5FD3.png
Normal file
After Width: | Height: | Size: 52 KiB |
BIN
src/img/plane-C8AB37.png
Normal file
After Width: | Height: | Size: 51 KiB |
BIN
src/img/plane-ECECEC.png
Normal file
After Width: | Height: | Size: 48 KiB |
BIN
src/img/plane-FF5555.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
src/img/plane-FF6600.png
Normal file
After Width: | Height: | Size: 41 KiB |
BIN
src/img/plane-FFE419.png
Normal file
After Width: | Height: | Size: 47 KiB |
BIN
src/img/shadow.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
730
src/map.js
@ -1,266 +1,484 @@
|
||||
mapboxgl.accessToken = config.mapboxKey;
|
||||
const owmKey = config.owmKey
|
||||
var loader = new PIXI.Loader();
|
||||
var colors = ['66FF00','FF5555','FFE419','2A7FFF','BC5FD3','C8AB37','ECECEC','FF6600'];
|
||||
for (var i in colors){
|
||||
loader.add('marker'+colors[i]+'', 'src/img/plane-'+colors[i]+'.png');
|
||||
}
|
||||
|
||||
var map = new mapboxgl.Map({
|
||||
container: 'map',
|
||||
style: {
|
||||
"glyphs": "mapbox://fonts/mapbox/{fontstack}/{range}.pbf",
|
||||
"light": {
|
||||
"anchor": "viewport",
|
||||
"color": "white",
|
||||
"intensity": 0.1
|
||||
},
|
||||
'version': 8,
|
||||
'sources': {
|
||||
'default-background': {
|
||||
'type': 'raster',
|
||||
'tiles': [
|
||||
//'https://map1.vis.earthdata.nasa.gov/wmts-webmerc/VIIRS_CityLights_2012/default//GoogleMapsCompatible_Level8/{z}/{y}/{x}.jpg'
|
||||
//'https://server.arcgisonline.com/ArcGIS/rest/services/World_Terrain_Base/MapServer/tile/{z}/{y}/{x}'
|
||||
//'https://stamen-tiles-b.a.ssl.fastly.net/watercolor/{z}/{x}/{y}.jpg'
|
||||
'https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}'
|
||||
],
|
||||
'tileSize': 256
|
||||
}
|
||||
},
|
||||
'layers': [{
|
||||
id: 'background',
|
||||
type: 'background',
|
||||
paint: {
|
||||
'background-color': '#ffffff'
|
||||
}
|
||||
},
|
||||
{
|
||||
'id': 'default-background',
|
||||
'type': 'raster',
|
||||
'source': 'default-background',
|
||||
'minzoom': 0,
|
||||
'maxzoom': 18
|
||||
}
|
||||
]
|
||||
},
|
||||
center: [0, 20],
|
||||
zoom: 2,
|
||||
attributionControl: false
|
||||
//global variable
|
||||
var nbPlane = 0
|
||||
|
||||
});
|
||||
//prevent world duplication
|
||||
map.setRenderWorldCopies(status === 'false')
|
||||
loader.add('shadow', 'src/img/shadow.png');
|
||||
loader.load(function(loader, resources) {
|
||||
|
||||
map.on('load', function () {
|
||||
//displaying clouds from OpenWeatherMap free API not enough
|
||||
var pixiContainer = new PIXI.Container();
|
||||
|
||||
// map.addSource('clouds', {
|
||||
// 'type': 'raster',
|
||||
// 'tiles': [
|
||||
// 'https://tile.openweathermap.org/map/clouds_new/{z}/{x}/{y}.png?appid='+owmKey+''
|
||||
// ],
|
||||
// 'tileSize': 256
|
||||
// });
|
||||
|
||||
// map.addLayer({
|
||||
// 'id': 'clouds',
|
||||
// 'type': 'raster',
|
||||
// 'source': 'clouds',
|
||||
// 'minzoom': 0,
|
||||
// 'maxzoom': 10,
|
||||
// 'paint':{
|
||||
// 'raster-opacity':0.5
|
||||
// }
|
||||
// });
|
||||
|
||||
//loading icons and colors, too lazy to make a loop, to change.
|
||||
map.loadImage('src/img/plane-FFE419.png',
|
||||
function (error, image) {
|
||||
if (error) throw error;
|
||||
map.addImage('plane-FFE419', image);
|
||||
var map = L.map('map',{
|
||||
zoomControl: false,
|
||||
minZoom:2,
|
||||
maxZoom: 16,
|
||||
maxBounds: [
|
||||
[-Infinity, -360],
|
||||
[Infinity, 360]
|
||||
],
|
||||
//worldCopyJump: true,
|
||||
attributionControl: false
|
||||
})
|
||||
map.loadImage('src/img/plane-66FF00.png',
|
||||
function (error, image) {
|
||||
if (error) throw error;
|
||||
map.addImage('plane-66FF00', image);
|
||||
})
|
||||
map.loadImage('src/img/plane-FF5555.png',
|
||||
function (error, image) {
|
||||
if (error) throw error;
|
||||
map.addImage('plane-FF5555', image);
|
||||
})
|
||||
var colors = ["FFE419","66FF00","FF5555"]
|
||||
|
||||
//get now in GMT+0
|
||||
var nowGMTSeconds = moment.tz(new Date(), "Europe/London").unix()
|
||||
//zoom controls
|
||||
L.control.zoom({position: 'bottomright'}).addTo(map);
|
||||
//Locate user
|
||||
L.control.locate({position: 'bottomright'}).addTo(map);
|
||||
//fullscreen
|
||||
map.addControl(new L.Control.Fullscreen({position: 'bottomright'}));
|
||||
|
||||
//get the planes from firestore
|
||||
db.collection("planes").where("deliverySecondsServer", ">", nowGMTSeconds).get().then((querySnapshot) => { //change query to get only the ones who are still flying
|
||||
querySnapshot.forEach((doc) => {
|
||||
var id = doc.id
|
||||
var data = doc.data()
|
||||
//creating arcs
|
||||
var line = turf.lineString([data.startCoordo,data.destCoordo])
|
||||
var lineDistance = turf.length(line);
|
||||
var arc = [];
|
||||
var steps = 500;
|
||||
for (var i = 0; i < lineDistance; i += lineDistance / steps) {
|
||||
var segment = turf.along(line, i);
|
||||
arc.push(segment.geometry.coordinates);
|
||||
}
|
||||
line.geometry.coordinates = arc;
|
||||
// Licence Icon
|
||||
L.Control.Watermark = L.Control.extend({
|
||||
onAdd: function(map) {
|
||||
var img = L.DomUtil.create('img');
|
||||
|
||||
//random color
|
||||
var randomColor = colors[Math.floor(Math.random() * colors.length)];
|
||||
img.src = 'src/img/licence.svg';
|
||||
img.style.width = '100px';
|
||||
|
||||
map.addSource('route-'+id+'', {
|
||||
'type': 'geojson',
|
||||
'data': line
|
||||
});
|
||||
map.addLayer({
|
||||
'id': 'route-'+id+'',
|
||||
'source': 'route-'+id+'',
|
||||
'type': 'line',
|
||||
'paint': {
|
||||
'line-width': 2,
|
||||
'line-color': '#'+randomColor
|
||||
}
|
||||
});
|
||||
map.setLayoutProperty('route-'+id+'', 'visibility', 'none');
|
||||
|
||||
|
||||
//creating and animating planes
|
||||
|
||||
// calculating area already travelled
|
||||
var dateStart = moment(data.sentDate[0])
|
||||
var dateEnd = moment(data.deliveryDate[0])
|
||||
var dateNow = moment(new Date())
|
||||
var totalSeconds = dateEnd.diff(dateStart,'seconds');
|
||||
var travelledSeconds = dateNow.diff(dateStart,'seconds')
|
||||
var travelRatio = travelledSeconds/totalSeconds
|
||||
var lineDistance = turf.length(line);
|
||||
var currentPosition = turf.along(line, lineDistance*travelRatio,{units: 'kilometers'})
|
||||
var plane = turf.point(currentPosition.geometry.coordinates,data)
|
||||
|
||||
//calculating bearing based on two points, one just before and one just after
|
||||
var positionBefore = turf.along(line, (lineDistance*travelRatio)-0.00001,{units: 'kilometers'})
|
||||
var positionAfter = turf.along(line, (lineDistance*travelRatio)+0.00001,{units: 'kilometers'})
|
||||
plane.properties.bearing = turf.bearing(
|
||||
positionBefore,
|
||||
positionAfter
|
||||
);
|
||||
|
||||
map.addSource('plane-'+id+'', {
|
||||
'type': 'geojson',
|
||||
'data': plane
|
||||
});
|
||||
map.addLayer({
|
||||
'id': 'plane-'+id+'',
|
||||
'source': 'plane-'+id+'',
|
||||
'type': 'symbol',
|
||||
'layout': {
|
||||
'icon-image': 'plane-'+randomColor+'',
|
||||
'icon-rotate': ['get', 'bearing'],
|
||||
'icon-size':0.05,
|
||||
'icon-rotation-alignment': 'map',
|
||||
'icon-allow-overlap': true,
|
||||
'icon-ignore-placement': true
|
||||
}
|
||||
});
|
||||
|
||||
//animating
|
||||
function animate(){
|
||||
var dateStart = moment(data.sentDate[0])
|
||||
var dateEnd = moment(data.deliveryDate[0])
|
||||
var dateNow = moment(new Date())
|
||||
var totalSeconds = dateEnd.diff(dateStart,'seconds');
|
||||
var travelledSeconds = dateNow.diff(dateStart,'seconds')
|
||||
var travelRatio = travelledSeconds/totalSeconds
|
||||
var lineDistance = turf.length(line);
|
||||
var currentPosition = turf.along(line, lineDistance*travelRatio,{units: 'kilometers'})
|
||||
var plane = turf.point(currentPosition.geometry.coordinates,data)
|
||||
|
||||
//calculating bearing based on two points, one just before and one just after
|
||||
var positionBefore = turf.along(line, (lineDistance*travelRatio)-0.00001,{units: 'kilometers'})
|
||||
var positionAfter = turf.along(line, (lineDistance*travelRatio)+0.00001,{units: 'kilometers'})
|
||||
plane.properties.bearing = turf.bearing(
|
||||
positionBefore,
|
||||
positionAfter
|
||||
);
|
||||
map.getSource('plane-'+id+'').setData(plane);
|
||||
var nowGMTSeconds = moment.tz(new Date(), "Europe/London").unix()
|
||||
//removing the plane from map if arrived
|
||||
if (data.deliverySecondsServer < nowGMTSeconds){
|
||||
map.setLayoutProperty('plane-'+id+'', 'visibility', 'none');
|
||||
}
|
||||
requestAnimationFrame(animate)
|
||||
}
|
||||
// uncomment to animate below, still some clipping issues
|
||||
//animate()
|
||||
|
||||
//on click on a plane: get popup + display route
|
||||
map.on('click', 'plane-'+id+'', function (e) {
|
||||
var coordinates = e.features[0].geometry.coordinates.slice();
|
||||
var prop = e.features[0].properties;
|
||||
var sentDate = JSON.parse(prop.sentDate)[0]
|
||||
var deliveryDate = JSON.parse(prop.deliveryDate)[0]
|
||||
while (Math.abs(e.lngLat.lng - coordinates[0]) > 180) {
|
||||
coordinates[0] += e.lngLat.lng > coordinates[0] ? 360 : -360;
|
||||
}
|
||||
//displying route
|
||||
map.setLayoutProperty('route-'+id+'', 'visibility', 'visible');
|
||||
|
||||
var popup = new mapboxgl.Popup()
|
||||
.setLngLat(coordinates)
|
||||
.setHTML("<b>Origine:</b> "+prop.startName+"<br><em>"+sentDate+"</em><br><b>Destination:</b> "+prop.destName+"<br><em>"+deliveryDate+"</em>")
|
||||
.addTo(map);
|
||||
//removing route
|
||||
popup.on('close', function(){
|
||||
map.setLayoutProperty('route-'+id+'', 'visibility', 'none');
|
||||
});
|
||||
|
||||
});
|
||||
// Change the cursor to a pointer when the mouse is over the places layer.
|
||||
map.on('mouseenter', 'plane-'+id+'', function () {
|
||||
map.getCanvas().style.cursor = 'pointer';
|
||||
});
|
||||
|
||||
// Change it back to a pointer when it leaves.
|
||||
map.on('mouseleave', 'plane-'+id+'', function () {
|
||||
map.getCanvas().style.cursor = '';
|
||||
});
|
||||
|
||||
//adapt icon size to zoom level
|
||||
map.on('zoom', function() {
|
||||
map.setLayoutProperty('plane-'+id+'', 'icon-size', (map.getZoom())*0.025);
|
||||
});
|
||||
|
||||
|
||||
//URL Parameter : zooming to ID and opening popup when url in format avion-poe.me?plane=id
|
||||
var queryString = window.location.search;
|
||||
queryString = queryString.substring(7)
|
||||
if(id == queryString){
|
||||
map.setLayoutProperty('route-'+id+'', 'visibility', 'visible');
|
||||
var bboxTravel = turf.bbox(line);
|
||||
var bounds = [[bboxTravel[0],bboxTravel[1]],[bboxTravel[2],bboxTravel[3]]]
|
||||
map.fitBounds(bounds, {
|
||||
padding: 65,
|
||||
speed: 0.5, // make the flying slow
|
||||
curve: 0.8, // change the speed at which it zooms out
|
||||
// This can be any easing function: it takes a number between
|
||||
// 0 and 1 and returns another number between 0 and 1.
|
||||
easing: function(
|
||||
t) {
|
||||
return t;
|
||||
},
|
||||
});
|
||||
var sentDate = plane.properties.sentDate[0]
|
||||
var deliveryDate = plane.properties.deliveryDate[0]
|
||||
var popup = new mapboxgl.Popup()
|
||||
.setLngLat(currentPosition.geometry.coordinates)
|
||||
.setHTML("<b>Origine:</b> "+plane.properties.startName+"<br><em>"+sentDate+"</em><br><b>Destination:</b> "+plane.properties.destName+"<br><em>"+deliveryDate+"</em>")
|
||||
.addTo(map);
|
||||
//removing route
|
||||
popup.on('close', function(){
|
||||
map.setLayoutProperty('route-'+id+'', 'visibility', 'none');
|
||||
});
|
||||
}
|
||||
});
|
||||
return img;
|
||||
}
|
||||
});
|
||||
})
|
||||
L.control.watermark = function(opts) {
|
||||
return new L.Control.Watermark(opts);
|
||||
}
|
||||
L.control.watermark({ position: 'bottomleft' }).addTo(map);
|
||||
//scale
|
||||
L.control.scale().addTo(map);
|
||||
|
||||
//disabling send plane button if alreada 100 planes sent the current day
|
||||
|
||||
|
||||
$.post("avionJournalier.php", function(result) {
|
||||
result = result.replace(/'/g, '"');
|
||||
result = $.parseJSON(result)
|
||||
nbPlane = Number(result.nAvion)
|
||||
$("#buttonNewPlane").val("Lancer un avion-poème "+Number(result.nAvion)+"/100")
|
||||
if (nbPlane > 99){
|
||||
$("#buttonNewPlane").prop("disabled",true);
|
||||
}
|
||||
else{
|
||||
|
||||
}
|
||||
translateUI(lang)
|
||||
})
|
||||
|
||||
//background
|
||||
L.tileLayer('https://server.arcgisonline.com/ArcGIS/rest/services/World_Imagery/MapServer/tile/{z}/{y}/{x}', {
|
||||
attribution: '',
|
||||
//minZoom:8,
|
||||
maxZoom: 16,
|
||||
}).addTo(map);
|
||||
|
||||
//adding terminator
|
||||
var terminator = L.terminator()
|
||||
.addTo(map);
|
||||
setInterval(function() {
|
||||
terminator.setTime();
|
||||
}, 1000);
|
||||
|
||||
|
||||
//center map on sun by default
|
||||
function centerOnSun(){
|
||||
var equator = turf.lineString([[-1000, 0], [1000, 0]])
|
||||
var intersects = turf.lineIntersect(equator, terminator.toGeoJSON());
|
||||
//console.log(intersects)
|
||||
var lonCenter = ((intersects.features[1].geometry.coordinates[0])+(intersects.features[2].geometry.coordinates[0]))/2
|
||||
//console.log(lonCenter)
|
||||
return lonCenter
|
||||
}
|
||||
map.setView([30,0], 2);
|
||||
|
||||
|
||||
//could layer from GBIS NASA - always 1 day of delay
|
||||
var twoDaysAgo = moment(new Date()).subtract(2, "days").format('YYYY-MM-DD')
|
||||
L.tileLayer('https://map1.vis.earthdata.nasa.gov/wmts-webmerc/VIIRS_SNPP_CorrectedReflectance_TrueColor/default/'+twoDaysAgo+'/GoogleMapsCompatible_Level9/{z}/{y}/{x}.jpg', {
|
||||
attribution: '',
|
||||
maxZoom: 8,
|
||||
opacity:0.4
|
||||
})
|
||||
.addTo(map);
|
||||
|
||||
|
||||
//Bluring the terminator | Source: https://stackoverflow.com/questions/28235792/leaflet-polygon-with-fuzzy-outline
|
||||
var svg = map.getPanes().overlayPane.firstChild,
|
||||
svgFilter = document.createElementNS('http://www.w3.org/2000/svg', 'filter'),
|
||||
svgBlur = document.createElementNS('http://www.w3.org/2000/svg', 'feGaussianBlur');
|
||||
svgFilter.setAttribute('id', 'blur');
|
||||
svgFilter.setAttribute('x', '-100%');
|
||||
svgFilter.setAttribute('y', '-100%');
|
||||
svgFilter.setAttribute('width', '500%');
|
||||
svgFilter.setAttribute('height', '500%');
|
||||
svgBlur.setAttribute('stdDeviation', 15);
|
||||
svgFilter.appendChild(svgBlur);
|
||||
svg.appendChild(svgFilter);
|
||||
terminator._path.setAttribute('filter', 'url(#blur)');
|
||||
|
||||
//geojson for arclines
|
||||
//travel
|
||||
var arcTravelStyle = {
|
||||
"color": "#00ff00",
|
||||
"weight": 2.5,
|
||||
"dashArray": "10 5",
|
||||
"opacity": 0.65
|
||||
};
|
||||
var arcTravel = L.geoJSON([],{style: arcTravelStyle}).addTo(map);
|
||||
//travelled
|
||||
var arcTravelledStyle = {
|
||||
"color": "#00ff00",
|
||||
"weight": 2.5,
|
||||
"opacity": 0.65
|
||||
};
|
||||
var arcTravelled = L.geoJSON([],{style: arcTravelledStyle}).addTo(map);
|
||||
|
||||
var pulsatingMarker = L.layerGroup([]).addTo(map)
|
||||
var originMarker = L.layerGroup([]).addTo(map)
|
||||
|
||||
var firstDraw = true;
|
||||
var prevZoom;
|
||||
|
||||
var pixiOverlay = L.pixiOverlay(function(utils, event) {
|
||||
var zoom = utils.getMap().getZoom();
|
||||
var container = utils.getContainer();
|
||||
var renderer = utils.getRenderer();
|
||||
var project = utils.latLngToLayerPoint;
|
||||
var scale = utils.getScale();
|
||||
|
||||
if (firstDraw) {
|
||||
|
||||
//get planes
|
||||
$.post( "getCurrentPlanes.php", function(result) {
|
||||
// console.log(result)
|
||||
var planes = $.parseJSON(result)
|
||||
console.log(planes)
|
||||
function formatResults(data){
|
||||
data.deliveryTime = Number(data.deliveryTime)*1000
|
||||
data.startTime = Number(data.startTime)*1000
|
||||
return data
|
||||
}
|
||||
|
||||
function displayPlane(data){
|
||||
var line = turf.greatCircle(turf.point([Number(data.startLon),Number(data.startLat)]), turf.point([Number(data.destLon),Number(data.destLat)]),{offset:20})
|
||||
var lineDistance = turf.length(line);
|
||||
var dateStart = moment(data.startTime)
|
||||
var dateEnd = moment(data.deliveryTime)
|
||||
var dateNow = moment(new Date())
|
||||
var totalSeconds = dateEnd.diff(dateStart,'seconds');
|
||||
var travelledSeconds = dateNow.diff(dateStart,'seconds')
|
||||
var travelRatio = travelledSeconds/totalSeconds
|
||||
var travelledDistance = lineDistance*travelRatio // getting the travelled distance
|
||||
var segment;
|
||||
if(line.geometry.type == "MultiLineString"){ // if the arc is cutting the dateline, well it's a mess.
|
||||
var l1 = turf.lineString(line.geometry.coordinates[0]) // creating a line from first segment
|
||||
var l2 = turf.lineString(line.geometry.coordinates[1]) // creating a line from second segment
|
||||
var l1Length = turf.length(l1) // calculating length of first segment
|
||||
if (travelledDistance < l1Length){ // if the travelled distance is inferior to segment 1 line, the point is somewhere in it
|
||||
segment = l1
|
||||
data.position = 1
|
||||
}
|
||||
else{
|
||||
segment = l2 // otherwise on segment 2
|
||||
data.position = 2
|
||||
travelledDistance = Number(travelledDistance)-Number(l1Length) // we remove the travel distance done in s1
|
||||
}
|
||||
}
|
||||
else{
|
||||
segment = line
|
||||
data.position = 0
|
||||
}
|
||||
var currentPosition = turf.along(segment, travelledDistance,{units: 'kilometers'})
|
||||
if(currentPosition.geometry.coordinates[0] < -180){currentPosition.geometry.coordinates[0] = currentPosition.geometry.coordinates[0]+360}
|
||||
if(currentPosition.geometry.coordinates[0] > 180){currentPosition.geometry.coordinates[0] = currentPosition.geometry.coordinates[0]-Number(360)}
|
||||
//calculating bearing based on two points, one just before and one just after
|
||||
var positionBefore = turf.along(segment, (travelledDistance)-0.00001,{units: 'kilometers'})
|
||||
var positionAfter = turf.along(segment, (travelledDistance)+0.00001,{units: 'kilometers'})
|
||||
var rotation = turf.bearing(
|
||||
positionBefore,
|
||||
positionAfter
|
||||
);
|
||||
|
||||
//plane
|
||||
var iconColor = 'marker'+data.color
|
||||
var markerTexture = resources[iconColor].texture;
|
||||
var marker = new PIXI.Sprite(markerTexture);
|
||||
marker.anchor.set(0.5, 0.5);
|
||||
var markerCoords = project([currentPosition.geometry.coordinates[1],currentPosition.geometry.coordinates[0]]);
|
||||
marker.x = markerCoords.x;
|
||||
marker.y = markerCoords.y;
|
||||
marker.angle = rotation;
|
||||
marker.scale.set(5);
|
||||
marker.interactive = true;
|
||||
marker.cursor = 'pointer'
|
||||
marker.data = data
|
||||
marker.data.line = line
|
||||
marker.data.currentPosition = currentPosition
|
||||
|
||||
//shadow
|
||||
var shadowTexture = resources.shadow.texture;
|
||||
var shadow = new PIXI.Sprite(shadowTexture);
|
||||
shadow.anchor.set(0.5, 0.5);
|
||||
shadow.x = markerCoords.x;
|
||||
shadow.y = markerCoords.y + 0.5;
|
||||
shadow.angle = rotation;
|
||||
shadow.scale.set(0.00025);
|
||||
shadow.alpha = 0.3
|
||||
shadow.visible = false
|
||||
|
||||
//popup
|
||||
marker.popup = L.popup({className: 'pixi-popup'})
|
||||
|
||||
pixiContainer.addChild(shadow);
|
||||
pixiContainer.addChild(marker);
|
||||
|
||||
renderer.render(container)
|
||||
|
||||
//adapting scale based on zoom level. Max zoom = writting visible
|
||||
map.on('zoomend', function() {
|
||||
marker.scale.set((1/(utils.getScale(map.getZoom())*20))+(Math.pow(map.getZoom(),2)/100*2*(1/(utils.getScale(map.getZoom())*20))))
|
||||
if(map.getZoom() == 16){
|
||||
shadow.visible = true
|
||||
}
|
||||
else{
|
||||
shadow.visible = false
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
//animating moving plane
|
||||
setInterval(function() {
|
||||
animate();
|
||||
}, 1000)
|
||||
|
||||
function animate() {
|
||||
if (map.getZoom() > 12){ // we animate only starting zoom 12
|
||||
var bounds = map.getBounds()
|
||||
var bbox = [bounds._southWest.lng, bounds._southWest.lat, bounds._northEast.lng, bounds._northEast.lat];
|
||||
var extentPoly = turf.bboxPolygon(bbox);
|
||||
var planeInExtent = turf.booleanWithin(marker.data.currentPosition, extentPoly);
|
||||
if(planeInExtent == true){ // we animate only the planes in map extent
|
||||
var dateNow = moment(new Date())
|
||||
var totalSeconds = dateEnd.diff(dateStart,'seconds');
|
||||
var travelledSeconds = dateNow.diff(dateStart,'seconds')
|
||||
var travelRatio = travelledSeconds/totalSeconds
|
||||
var lineDistance = turf.length(line);
|
||||
var segment;
|
||||
var travelledDistance = lineDistance*travelRatio // getting the travelled distance
|
||||
if(line.geometry.type == "MultiLineString"){ // if the arc is cutting the dateline
|
||||
var l1 = turf.lineString(line.geometry.coordinates[0]) // creating a line from first segment
|
||||
var l2 = turf.lineString(line.geometry.coordinates[1]) // creating a line from second segment
|
||||
var l1Length = turf.length(l1) // calculating length of first segment
|
||||
if (travelledDistance < l1Length){ // if the travelled distance is inferior to segment 1 line, the point is somewhere in it
|
||||
segment = l1
|
||||
marker.data.position = 1 // we store it, usefull for popup event
|
||||
}
|
||||
else{
|
||||
segment = l2 // otherwise on segment 2
|
||||
marker.data.position = 2
|
||||
travelledDistance = Number(travelledDistance)-Number(l1Length) // we remove the travel distance done in s1
|
||||
}
|
||||
}
|
||||
else{
|
||||
segment = line
|
||||
}
|
||||
var currentPosition = turf.along(segment, travelledDistance,{units: 'kilometers'})
|
||||
//troubleshooting extreme lons
|
||||
if(currentPosition.geometry.coordinates[0] < -180){currentPosition.geometry.coordinates[0] = currentPosition.geometry.coordinates[0]+360}
|
||||
if(currentPosition.geometry.coordinates[0] > 180){currentPosition.geometry.coordinates[0] = currentPosition.geometry.coordinates[0]-Number(360)}
|
||||
marker.data.currentPosition = currentPosition
|
||||
var markerCoords = project([currentPosition.geometry.coordinates[1],currentPosition.geometry.coordinates[0]]);
|
||||
marker.x = markerCoords.x;
|
||||
marker.y = markerCoords.y;
|
||||
shadow.x = markerCoords.x;
|
||||
shadow.y = markerCoords.y + 0.5;
|
||||
renderer.render(container);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//if parameter in URL, zoom on it
|
||||
var queryString = window.location.search;
|
||||
queryString = queryString.split('=')[1]
|
||||
if(Number(queryString)==data.uid){
|
||||
setTimeout(
|
||||
function()
|
||||
{
|
||||
map.setView([data.currentPosition.geometry.coordinates[1],data.currentPosition.geometry.coordinates[0]], 15);
|
||||
openPopup(marker)
|
||||
}, 100);
|
||||
}
|
||||
|
||||
}
|
||||
for (var i in planes){
|
||||
displayPlane(formatResults(planes[i]),0)
|
||||
}
|
||||
});
|
||||
|
||||
function openPopup(target){
|
||||
//drawing arcs
|
||||
arcTravel.clearLayers()
|
||||
arcTravelled.clearLayers()
|
||||
arcTravelStyle.color = '#'+target.data.color
|
||||
arcTravelledStyle.color = '#'+target.data.color
|
||||
var travel = target.data.line
|
||||
var start = turf.point([Number(target.data.startLon),Number(target.data.startLat)])
|
||||
var current = target.data.currentPosition
|
||||
var end = turf.point([Number(target.data.destLon),Number(target.data.destLat)])
|
||||
// for linestrings
|
||||
if(travel.geometry.type == "LineString"){
|
||||
var sliced1 = turf.lineSlice(start, current, travel);
|
||||
var sliced2 = turf.lineSlice(current, end, travel);
|
||||
arcTravelled.addData(sliced1);
|
||||
arcTravel.addData(sliced2);
|
||||
}
|
||||
// we create a copy of lines crossing the datetime
|
||||
function createCopy(c){
|
||||
for (var i in c.geometry.coordinates){
|
||||
if (c.geometry.coordinates[i][0] > 0){
|
||||
c.geometry.coordinates[i][0] = c.geometry.coordinates[i][0] - Number(360)
|
||||
}
|
||||
else{
|
||||
c.geometry.coordinates[i][0] = c.geometry.coordinates[i][0] + Number(360)
|
||||
}
|
||||
}
|
||||
|
||||
return c
|
||||
}
|
||||
//for multilinetrings
|
||||
if(travel.geometry.type == "MultiLineString"){
|
||||
var l1 = turf.lineString(travel.geometry.coordinates[0]) // creating a line from first segment
|
||||
var l2 = turf.lineString(travel.geometry.coordinates[1]) // creating a line from second segment
|
||||
if(target.data.position == 1){
|
||||
var sliced1 = turf.lineSlice(start, current, l1);
|
||||
var sliced2 = turf.lineSlice(current, turf.point(l1.geometry.coordinates[l1.geometry.coordinates.length-1]), l1);
|
||||
arcTravelled.addData(sliced1);
|
||||
arcTravel.addData(sliced2);
|
||||
arcTravel.addData(l2);
|
||||
|
||||
}
|
||||
else if(target.data.position == 2){
|
||||
var sliced1 = turf.lineSlice(turf.point(l2.geometry.coordinates[0]), current, l2);
|
||||
var sliced2 = turf.lineSlice(current, end, l2);
|
||||
arcTravelled.addData(l1);
|
||||
arcTravelled.addData(sliced1);
|
||||
arcTravel.addData(sliced2);
|
||||
}
|
||||
var travelledGeoJSON = arcTravelled.toGeoJSON()
|
||||
for (var i in travelledGeoJSON.features){
|
||||
arcTravelled.addData(createCopy(travelledGeoJSON.features[i]))
|
||||
}
|
||||
var travelGeoJSON = arcTravel.toGeoJSON()
|
||||
for (var i in travelGeoJSON.features){
|
||||
arcTravel.addData(createCopy(travelGeoJSON.features[i]))
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
//add pulsating marker on destination;
|
||||
pulsatingMarker.clearLayers()
|
||||
var pulseIcon = L.divIcon({
|
||||
className: 'pulse-icon', //empty class to overwrite leaflet defaults
|
||||
html: '<div class="pulse-icon-anim" style="border-color:#'+target.data.color+'"></div>',
|
||||
iconSize: [22,22]
|
||||
});
|
||||
var endCoordo = [Number(target.data.destLat),Number(target.data.destLon)]
|
||||
pulsatingMarker.addLayer(new L.marker(endCoordo, {icon: pulseIcon}));
|
||||
if(travel.geometry.type == "MultiLineString"){ //if arc cross dateline, we multiply the marker
|
||||
pulsatingMarker.addLayer(new L.marker([endCoordo[0],endCoordo[1]-Number(360)], {icon: pulseIcon}));
|
||||
pulsatingMarker.addLayer(new L.marker([endCoordo[0],endCoordo[1]+Number(360)], {icon: pulseIcon}));
|
||||
}
|
||||
|
||||
//adding static marker on origin
|
||||
originMarker.clearLayers()
|
||||
var startCoordo = [Number(target.data.startLat),Number(target.data.startLon)]
|
||||
originMarker.addLayer(new L.circleMarker(startCoordo, {radius: 6,opacity:0.7, weight:2,color:'#'+target.data.color}));
|
||||
if(travel.geometry.type == "MultiLineString"){ //if arc cross dateline, we multiply the marker
|
||||
originMarker.addLayer(new L.circleMarker([startCoordo[0],startCoordo[1]-Number(360)], {radius: 6,opacity:0.7,weight:2,color:'#'+target.data.color}));
|
||||
originMarker.addLayer(new L.circleMarker([startCoordo[0],startCoordo[1]+Number(360)], {radius: 6,opacity:0.7,color:'#'+target.data.color}));
|
||||
}
|
||||
|
||||
|
||||
|
||||
//popup
|
||||
var momentLocale = lang;
|
||||
if (momentLocale == 'zh'){momentLocale = 'zh-cn'} //troubleshot for chinese
|
||||
moment.locale(momentLocale)
|
||||
|
||||
target.popup.setLatLng([target.data.currentPosition.geometry.coordinates[1],target.data.currentPosition.geometry.coordinates[0]])
|
||||
//arabic popup
|
||||
if(lang=="ar"){
|
||||
target.popup.setContent('<table><tbody><tr><th style="text-align:center">'+target.data.startName+'</th><th> <i class="fas fa-plane"></i> </th><th style="text-align:center">'+target.data.destName+'</th></tr><tr><th style="text-align:center"><small>'+moment(target.data.startTime).fromNow()+'</small></th><th></th><th style="text-align:center"><small>'+moment(target.data.deliveryTime).fromNow()+'</small></th></tr></tbody></table>')
|
||||
}
|
||||
//other languages
|
||||
else{
|
||||
target.popup.setContent('<table><tbody><tr><th style="text-align:center">'+target.data.startName+'</th><th> <i class="fas fa-plane"></i> </th><th style="text-align:center">'+target.data.destName+'</th></tr><tr><th style="text-align:center"><small>'+moment(target.data.startTime).fromNow()+'</small></th><th></th><th style="text-align:center"><small>'+moment(target.data.deliveryTime).fromNow()+'</small></th></tr></tbody></table>')
|
||||
}
|
||||
target.popup.openOn(map);
|
||||
target.popup.on('remove', function() {
|
||||
arcTravel.clearLayers()
|
||||
arcTravelled.clearLayers()
|
||||
pulsatingMarker.clearLayers()
|
||||
originMarker.clearLayers()
|
||||
});
|
||||
target.popup.on('popupclose', function() {
|
||||
arcTravel.clearLayers()
|
||||
arcTravelled.clearLayers()
|
||||
pulsatingMarker.clearLayers()
|
||||
originMarker.clearLayers()
|
||||
});
|
||||
}
|
||||
//utils for popup
|
||||
utils.getMap().on('click', function(e) {
|
||||
var interaction = utils.getRenderer().plugins.interaction;
|
||||
var pointerEvent = e.originalEvent;
|
||||
var pixiPoint = new PIXI.Point();
|
||||
interaction.mapPositionToPoint(pixiPoint, pointerEvent.clientX, pointerEvent.clientY);
|
||||
var target = interaction.hitTest(pixiPoint, container);
|
||||
if (target && target.popup) {
|
||||
openPopup(target)
|
||||
}
|
||||
});
|
||||
utils.getMap().on('touchend', function(e) {
|
||||
var interaction = utils.getRenderer().plugins.interaction;
|
||||
var pointerEvent = e.originalEvent;
|
||||
var pixiPoint = new PIXI.Point();
|
||||
interaction.mapPositionToPoint(pixiPoint, pointerEvent.clientX, pointerEvent.clientY);
|
||||
var target = interaction.hitTest(pixiPoint, container);
|
||||
if (target && target.popup) {
|
||||
openPopup(target)
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
|
||||
firstDraw = false;
|
||||
prevZoom = zoom;
|
||||
renderer.render(container);
|
||||
}, pixiContainer);
|
||||
pixiOverlay.addTo(map);
|
||||
});
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//hack to make white lines between lines disapear on non-retina screens (from: https://github.com/Leaflet/Leaflet/issues/3575 )
|
||||
(function(){
|
||||
var originalInitTile = L.GridLayer.prototype._initTile
|
||||
L.GridLayer.include({
|
||||
_initTile: function (tile) {
|
||||
originalInitTile.call(this, tile);
|
||||
|
||||
var tileSize = this.getTileSize();
|
||||
|
||||
tile.style.width = tileSize.x + 1 + 'px';
|
||||
tile.style.height = tileSize.y + 1 + 'px';
|
||||
}
|
||||
});
|
||||
})()
|
||||
|
240
src/newPlane.js
@ -12,99 +12,195 @@ var quill = new Quill('#messageTextArea', {
|
||||
theme: 'snow' // or 'bubble',
|
||||
});
|
||||
|
||||
// get random number between interval
|
||||
function randomIntFromInterval(min, max) { // min and max included
|
||||
return Math.floor(Math.random() * (max - min + 1) + min);
|
||||
}
|
||||
|
||||
// get random color
|
||||
function getRandomColor() {
|
||||
var colors = ['66FF00','FF5555','FFE419','2A7FFF','BC5FD3','FF6600','ECECEC']
|
||||
var color = colors[Math.floor(Math.random() * colors.length)];
|
||||
return color
|
||||
}
|
||||
|
||||
//init tooltips in form
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip()
|
||||
})
|
||||
|
||||
//closing navbar antholoy about on open
|
||||
$('#newPlaneModal').on('shown.bs.modal', function (e) {
|
||||
$('.navbar-collapse').collapse('hide');
|
||||
$('#anthology').css('opacity','0')
|
||||
$('#anthology').css('visibility','hidden')
|
||||
$('#backToMap').css('opacity','0')
|
||||
$('#backToMap').css('visibility','hidden')
|
||||
$('#about').css('visibility','hidden');
|
||||
$('#about').css('opacity','0')
|
||||
anthologyOpen = 0
|
||||
aboutOpen = 0
|
||||
})
|
||||
|
||||
$("#sendNewPlane").on('click',function(){
|
||||
|
||||
//hiding navbar
|
||||
$('.navbar-collapse').collapse('hide');
|
||||
|
||||
//hiding modal
|
||||
$("#newPlaneModal").modal('hide')
|
||||
|
||||
var line = turf.lineString([expeLoc.center,destLoc.center]) //create line between start and end
|
||||
var length = turf.length(line) //get length in Km
|
||||
var speed = 30 //speed in km/h
|
||||
var time = length/speed //time to delivery in hours
|
||||
var deliveryMethod = $("#selectTime").val()
|
||||
|
||||
var time; //time to delivery in hours
|
||||
|
||||
|
||||
if(deliveryMethod == '3days'){
|
||||
time = 24*3.14
|
||||
}
|
||||
else if(deliveryMethod == '7days'){
|
||||
time = 24*7
|
||||
}
|
||||
else if(deliveryMethod == '30days'){
|
||||
time = 24*30
|
||||
}
|
||||
else if(deliveryMethod == '365days'){
|
||||
time = 24*365
|
||||
}
|
||||
else if(deliveryMethod == 'random'){
|
||||
var speed = randomIntFromInterval(5.05, 25.82)
|
||||
|
||||
var line = turf.lineString([expeLoc.center,destLoc.center]) //create line between start and end
|
||||
var length = turf.length(line) //get length in Km
|
||||
var additionalTime = length/speed;
|
||||
time = 37.68 + additionalTime //minimum 37.68 hours + additional time based on random speed
|
||||
|
||||
}
|
||||
|
||||
|
||||
//get the local time with TZ for starting point
|
||||
$.getJSON('https://api.mapbox.com/v4/examples.4ze9z6tv/tilequery/'+expeLoc.center[0]+','+expeLoc.center[1]+'.json?access_token='+mapboxgl.accessToken+'',function(startTime){
|
||||
var expeTimezone = startTime.features[0].properties.TZID;
|
||||
var sentDate = moment.tz(new Date(), expeTimezone);
|
||||
sentDate = [sentDate.format(),expeTimezone]
|
||||
$.getJSON('https://secure.geonames.org/timezoneJSON?lat='+expeLoc.center[1]+'&lng='+expeLoc.center[0]+'&username=avionpoeme',function(startTime){
|
||||
var expeTimezone = startTime.timezoneId;
|
||||
|
||||
var sentDate = moment.tz(new Date(), expeTimezone).unix();
|
||||
|
||||
|
||||
|
||||
//get the local time with TZ for end point
|
||||
$.getJSON('https://api.mapbox.com/v4/examples.4ze9z6tv/tilequery/'+destLoc.center[0]+','+destLoc.center[1]+'.json?access_token='+mapboxgl.accessToken+'',function(endTime){
|
||||
var destTimezone = endTime.features[0].properties.TZID;
|
||||
var endDate = moment.tz(new Date(), destTimezone);
|
||||
var deliveryDate = endDate.add(time, 'hours') // adding hours
|
||||
deliveryDate = [endDate.format(),destTimezone]
|
||||
$.getJSON('https://secure.geonames.org/timezoneJSON?lat='+destLoc.center[1]+'&lng='+destLoc.center[0]+'&username=avionpoeme',function(endTime){
|
||||
var destTimezone = endTime.timezoneId;
|
||||
|
||||
var endDate = moment.tz(new Date(), destTimezone)
|
||||
var deliveryDate = endDate.add(time, 'hours').unix(); // adding hours
|
||||
|
||||
|
||||
//storing the endDate in GMT+0 in seconds for the query
|
||||
var deliverySecondsServer = moment.tz(new Date(), "Europe/London").add(time, 'hours').unix()
|
||||
var deliverySecondsServer = moment.tz(new Date(), "Europe/Berlin").add(time, 'hours').unix()
|
||||
|
||||
var publicMessage = $("#publicMessage").prop("checked")
|
||||
var message = $("#messageTextArea").val()
|
||||
var publicMessage = $("#public").prop("checked")
|
||||
|
||||
var expeKnown = $("#expeKnown").prop("checked")
|
||||
if(expeKnown == true){
|
||||
expeKnown = false
|
||||
}
|
||||
else{
|
||||
expeKnown = true
|
||||
}
|
||||
|
||||
var message = quill.root.innerHTML
|
||||
|
||||
var randomColor = getRandomColor()
|
||||
|
||||
console.log(message)
|
||||
|
||||
var data = {
|
||||
'message':message,
|
||||
'public':publicMessage,
|
||||
'message':encodeURIComponent(message),
|
||||
'expeMail':$("#expeMail").val(),
|
||||
'expeKnown':expeKnown,
|
||||
'expeLang':lang,
|
||||
'destLang':$("#selectDestLang").val(),
|
||||
'startLat':expeLoc.center[1],
|
||||
'startLon':expeLoc.center[0],
|
||||
'startName':expeLoc.name,
|
||||
'startTime':sentDate,
|
||||
'startTZ':expeTimezone,
|
||||
'destMail':$("#destMail").val(),
|
||||
'expeName':expeLoc.name,
|
||||
'destLat':destLoc.center[1],
|
||||
'destLon':destLoc.center[0],
|
||||
'destName':destLoc.name,
|
||||
'expeCoordo':expeLoc.center,
|
||||
'destCoordo':destLoc.center,
|
||||
'sentDate': sentDate,
|
||||
'deliveryDate':deliveryDate,
|
||||
'deliverySecondsServer':deliverySecondsServer,
|
||||
'public':publicMessage,
|
||||
'color':randomColor,
|
||||
'deliveryTime':deliveryDate,
|
||||
'deliveryTZ':destTimezone,
|
||||
'deliveryTimeServer':deliverySecondsServer,
|
||||
'deliveryMethod':$("#selectTime").val()
|
||||
}
|
||||
//sending confirm mail
|
||||
|
||||
//sending notif mail
|
||||
|
||||
//scheduling mail
|
||||
|
||||
//adding the plane
|
||||
var planes = db.collection('planes')
|
||||
if (!publicMessage){ //removing message from DB if not public
|
||||
data.message = ''
|
||||
}
|
||||
planes.add({
|
||||
public: data.public,
|
||||
message:data.message,
|
||||
destName: data.destName,
|
||||
destCoordo: data.destCoordo,
|
||||
startName: data.expeName,
|
||||
startCoordo: data.expeCoordo,
|
||||
sentDate: data.sentDate,
|
||||
deliveryDate: data.deliveryDate,
|
||||
deliverySecondsServer: data.deliverySecondsServer
|
||||
});
|
||||
|
||||
// creating image for plane, need to link it to the inputs tog et entered values.
|
||||
var canvas = document.getElementById("blankCanvas");
|
||||
var ctx = canvas.getContext("2d");
|
||||
ctx.fillStyle = "rgb(255,255,255)";
|
||||
ctx.fillRect(0,0,400,400);
|
||||
ctx.fillStyle = "rgb(0,0,0)";
|
||||
ctx.font = "9px Courier";
|
||||
ctx.fillText("Message: .- / -- --- -. / ... . -. ... --..-- /",10,60);
|
||||
ctx.fillText("Expediteur: leo.martine@yahoo.fr - Annemasse",10,300);
|
||||
ctx.fillText("Destinataire: leo.martine@yahoo.fr - Lyon",10,320);
|
||||
$("#front").attr('src',document.getElementById("blankCanvas").toDataURL())
|
||||
|
||||
|
||||
//display and animate plane
|
||||
$("#canvas3d").css('display','block')
|
||||
animePlane()
|
||||
//moving plane at the end
|
||||
setInterval(function(){
|
||||
$("#canvas3d").css('transition','transform 2500ms ease-in-out')
|
||||
$("#canvas3d").css('transform','translate(50vw, -150vh)')
|
||||
},4400);
|
||||
//reloading page (to change)
|
||||
setInterval(function(){
|
||||
window.location.href = "http://127.0.0.1:8887/?plane=1FTMbm9V9eindbwoJ9uW";
|
||||
},5500);
|
||||
var query = 'avionpoeme.php?'+
|
||||
'message='+data.message+'&'+
|
||||
'expeMail='+data.expeMail+'&'+
|
||||
'expeKnown='+data.expeKnown+'&'+
|
||||
'expeLang='+data.expeLang+'&'+
|
||||
'destLang='+data.destLang+'&'+
|
||||
'startLat='+data.startLat+'&'+
|
||||
'startLon='+data.startLon+'&'+
|
||||
'startName='+data.startName+'&'+
|
||||
'startTime='+data.startTime+'&'+
|
||||
'startTZ='+data.startTZ+'&'+
|
||||
'destMail='+data.destMail+'&'+
|
||||
'destLat='+data.destLat+'&'+
|
||||
'destLon='+data.destLon+'&'+
|
||||
'destName='+data.destName+'&'+
|
||||
'public='+data.public+'&'+
|
||||
'color='+data.color+'&'+
|
||||
'deliveryTime='+data.deliveryTime+'&'+
|
||||
'deliveryTZ='+data.deliveryTZ+'&'+
|
||||
'deliveryTimeServer='+data.deliveryTimeServer+'&'+
|
||||
'deliveryMethod='+data.deliveryMethod+'';
|
||||
|
||||
$.post(query, function(result) {
|
||||
result = result.replace(/'/g, '"');
|
||||
console.log(result)
|
||||
result = $.parseJSON(result)
|
||||
var planeId = Number(result.uid);
|
||||
//selecting proper color for back
|
||||
$("#back").attr("src","src/img/back-"+data.color+".jpg");
|
||||
|
||||
// creating image for plane, need to link it to the inputs tog et entered values.
|
||||
var message = quill.root.innerHTML
|
||||
|
||||
var canvas1 = document.getElementById("blankCanvas1"),
|
||||
html = quill.root.innerHTML;
|
||||
|
||||
rasterizeHTML.drawHTML(html, canvas1,{zoom:0.7}).then(function success(renderResult) {
|
||||
|
||||
var canvas2 = document.getElementById("blankCanvas2");
|
||||
var ctx = canvas2.getContext("2d");
|
||||
ctx.fillStyle = "#"+data.color;
|
||||
ctx.fillRect(0,0,400,400);
|
||||
ctx.drawImage(canvas1, 0, 0,400,400)
|
||||
ctx.fillStyle = "rgb(0,0,0)";
|
||||
ctx.font = "9px Courier";
|
||||
$("#front").attr('src',document.getElementById("blankCanvas2").toDataURL())
|
||||
//display and animate plane
|
||||
$("#canvas3d").css('display','block')
|
||||
animePlane()
|
||||
|
||||
|
||||
//moving plane at the end
|
||||
setInterval(function(){
|
||||
$("#canvas3d").css('transition','transform 2500ms ease-in-out')
|
||||
$("#canvas3d").css('transform','translate(50vw, -150vh)')
|
||||
},4400);
|
||||
//reloading page (to change)
|
||||
setInterval(function(){
|
||||
window.location.href ='https://avion-poe.me?avion='+planeId+'';
|
||||
},5500);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
})
|
||||
});
|
||||
|
164
src/translation.js
Normal file
@ -0,0 +1,164 @@
|
||||
var lang = 'en'
|
||||
var userLang = navigator.userLanguage || navigator.language;
|
||||
if (userLang){
|
||||
lang = userLang.substring(0,2)
|
||||
}
|
||||
|
||||
//loading the lang.json file
|
||||
$(document).ready(function(){
|
||||
translateUI(lang)
|
||||
$.getJSON("lang/lang.json", function(data){
|
||||
//creating dropdown list of languages in navbar
|
||||
for (var key in data){
|
||||
$("#langChoices").append( '<a class="dropdown-item langSelect" value="'+key+'" href="#">'+data[key]+'</a>' )
|
||||
$("#selectDestLang").append( '<option value="'+key+'" href="#">'+data[key]+'</option>' )
|
||||
}
|
||||
//setting the user lang
|
||||
if(data[lang]){
|
||||
//$("#navbarDropdownLang").html(data[lang])
|
||||
translateUI(lang)
|
||||
}
|
||||
//or english if not in list
|
||||
else{
|
||||
//$("#navbarDropdownLang").html("English")
|
||||
translateUI('en')
|
||||
}
|
||||
$(".langSelect").on('click',function(e){
|
||||
lang = e.currentTarget.attributes[1].value
|
||||
translateUI(lang)
|
||||
//$("#navbarDropdownLang").html($(this).html())
|
||||
})
|
||||
}).fail(function(error){
|
||||
console.log(error);
|
||||
});
|
||||
});
|
||||
|
||||
var dictionnary = []
|
||||
|
||||
function translateUI(l){
|
||||
$.getJSON("lang/"+l+"", function(s){
|
||||
//console.log(s)
|
||||
dictionnary = s
|
||||
//if arabic : display left to right (ltr) + troubleshooting a lot of individual elements
|
||||
if (lang == "ar"){
|
||||
//navbar
|
||||
$("nav").css('direction','rtl')
|
||||
$(".nav-menus").removeClass('mr-auto')
|
||||
$(".nav-button").addClass('mr-auto')
|
||||
//form
|
||||
// $(".ql-container").css('direction','rtl')
|
||||
// $(".ql-container").css('float','right')
|
||||
// $(".ql-editor").css('float','right')
|
||||
// $(".ql-editor p").css('float','right')
|
||||
$(".modal-content").css('direction','rtl')
|
||||
$(".bold").css('float','right')
|
||||
$("#public").css('margin-left','5px')
|
||||
$("#prive").css('margin-left','5px')
|
||||
$("#newPlaneModalAnonyme").css('margin-right','25px')
|
||||
$("#newPlaneModalCancel").css('margin-left','8px')
|
||||
$("#closeModal").css('margin-left','0px')
|
||||
$("#closeModal").css('padding-left','0px')
|
||||
//anthology
|
||||
$("#anthology").css('direction','rtl')
|
||||
$("#anthologyDisclaimer").css('float','right')
|
||||
|
||||
}
|
||||
else{
|
||||
//navbar
|
||||
$("nav").css('direction','ltr')
|
||||
$(".nav-menus").addClass('mr-auto')
|
||||
$(".nav-button").removeClass('mr-auto')
|
||||
//form
|
||||
// $(".ql-container").css('direction','ltr')
|
||||
// $(".ql-container").css('float','left')
|
||||
// $(".ql-editor").css('float','left')
|
||||
// $(".ql-editor p").css('float','none')
|
||||
$(".modal-content").css('direction','ltr')
|
||||
$(".bold").css('float','left')
|
||||
$("#public").css('margin-left','0px')
|
||||
$("#prive").css('margin-left','0px')
|
||||
$("#newPlaneModalAnonyme").css('margin-right','0px')
|
||||
$("#newPlaneModalCancel").css('margin-left','0px')
|
||||
//anthology
|
||||
$("#anthology").css('direction','ltr')
|
||||
$("#anthologyDisclaimer").css('float','left')
|
||||
}
|
||||
|
||||
//changing all strings
|
||||
//main page
|
||||
$('head title', window.parent.document).text(s.avionpoeme);
|
||||
$("#navTitle").html(s.avionpoeme)
|
||||
$("#buttonAnthology").html(s.anthologie)
|
||||
$("#buttonAbout").html(s.apropos)
|
||||
$("#buttonNewPlane").val(s.lancer_avion+" "+nbPlane+"/100")
|
||||
//new plane form
|
||||
$("#newPlaneModalTitle").html(s.lancer_avion)
|
||||
$("#newPlaneModalMessage").html(s.message)
|
||||
$("#newPlaneModalPrive").html(s.prive)
|
||||
$("#newPlaneModalPublic").html(s.public)
|
||||
$("#flightTime").html(s.temps_de_vol)
|
||||
$("#newPlaneModalRandom").html(s.aléatoire)
|
||||
$("#newPlaneModal3j").html(s.trois_jours)
|
||||
$("#newPlaneModal7j").html(s.sept_jours)
|
||||
$("#newPlaneModal30j").html(s.trente_jours)
|
||||
$("#newPlaneModal365j").html(s.unan_jours)
|
||||
$("#newPlaneModalExpediteur").html(s.expediteur)
|
||||
$("#newPlaneModalDestinataire").html(s.destinataire)
|
||||
$("#newPlaneModalAnonyme").html(s.anonyme)
|
||||
$("#newPlaneModalCancel").html(s.annuler)
|
||||
$("#sendNewPlane").html(s.lancer)
|
||||
$("#destLang").html(s.langue_destinataire)
|
||||
$("#expeMail").attr("placeholder", s.expeMail_placeholder)
|
||||
$("#expeGeocoderPhoton").attr("placeholder", s.expeLoc_placeholder)
|
||||
$("#destMail").attr("placeholder", s.destMail_placeholder)
|
||||
$("#destGeocoderPhoton").attr("placeholder", s.destLoc_placeholder)
|
||||
$('#anonymeTooltip').attr("title", s.anonyme_tooltip).tooltip("_fixTitle");
|
||||
$('#publicTooltip').attr("title", s.public_tooltip).tooltip("_fixTitle");
|
||||
|
||||
$('#selectDestLang option[value="'+lang+'"]').prop('selected', true); //selecting by default recipient language same as interface
|
||||
//Anthology
|
||||
displayAnthology()
|
||||
$("#anthologyTitle").html(s.anthologie)
|
||||
$("#anthologyDisclaimer").html(s.suppr_message_public)
|
||||
$("#closeAnthologyAbout").html(s.retour_carte)
|
||||
|
||||
//About
|
||||
$("#aboutTitle").html(s.apropos)
|
||||
$("#librairies").html(s.librairies)
|
||||
$("#mapSources").html(s.source_carte)
|
||||
$("#mapBackground").html(s.map_background)
|
||||
$("#clouds").html(s.clouds)
|
||||
$.getJSON("lang/about.json", function(e){
|
||||
if(lang !== 'en' && lang !== 'fr' && lang !== 'de'){
|
||||
$("#aboutText").html(e[0].en)
|
||||
}
|
||||
else{
|
||||
$("#aboutText").html(e[0][lang])
|
||||
}
|
||||
})
|
||||
|
||||
//plane limit tooltip
|
||||
if (nbPlane > 99){
|
||||
$("#planeLimitTooltip").attr("title", s.AvionPoeme_epuise).tooltip("_fixTitle");
|
||||
}
|
||||
else{
|
||||
var remainingPlanes = 100 - nbPlane;
|
||||
s.NB_AvionPoeme_restant = s.NB_AvionPoeme_restant.replace('$NB_avion_poeme',remainingPlanes)
|
||||
$("#planeLimitTooltip").attr("title", s.NB_AvionPoeme_restant).tooltip("_fixTitle");
|
||||
}
|
||||
|
||||
})
|
||||
.always(function(callback) {
|
||||
//console.log( callback );
|
||||
});
|
||||
}
|
||||
|
||||
//hovering lang icon
|
||||
$( "#navbarDropdownLang" ).mouseenter(function() {
|
||||
$("#langIcon").attr("src","src/img/lang-hover.png");
|
||||
});
|
||||
$( "#navbarDropdownLang" ).mouseleave(function() {
|
||||
$("#langIcon").attr("src","src/img/lang.png");
|
||||
});
|
||||
|
||||
|