DTux
/
dtux__avion-poeme
Archived
1
0
Fork 0

Merge branch 'synchro-with-prod' of DTux/avion-poeme into master

This commit is contained in:
DTux 2021-10-22 08:37:08 +00:00 committed by Gogs
commit 849a8f3629
74 changed files with 17935 additions and 735 deletions

7
dist/bootstrap/bootstrap.min.css vendored Normal file

File diff suppressed because one or more lines are too long

7
dist/bootstrap/bootstrap.min.js vendored Normal file

File diff suppressed because one or more lines are too long

584
dist/bootstrap/bootstrap3-typeahead.js vendored Normal file
View 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

File diff suppressed because one or more lines are too long

1
dist/glify-browser.js.map vendored Normal file

File diff suppressed because one or more lines are too long

2
dist/jquery/jquery-3.6.0.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View 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

Binary file not shown.

After

Width:  |  Height:  |  Size: 299 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 420 B

View 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);
}
}

View 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 */

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

148
dist/leaflet-terminator/L.Terminator.js vendored Normal file
View 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
View 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

File diff suppressed because one or more lines are too long

1
dist/leaflet/leaflet.js.map vendored Normal file

File diff suppressed because one or more lines are too long

55
dist/leaflet/touch-fix.js vendored Normal file
View 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

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

9
dist/pixi/pixi.min.js vendored Normal file

File diff suppressed because one or more lines are too long

5
dist/popper/popper.min.js vendored Normal file

File diff suppressed because one or more lines are too long

10576
dist/quill/quill.js vendored Normal file

File diff suppressed because it is too large Load Diff

899
dist/quill/quill.snow.css vendored Normal file
View 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;
}

File diff suppressed because one or more lines are too long

1369
dist/swal/sweetalert2.css vendored Normal file

File diff suppressed because it is too large Load Diff

1
dist/swal/sweetalert2.min.js vendored Normal file

File diff suppressed because one or more lines are too long

96
dist/turf/turf.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -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>&nbsp;
<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 &copy; Esri &mdash; 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">&times;</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>&nbsp;&nbsp;
<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>&nbsp;&nbsp;<i id="publicTooltip" class="fas fa-question-circle" data-toggle="tooltip" data-placement="auto" title="Message publié dans lAnthologie une fois lavion-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>&nbsp;&nbsp;&nbsp;&nbsp;
<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>&nbsp;&nbsp;
<input type="checkbox" class="form-check-input" id="expeKnown">
<label class="form-check-label" for="expeKnown" id="newPlaneModalAnonyme">envoi anonyme</label>&nbsp;&nbsp;<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à larrivée de lavion-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:&nbsp;</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>&nbsp;
<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">&times;</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/newPlane.js"></script>
<script src="src/translation.js"></script>
<script src="src/anthology.js"></script>
</body>
</html>

File diff suppressed because one or more lines are too long

7
lang/about.json Normal file
View 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 dautres que nous vous offrent linstantané,<br>Nous vous offrirons le temps et lattente<br><br>Sils vous offrent une lettre<br>Nous vous offrirons un poème<br><br>Sils vous offrent une certitude<br>Nous vous offrirons les aléas et linconnu<br><br>Sils vous offrent labondance<br>Nous vous offrirons le partage<br><br>Et sils vous offrent un message<br>Nous vous offrirons le voyage<br><br>Librement,<br><br>Léquipe davion-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, quelles soient verbales ou physiques.</li><li>Les messages privés sont supprimés physiquement de notre serveur une fois arrivés, ainsi que lensemble 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\">lorigine des avions-poèmes</a>.</li></ul><br>Nhé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

Binary file not shown.

1
lang/ar Normal file

File diff suppressed because one or more lines are too long

1
lang/bg Normal file

File diff suppressed because one or more lines are too long

1
lang/de Normal file

File diff suppressed because one or more lines are too long

1
lang/en Normal file

File diff suppressed because one or more lines are too long

1
lang/es Normal file

File diff suppressed because one or more lines are too long

1
lang/fr Normal file

File diff suppressed because one or more lines are too long

1
lang/ja Normal file

File diff suppressed because one or more lines are too long

1
lang/lang.json Normal file
View File

@ -0,0 +1 @@
{"fr":"Français","en":"English","de":"Deutsch","bg":"български","zh":"中文","ja":"日本語","es":"español","pt":"português","ar":"اللغة العربية"}

1
lang/pt Normal file

File diff suppressed because one or more lines are too long

1
lang/zh Normal file

File diff suppressed because one or more lines are too long

33
src/about.js Normal file
View 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
View 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> &bull; '+dictionnary.destination+': <b>'+results.destName+'</b> &bull; '+dictionnary.date_arrivee+': <b>'+moment(Number(results.deliveryTime)*1000).format('LL')+'</b> &bull; '+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> &bull; '+dictionnary.destination+': <b>'+results.destName+'</b> &bull; '+dictionnary.date_arrivee+': <b>'+moment(Number(results.deliveryTime)*1000).format('LL')+'</b> &bull; '+dictionnary.temps_de_vol+': <b>'+flightTime(Number(results.startTime),Number(results.deliveryTime))+'</b></small><br><br>'+results.message+'<br><hr><br>'
)
}
}

View File

@ -1,73 +1,264 @@
body {
margin: 0;
padding: 0;
font-family: 'PT Mono', monospace;
/* font-family: 'Special Elite', cursive !important */
}
#map {
position: absolute;
top: 0;
bottom: 0;
width: 100%;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 30px;
line-height: 30px; /* Vertically center the text there */
background-color: #f5f5f5;
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;
transition: all .3s;
position:fixed;
height:100vh;
width:100vw;
background-color: rgba(0,0,0,0);
z-index:9999;
margin-top: 50vh; /* poussé de la moitié de hauteur de viewport */
transform: translateY(-50%) translateX(-50%); /* tiré de la moitié de sa propre hauteur */
margin-left: 50vw; /* poussé de la moitié de hauteur de viewport */
}
/* qill text editor */
#messageTextArea {
min-height: 200px;
border-radius: 0px 0px .25em .25em !important;
border-color: #ced4da !important
}
.ql-toolbar{
border-radius: .25em .25em 0px 0px !important;
border-color: #ced4da !important
}
html,
body {
overflow-x: hidden;
height: 100%;
}
body {
position: relative;
margin: 0;
padding: 0;
font-family: 'PT Mono', monospace;
}
#map {
position: fixed;
top: 0;
bottom: 0;
height:100%;
width: 100%;
}
.footer {
position: absolute;
bottom: 0;
width: 100%;
/* Set the fixed height of the footer here */
height: 30px;
line-height: 30px; /* Vertically center the text there */
background-color: #f5f5f5;
font-size: 12px
}
/* big modal */
.modal-lg {
max-width:1140px !important;
}
/* paper plane animation */
#canvas3d{
display:none;
transition: all .3s;
position:fixed;
height:100vh;
width:100vw;
background-color: rgba(0,0,0,0);
z-index:9999;
margin-top: 50vh; /* poussé de la moitié de hauteur de viewport */
transform: translateY(-50%) translateX(-50%); /* tiré de la moitié de sa propre hauteur */
margin-left: 50vw; /* poussé de la moitié de hauteur de viewport */
}
/* qill text editor */
#messageTextArea {
min-height: 200px;
border-radius: 0px 0px .25em .25em !important;
border-color: #ced4da !important
}
.ql-toolbar{
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;
}
}

View File

@ -1,4 +1,4 @@
var config = {
mapboxKey: 'pk.eyJ1IjoibGVvLWlnYSIsImEiOiJjazY2bGV3MTYxMjV3M25sMmdtNWluM2wzIn0.2THSqD6nz9OhE0Xsjnbw1g',
owmKey: "39d5c3be709ba4f5b6230cdffdedd2ac",
var config = {
mapboxKey: 'pk.eyJ1IjoiYXZpb25wb2VtZSIsImEiOiJja20yY28xaWQyNnRiMnBvNm1kdjF4M3A5In0.gbs_ozL4rwh7KNsLmph-yQ',
owmKey: "39d5c3be709ba4f5b6230cdffdedd2ac",
}

25
src/formValidation.js Normal file
View 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)
}
}

View File

@ -1,67 +1,129 @@
let langGeocoder = "fr"
// 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)
})
},
matcher: function(item){ //needed when spelling not exact
return true
},
afterSelect: function (obj) {
for (var i in expeLocList){
if (expeLocList[i].fullname == obj){
expeLoc = expeLocList[i]
}
}
}
})
//Destinataire
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)
})
},
matcher: function(item){ //needed when spelling not exact
return true
},
afterSelect: function (obj) {
for (var i in destLocList){
if (destLocList[i].fullname == obj){
destLoc = destLocList[i]
}
}
}
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) {
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
},
afterSelect: function (obj) {
for (var i in expeLocList){
if (expeLocList[i].fullname == obj){
expeLoc = expeLocList[i]
validExpeLoc = true
checkFormValid()
}
}
}
})
//Destinataire
var destLocList = []
var destLoc;
$('#destGeocoderPhoton').typeahead({
source: function (query, process) {
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
},
afterSelect: function (obj) {
for (var i in destLocList){
if (destLocList[i].fullname == obj){
destLoc = destLocList[i]
validDestLoc = true
checkFormValid()
}
}
}
})

BIN
src/img/back-2A7FFF.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-66FF00.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-BC5FD3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-C8AB37.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-ECECEC.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-FF5555.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-FF6600.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back-FFE419.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/back.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

BIN
src/img/front.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/img/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

BIN
src/img/lang-hover.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
src/img/lang.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

71
src/img/licence.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 52 KiB

BIN
src/img/plane-2A7FFF.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
src/img/plane-66FF00.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

BIN
src/img/plane-BC5FD3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

BIN
src/img/plane-C8AB37.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 51 KiB

BIN
src/img/plane-ECECEC.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

BIN
src/img/plane-FF5555.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

BIN
src/img/plane-FF6600.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

BIN
src/img/plane-FFE419.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

BIN
src/img/shadow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

View File

@ -1,266 +1,484 @@
mapboxgl.accessToken = config.mapboxKey;
const owmKey = config.owmKey
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
});
//prevent world duplication
map.setRenderWorldCopies(status === 'false')
map.on('load', function () {
//displaying clouds from OpenWeatherMap free API not enough
// 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);
})
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()
//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;
//random color
var randomColor = colors[Math.floor(Math.random() * colors.length)];
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');
});
}
});
});
})
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');
}
//global variable
var nbPlane = 0
loader.add('shadow', 'src/img/shadow.png');
loader.load(function(loader, resources) {
var pixiContainer = new PIXI.Container();
var map = L.map('map',{
zoomControl: false,
minZoom:2,
maxZoom: 16,
maxBounds: [
[-Infinity, -360],
[Infinity, 360]
],
//worldCopyJump: true,
attributionControl: false
})
//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'}));
// Licence Icon
L.Control.Watermark = L.Control.extend({
onAdd: function(map) {
var img = L.DomUtil.create('img');
img.src = 'src/img/licence.svg';
img.style.width = '100px';
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>&nbsp;<i class="fas fa-plane"></i>&nbsp;</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>&nbsp;<i class="fas fa-plane"></i>&nbsp;</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';
}
});
})()

View File

@ -1,111 +1,207 @@
// init text editor in modal
var quill = new Quill('#messageTextArea', {
modules: {
toolbar: [
[{ 'size': ['small', false, 'large'] }],
[{ 'font': [] }],
['bold', 'italic', 'underline','strike'],
[{ 'color': [] }],
]
},
placeholder: '',
theme: 'snow' // or 'bubble',
});
$("#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
//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]
//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]
//storing the endDate in GMT+0 in seconds for the query
var deliverySecondsServer = moment.tz(new Date(), "Europe/London").add(time, 'hours').unix()
var publicMessage = $("#publicMessage").prop("checked")
var message = $("#messageTextArea").val()
var data = {
'message':message,
'public':publicMessage,
'expeMail':$("#expeMail").val(),
'destMail':$("#destMail").val(),
'expeName':expeLoc.name,
'destName':destLoc.name,
'expeCoordo':expeLoc.center,
'destCoordo':destLoc.center,
'sentDate': sentDate,
'deliveryDate':deliveryDate,
'deliverySecondsServer':deliverySecondsServer,
}
//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);
})
});
// init text editor in modal
var quill = new Quill('#messageTextArea', {
modules: {
toolbar: [
[{ 'size': ['small', false, 'large'] }],
[{ 'font': [] }],
['bold', 'italic', 'underline','strike'],
[{ 'color': [] }],
]
},
placeholder: '',
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 modal
$("#newPlaneModal").modal('hide')
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://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://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/Berlin").add(time, 'hours').unix()
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':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(),
'destLat':destLoc.center[1],
'destLon':destLoc.center[0],
'destName':destLoc.name,
'public':publicMessage,
'color':randomColor,
'deliveryTime':deliveryDate,
'deliveryTZ':destTimezone,
'deliveryTimeServer':deliverySecondsServer,
'deliveryMethod':$("#selectTime").val()
}
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
View 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");
});