- New map deeplink URLs, closed #593

- updated SQL Schema library `2.2.1` -> `2.2.2`
- updated _Bootstrap Confirmation_ library `1.0.5` -> `1.0.7`
- fixed a bug with "cookie accept" hint on /login page
This commit is contained in:
Mark Friedrich
2018-03-19 23:00:45 +01:00
parent 8006b9c303
commit 9b6108f9f6
17 changed files with 847 additions and 512 deletions

View File

@@ -13,96 +13,96 @@
* | | < | <| -__|-- __|
* |__|__|__||__|__|_____|_____|
*
* Copyright (c) 2016 by ikkez
* Copyright (c) 2012-2018 by ikkez
* Christian Knuth <ikkez0n3@gmail.com>
* https://github.com/ikkez/F3-Sugar/
*
* @package DB
* @version 2.2.1
* @date 25.04.2017
* @version 2.2.2
* @date 06.03.2018
**/
namespace DB\SQL;
use DB\SQL;
class Schema {
class Schema extends DB_Utils {
use DB_Utils;
public
$dataTypes = array(
'BOOLEAN' => array('mysql' => 'tinyint(1)',
'sqlite2?|pgsql' => 'BOOLEAN',
'mssql|sybase|dblib|odbc|sqlsrv' => 'bit',
'ibm' => 'numeric(1,0)',
'sqlite2?|pgsql' => 'BOOLEAN',
'mssql|sybase|dblib|odbc|sqlsrv' => 'bit',
'ibm' => 'numeric(1,0)',
),
'INT1' => array('mysql' => 'tinyint(4)',
'sqlite2?' => 'integer(4)',
'mssql|sybase|dblib|odbc|sqlsrv' => 'tinyint',
'pgsql|ibm' => 'smallint',
'sqlite2?' => 'integer(4)',
'mssql|sybase|dblib|odbc|sqlsrv' => 'tinyint',
'pgsql|ibm' => 'smallint',
),
'INT2' => array('mysql' => 'smallint(6)',
'sqlite2?' => 'integer(6)',
'pgsql|ibm|mssql|sybase|dblib|odbc|sqlsrv' => 'smallint',
'sqlite2?' => 'integer(6)',
'pgsql|ibm|mssql|sybase|dblib|odbc|sqlsrv' => 'smallint',
),
'INT4' => array('sqlite2?' => 'integer(11)',
'pgsql|imb' => 'integer',
'mysql' => 'int(11)',
'mssql|dblib|sybase|odbc|sqlsrv' => 'int',
'pgsql|imb' => 'integer',
'mysql' => 'int(11)',
'mssql|dblib|sybase|odbc|sqlsrv' => 'int',
),
'INT8' => array('sqlite2?' => 'integer(20)',
'pgsql|mssql|sybase|dblib|odbc|sqlsrv|imb' => 'bigint',
'mysql' => 'bigint(20)',
'pgsql|mssql|sybase|dblib|odbc|sqlsrv|imb' => 'bigint',
'mysql' => 'bigint(20)',
),
'FLOAT' => array('mysql|sqlite2?' => 'FLOAT',
'pgsql' => 'double precision',
'mssql|sybase|dblib|odbc|sqlsrv' => 'float',
'imb' => 'decfloat'
'pgsql' => 'double precision',
'mssql|sybase|dblib|odbc|sqlsrv' => 'float',
'imb' => 'decfloat'
),
'DOUBLE' => array('mysql|ibm' => 'decimal(18,6)',
'sqlite2?' => 'decimal(15,6)', // max 15-digit on sqlite
'pgsql' => 'numeric(18,6)',
'mssql|dblib|sybase|odbc|sqlsrv' => 'decimal(18,6)',
'sqlite2?' => 'decimal(15,6)', // max 15-digit on sqlite
'pgsql' => 'numeric(18,6)',
'mssql|dblib|sybase|odbc|sqlsrv' => 'decimal(18,6)',
),
'VARCHAR128' => array('mysql|sqlite2?|ibm|mssql|sybase|dblib|odbc|sqlsrv' => 'varchar(128)',
'pgsql' => 'character varying(128)',
'pgsql' => 'character varying(128)',
),
'VARCHAR256' => array('mysql|sqlite2?|ibm|mssql|sybase|dblib|odbc|sqlsrv' => 'varchar(255)',
'pgsql' => 'character varying(255)',
'pgsql' => 'character varying(255)',
),
'VARCHAR512' => array('mysql|sqlite2?|ibm|mssql|sybase|dblib|odbc|sqlsrv' => 'varchar(512)',
'pgsql' => 'character varying(512)',
'pgsql' => 'character varying(512)',
),
'TEXT' => array('mysql|sqlite2?|pgsql|mssql' => 'text',
'sybase|dblib|odbc|sqlsrv' => 'nvarchar(max)',
'ibm' => 'BLOB SUB_TYPE TEXT',
'sybase|dblib|odbc|sqlsrv' => 'nvarchar(max)',
'ibm' => 'BLOB SUB_TYPE TEXT',
),
'LONGTEXT' => array('mysql' => 'LONGTEXT',
'sqlite2?|pgsql|mssql' => 'text',
'sybase|dblib|odbc|sqlsrv' => 'nvarchar(max)',
'ibm' => 'CLOB(2000000000)',
'sqlite2?|pgsql|mssql' => 'text',
'sybase|dblib|odbc|sqlsrv' => 'nvarchar(max)',
'ibm' => 'CLOB(2000000000)',
),
'DATE' => array('mysql|sqlite2?|pgsql|mssql|sybase|dblib|odbc|sqlsrv|ibm' => 'date',
),
'DATETIME' => array('pgsql' => 'timestamp without time zone',
'mysql|sqlite2?|mssql|sybase|dblib|odbc|sqlsrv' => 'datetime',
'ibm' => 'timestamp',
'mysql|sqlite2?|mssql|sybase|dblib|odbc|sqlsrv' => 'datetime',
'ibm' => 'timestamp',
),
'TIMESTAMP' => array('mysql|ibm' => 'timestamp',
'pgsql|odbc' => 'timestamp without time zone',
'sqlite2?|mssql|sybase|dblib|sqlsrv'=>'DATETIME',
'pgsql|odbc' => 'timestamp without time zone',
'sqlite2?|mssql|sybase|dblib|sqlsrv'=>'DATETIME',
),
'BLOB' => array('mysql|odbc|sqlite2?|ibm' => 'blob',
'pgsql' => 'bytea',
'mssql|sybase|dblib' => 'image',
'sqlsrv' => 'varbinary(max)',
'pgsql' => 'bytea',
'mssql|sybase|dblib' => 'image',
'sqlsrv' => 'varbinary(max)',
),
),
$defaultTypes = array(
'CUR_STAMP' => array('mysql' => 'CURRENT_TIMESTAMP',
'mssql|sybase|dblib|odbc|sqlsrv' => 'getdate()',
'pgsql' => 'LOCALTIMESTAMP(0)',
'sqlite2?' => "(datetime('now','localtime'))",
'mssql|sybase|dblib|odbc|sqlsrv' => 'getdate()',
'pgsql' => 'LOCALTIMESTAMP(0)',
'sqlite2?' => "(datetime('now','localtime'))",
),
);
@@ -112,9 +112,6 @@ class Schema extends DB_Utils {
public static
$strict = FALSE;
/** @var \Base */
protected $fw;
const
// DataTypes and Aliases
DT_BOOL = 'BOOLEAN',
@@ -147,8 +144,7 @@ class Schema extends DB_Utils {
public function __construct(\DB\SQL $db)
{
$this->fw = \Base::instance();
parent::__construct($db);
$this->db = $db;
}
/**
@@ -304,7 +300,9 @@ class Schema extends DB_Utils {
}
}
abstract class TableBuilder extends DB_Utils {
abstract class TableBuilder {
use DB_Utils;
protected $columns, $pkeys, $queries, $increments, $rebuild_cmd, $suppress;
public $name;
@@ -318,7 +316,6 @@ abstract class TableBuilder extends DB_Utils {
/**
* @param string $name
* @param Schema $schema
* @return \DB\SQL\TableBuilder
*/
public function __construct($name, Schema $schema)
{
@@ -328,7 +325,7 @@ abstract class TableBuilder extends DB_Utils {
$this->queries = array();
$this->pkeys = array('id');
$this->increments = 'id';
parent::__construct($schema->db);
$this->db = $schema->db;
}
/**
@@ -549,6 +546,8 @@ class TableModifier extends TableBuilder {
/**
* generate SQL queries for altering the table and execute it if $exec is true,
* otherwise return the generated query string
* @param bool $exec
* @return array|FALSE
*/
public function build($exec = TRUE)
{
@@ -763,9 +762,9 @@ class TableModifier extends TableBuilder {
else
foreach ($schema as $name => &$cols) {
$default = ($cols['default'] === '') ? null : $cols['default'];
if (!is_null($default) && (
(is_int(strpos($curdef=$this->findQuery($this->schema->defaultTypes['CUR_STAMP']),
$default)) || is_int(strpos($default,$curdef)))
if (!is_null($default) && ((is_int(strpos($curdef=strtolower(
$this->findQuery($this->schema->defaultTypes['CUR_STAMP'])),
strtolower($default))) || is_int(strpos(strtolower($default),$curdef)))
|| $default == "('now'::text)::timestamp(0) without time zone"))
{
$default = 'CUR_STAMP';
@@ -874,7 +873,6 @@ class TableModifier extends TableBuilder {
* @param string $name
* @param string|Column $datatype
* @param bool $force
* @return bool
*/
public function updateColumn($name, $datatype, $force = false)
{
@@ -1031,7 +1029,9 @@ class TableModifier extends TableBuilder {
* Class Column
* @package DB\SQL
*/
class Column extends DB_Utils {
class Column {
use DB_Utils;
public $name, $type, $nullable, $default, $after, $index, $unique, $passThrough, $pkey;
protected $table, $schema, $type_val;
@@ -1056,7 +1056,7 @@ class Column extends DB_Utils {
$this->table = $table;
$this->schema = $table->schema;
parent::__construct($this->schema->db);
$this->db = $this->schema->db;
}
/**
@@ -1281,22 +1281,16 @@ class Column extends DB_Utils {
constant('\PDO::PARAM_'.strtoupper($parts[0])) : \PDO::PARAM_STR;
return ($this->default === NULL ? 'NULL' :
$this->db->quote(htmlspecialchars($this->default, ENT_QUOTES,
$this->f3->get('ENCODING')), $pdo_type));
\Base::instance()->get('ENCODING')), $pdo_type));
}
}
}
class DB_Utils {
trait DB_Utils {
/** @var \DB\SQL */
protected $db;
/** @var \BASE */
protected $f3;
const
TEXT_ENGINE_NOT_SUPPORTED = 'DB Engine `%s` is not supported for this action.';
public $db;
/**
* parse command array and return backend specific query
@@ -1308,11 +1302,6 @@ class DB_Utils {
foreach ($cmd as $backend => $val)
if (preg_match('/'.$backend.'/', $this->db->driver()))
return $val;
trigger_error(sprintf(self::TEXT_ENGINE_NOT_SUPPORTED, $this->db->driver()),E_USER_ERROR);
}
public function __construct(SQL $db) {
$this->db = $db;
$this->f3 = \Base::instance();
trigger_error(sprintf('DB Engine `%s` is not supported for this action.', $this->db->driver()),E_USER_ERROR);
}
}

View File

@@ -9,7 +9,7 @@ GET @login: / [sync] = Controller\AppContro
; CCP SSO redirect
GET @sso: /sso/@action [sync] = Controller\Ccp\Sso->@action
; map page
GET @map: /map [sync] = Controller\MapController->init
GET @map: /map* [sync] = Controller\MapController->init
; admin panel
GET @admin: /admin* [sync] = Controller\Admin->dispatch
@@ -17,3 +17,4 @@ GET @admin: /admin* [sync] = Controller\Admin->di
GET|POST /api/@controller/@action [ajax] = Controller\Api\@controller->@action, 0, 512
GET|POST /api/@controller/@action/@arg1 [ajax] = Controller\Api\@controller->@action, 0, 512
GET|POST /api/@controller/@action/@arg1/@arg2 [ajax] = Controller\Api\@controller->@action, 0, 512

View File

@@ -8,51 +8,51 @@ define(['jquery'], ($) => {
let Config = {
path: {
img: 'public/img/', // path for images
img: '/public/img/', // path for images
// user API
getCaptcha: 'api/user/getCaptcha', // ajax URL - get captcha image
getServerStatus: 'api/user/getEveServerStatus', // ajax URL - get EVE-Online server status
getCookieCharacterData: 'api/user/getCookieCharacter', // ajax URL - get character data from cookie
logIn: 'api/user/logIn', // ajax URL - login
logout: 'api/user/logout', // ajax URL - logout
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
openIngameWindow: 'api/user/openIngameWindow', // ajax URL - open inGame Window
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
getCaptcha: '/api/user/getCaptcha', // ajax URL - get captcha image
getServerStatus: '/api/user/getEveServerStatus', // ajax URL - get EVE-Online server status
getCookieCharacterData: '/api/user/getCookieCharacter', // ajax URL - get character data from cookie
logIn: '/api/user/logIn', // ajax URL - login
logout: '/api/user/logout', // ajax URL - logout
deleteLog: '/api/user/deleteLog', // ajax URL - delete character log
openIngameWindow: '/api/user/openIngameWindow', // ajax URL - open inGame Window
saveUserConfig: '/api/user/saveAccount', // ajax URL - saves/update user account
deleteAccount: '/api/user/deleteAccount', // ajax URL - delete Account data
// access API
searchAccess: 'api/access/search', // ajax URL - search user/corporation/ally by name
searchAccess: '/api/access/search', // ajax URL - search user/corporation/ally by name
// main config/map ping API
initMap: 'api/map/init', // ajax URL - get static data
getAccessData: 'api/map/getAccessData', // ajax URL - get map access tokens (WebSocket)
updateMapData: 'api/map/updateData', // ajax URL - main map update trigger
updateUserData: 'api/map/updateUserData', // ajax URL - main map user data trigger
initMap: '/api/map/init', // ajax URL - get static data
getAccessData: '/api/map/getAccessData', // ajax URL - get map access tokens (WebSocket)
updateMapData: '/api/map/updateData', // ajax URL - main map update trigger
updateUserData: '/api/map/updateUserData', // ajax URL - main map user data trigger
// map API
saveMap: 'api/map/save', // ajax URL - save/update map
deleteMap: 'api/map/delete', // ajax URL - delete map
importMap: 'api/map/import', // ajax URL - import map
getMapConnectionData: 'api/map/getConnectionData', // ajax URL - get connection data
getMapLogData: 'api/map/getLogData', // ajax URL - get logs data
saveMap: '/api/map/save', // ajax URL - save/update map
deleteMap: '/api/map/delete', // ajax URL - delete map
importMap: '/api/map/import', // ajax URL - import map
getMapConnectionData: '/api/map/getConnectionData', // ajax URL - get connection data
getMapLogData: '/api/map/getLogData', // ajax URL - get logs data
// system API
searchSystem: 'api/system/search', // ajax URL - search system by name
saveSystem: 'api/system/save', // ajax URL - saves system to map
deleteSystem: 'api/system/delete', // ajax URL - delete system from map
getSystemGraphData: 'api/system/graphData', // ajax URL - get all system graph data
getConstellationData: 'api/system/constellationData', // ajax URL - get system constellation data
setDestination: 'api/system/setDestination', // ajax URL - set destination
pokeRally: 'api/system/pokeRally', // ajax URL - send rally point pokes
searchSystem: '/api/system/search', // ajax URL - search system by name
saveSystem: '/api/system/save', // ajax URL - saves system to map
deleteSystem: '/api/system/delete', // ajax URL - delete system from map
getSystemGraphData: '/api/system/graphData', // ajax URL - get all system graph data
getConstellationData: '/api/system/constellationData', // ajax URL - get system constellation data
setDestination: '/api/system/setDestination', // ajax URL - set destination
pokeRally: '/api/system/pokeRally', // ajax URL - send rally point pokes
// connection API
saveConnection: 'api/connection/save', // ajax URL - save new connection to map
deleteConnection: 'api/connection/delete', // ajax URL - delete connection from map
saveConnection: '/api/connection/save', // ajax URL - save new connection to map
deleteConnection: '/api/connection/delete', // ajax URL - delete connection from map
// signature API
getSignatures: 'api/signature/getAll', // ajax URL - get all signature data for system
saveSignatureData: 'api/signature/save', // ajax URL - save signature data for system
deleteSignatureData: 'api/signature/delete', // ajax URL - delete signature data for system
getSignatures: '/api/signature/getAll', // ajax URL - get all signature data for system
saveSignatureData: '/api/signature/save', // ajax URL - save signature data for system
deleteSignatureData: '/api/signature/delete', // ajax URL - delete signature data for system
// route API
searchRoute: 'api/route/search', // ajax URL - search system routes
searchRoute: '/api/route/search', // ajax URL - search system routes
// stats API
getStatisticsData: 'api/statistic/getData', // ajax URL - get statistics data (activity log)
getStatisticsData: '/api/statistic/getData', // ajax URL - get statistics data (activity log)
// GitHub API
gitHubReleases: 'api/github/releases' // ajax URL - get release info from GitHub
gitHubReleases: '/api/github/releases' // ajax URL - get release info from GitHub
},
breakpoints: [
{ name: 'desktop', width: Infinity },

View File

@@ -18,7 +18,7 @@ define([
'dialog/manual',
'dialog/changelog',
'dialog/credit'
], function($, Init, Util, Render, Gallery, bootbox) {
], ($, Init, Util, Render, Gallery, bootbox) => {
'use strict';
@@ -79,7 +79,7 @@ define([
/**
* set link observer for "version info" dialog
*/
let setVersionLinkObserver = function(){
let setVersionLinkObserver = () => {
$('.' + config.navigationVersionLinkClass).off('click').on('click', function(e){
$.fn.changelogsDialog();
});
@@ -94,13 +94,24 @@ define([
adminPanel.css({bottom: ((direction === 'up') ? '+' : '-') + '=35px'});
};
let setAcceptCookie = () => {
Util.setCookie('cookie', 1, config.defaultAcceptCookieExpire, 'd');
};
/**
* set page observer
*/
let setPageObserver = function(){
let setPageObserver = () => {
let ssoButtonElement = $('.' + config.ssoButtonClass);
let cookieHintElement = $('#' + config.cookieHintId);
// cookie hint --------------------------------------------------------
cookieHintElement.find('.btn-success').on('click', function(){
setAcceptCookie();
// confirmation no longer needed on SSO login button
ssoButtonElement.confirmation('destroy');
});
cookieHintElement.on('show.bs.collapse', function () {
// move admin panel upwards (prevents overlapping with cookie notice)
moveAdminPanel('up');
@@ -127,7 +138,7 @@ define([
btnCancelIcon: 'fas fa-fw fa-check',
onCancel: function(e, target){
// "Accept cookies"
Util.setCookie('cookie', 1, config.defaultAcceptCookieExpire, 'd');
setAcceptCookie();
// set "default" href
let href = $(target).data('bs.confirmation').getHref();
@@ -141,13 +152,9 @@ define([
}
};
$('.' + config.ssoButtonClass).confirmation(confirmationSettings);
ssoButtonElement.confirmation(confirmationSettings);
}
cookieHintElement.find('.btn-success').on('click', function(){
Util.setCookie('cookie', 1, config.defaultAcceptCookieExpire, 'd');
});
// manual -------------------------------------------------------------
$('.' + config.navigationLinkManualClass).on('click', function(e){
e.preventDefault();
@@ -179,7 +186,7 @@ define([
/**
* init image carousel
*/
let initCarousel = function(){
let initCarousel = () => {
// check if carousel exists
if($('#' + config.galleryCarouselId).length === 0){
@@ -313,7 +320,7 @@ define([
* get all thumbnail elements
* @returns {*|jQuery|HTMLElement}
*/
let getThumbnailElements = function(){
let getThumbnailElements = () => {
return $('a[data-gallery="#' + config.galleryId + '"]').not('.disabled');
};
@@ -321,14 +328,14 @@ define([
* init gallery for thumbnail elements
* @param newElements
*/
let initGallery = function(newElements){
let initGallery = (newElements) => {
if( newElements.length > 0){
// We have to add ALL thumbnail elements to the gallery!
// -> even those wthat are invisible (not lazyLoaded) now!
// -> This is required for "swipe" through all images
let allThumbLinks = getThumbnailElements();
requirejs(['blueImpGalleryBootstrap'], function() {
requirejs(['blueImpGalleryBootstrap'], () => {
$(newElements).each(function() {
let borderless = false;
@@ -360,7 +367,7 @@ define([
/**
* init "YouTube" video preview
*/
let initYoutube = function(){
let initYoutube = () => {
$('.youtube').each(function() {
// Based on the YouTube ID, we can easily find the thumbnail image
@@ -395,11 +402,11 @@ define([
/**
* init scrollSpy for navigation bar
*/
let initScrollSpy = function(){
let initScrollSpy = () => {
// init scrollspy
// show elements that are currently in the viewport
let showVisibleElements = function(){
let showVisibleElements = () => {
// find all elements that should be animated
let visibleElements = $('.' + config.animateElementClass).isInViewport();
@@ -421,7 +428,7 @@ define([
});
};
$( window ).scroll(function() {
$( window ).scroll(() => {
// check for new visible elements
showVisibleElements();
});
@@ -446,7 +453,7 @@ define([
* get current EVE-Online server status
* -> show "server panel"
*/
let initServerStatus = function(){
let initServerStatus = () => {
$.ajax({
type: 'POST',
url: Init.path.getServerStatus,
@@ -485,16 +492,16 @@ define([
* show "notification panel" to user
* -> checks if panel not already shown
*/
let initNotificationPanel = function(){
let initNotificationPanel = () => {
let storageKey = 'notification_panel';
let currentVersion = Util.getVersion();
let showNotificationPanel = function(){
let showNotificationPanel = () => {
let data = {
version: Util.getVersion()
};
requirejs(['text!templates/ui/notice.html', 'mustache'], function(template, Mustache) {
requirejs(['text!templates/ui/notice.html', 'mustache'], (template, Mustache) => {
let content = Mustache.render(template, data);
let notificationPanel = $('#' + config.notificationPanelId);
@@ -704,7 +711,7 @@ define([
* @param status
* @param error
*/
let handleAjaxErrorResponse = function(jqXHR, status, error){
let handleAjaxErrorResponse = (jqXHR, status, error) => {
let type = status;
let title = 'Status ' + jqXHR.status + ': ' + error;
@@ -734,7 +741,7 @@ define([
/**
* main init "landing" page
*/
$(function(){
$(() => {
// clear sessionStorage
Util.clearSessionStorage();
@@ -816,9 +823,9 @@ define([
initYoutube();
// draw header logo
$('#' + config.logoContainerId).drawLogo(function(){
$('#' + config.logoContainerId).drawLogo(() => {
// init header animation
$('#' + config.headerContainerId).initHeader(function(){
$('#' + config.headerContainerId).initHeader(() => {
});
}, false);

View File

@@ -1039,6 +1039,18 @@ define([
return hasAccess;
};
/**
* get a unique map url for deeplinking
* @param mapId
* @returns {string}
*/
let getMapDeeplinkUrl = (mapId) => {
let url = location.protocol + '//' + location.host + '/map';
url += mapId ? '/' + encodeURIComponent(window.btoa(mapId)) : '';
return url;
};
return {
config: config,
mapOptions: mapOptions,
@@ -1073,6 +1085,7 @@ define([
storeLocalData: storeLocalData,
deleteLocalData: deleteLocalData,
getSystemId: getSystemId,
checkRight: checkRight
checkRight: checkRight,
getMapDeeplinkUrl: getMapDeeplinkUrl
};
});

View File

@@ -628,6 +628,12 @@ define([
let mapElement = $(mapConfig.map.getContainer());
let mapWrapperElement = mapElement.closest('.mCustomScrollbar');
mapWrapperElement.mCustomScrollbar('update');
// change url to unique map URL
if (history.pushState) {
let mapUrl = MapUtil.getMapDeeplinkUrl(mapConfig.config.id);
history.pushState({}, '', mapUrl);
}
});
}
});
@@ -937,6 +943,15 @@ define([
return Promise.all(promiseDeleteTab);
};
/**
* get last URL segment e.g. https://pathfinder/map/test -> test
* @returns {string | undefined}
*/
let getLastUrlSegment = () => {
let parts = window.location.pathname.split('/');
return parts.pop() || parts.pop();
};
/**
* set "default" map tab
* -> default mapId might be available in local storage
@@ -946,6 +961,10 @@ define([
*/
let showDefaultTab = (tabMapElement, currentUserData) => {
let getActiveTabLinkElement = (mapId) => {
return tabMapElement.find('.' + config.mapTabClass + '[data-mapid="' + mapId + '"] > a');
};
/**
* show default tab promise
* @param resolve
@@ -956,13 +975,31 @@ define([
promiseStore.then((data) => {
let activeTabLinkElement = false;
if(data && data.defaultMapId){
// make specific map tab active
activeTabLinkElement = tabMapElement.find('.' + config.mapTabClass + '[data-mapid="' + data.defaultMapId + '"] > a');
// check for existing mapId URL identifier ------------------------------------------------------------
let lastURLSegment = getLastUrlSegment();
let defaultMapId = 0;
try{
defaultMapId = parseInt(atob(decodeURIComponent(lastURLSegment)));
}catch(e){
// defaultMapID could not be extracted from URL -> ignore
}
if(defaultMapId){
activeTabLinkElement = getActiveTabLinkElement(defaultMapId);
}
// ... else check for existing cached default mapId ---------------------------------------------------
if(
(!activeTabLinkElement || !activeTabLinkElement.length) &&
data && data.defaultMapId
){
// make specific map tab active
activeTabLinkElement = getActiveTabLinkElement(data.defaultMapId);
}
// ... else make first map tab active (default) -------------------------------------------------------
if(!activeTabLinkElement || !activeTabLinkElement.length){
// make first map tab active (default)
activeTabLinkElement = tabMapElement.find('.' + config.mapTabClass + ':not(.pull-right):first > a');
}

View File

@@ -42,6 +42,9 @@ define([
tableCellEllipsisClass: 'pf-table-cell-ellipses-auto', // class for table "ellipsis" cells
tableCellActionIconClass: 'pf-table-action-icon-cell', // class for table "action" icon (icon is part of cell content)
textActionIconClass: 'pf-module-icon-button', // class for text action
textActionIconCopyClass: 'pf-module-icon-button-copy', // class for text action "copy"
loadingOptions: { // config for loading overlay
icon: {
size: 'fa-2x'
@@ -79,6 +82,99 @@ define([
return icon.length ? '<i class="fas fa-fw ' + icon + ' ' + config.tableCellActionIconClass + '" title="' + type + '" data-toggle="tooltip"></i>' : '';
};
/**
* write clipboard text
* @param text
* @returns {Promise<any>}
*/
let copyToClipboard = (text) => {
let copyToClipboardExecutor = (resolve, reject) => {
let payload = {
action: 'copyToClipboard',
data: false
};
if (navigator.clipboard) {
// get current permission status
navigator.permissions.query({
name: 'clipboard-write'
}).then(permissionStatus => {
// will be 'granted', 'denied' or 'prompt'
if(
permissionStatus.state === 'granted' ||
permissionStatus.state === 'prompt'
){
navigator.clipboard.writeText(text)
.then(() => {
payload.data = true;
resolve(payload); })
.catch(err => {
let errorMsg = 'Failed to write clipboard content';
console.error(errorMsg, err);
Util.showNotify({title: 'Clipboard API', text: errorMsg, type: 'error'});
resolve(payload);
});
}else{
Util.showNotify({title: 'Clipboard API', text: 'You denied write access', type: 'warning'});
resolve(payload);
}
});
} else {
console.warn('Clipboard API not supported by your browser');
resolve(payload);
}
};
return new Promise(copyToClipboardExecutor);
};
/**
* read clipboard text
* @returns {Promise<any>}
*/
let readFromClipboard = () => {
let readFromClipboardExecutor = (resolve, reject) => {
let payload = {
action: 'readFromClipboard',
data: false
};
if (navigator.clipboard) {
// get current permission status
navigator.permissions.query({
name: 'clipboard-read'
}).then(permissionStatus => {
// will be 'granted', 'denied' or 'prompt'
if(
permissionStatus.state === 'granted' ||
permissionStatus.state === 'prompt'
){
navigator.clipboard.readText()
.then(text => {
payload.data = text;
resolve(payload); })
.catch(err => {
let errorMsg = 'Failed to read clipboard content';
console.error(errorMsg, err);
Util.showNotify({title: 'Clipboard API', text: errorMsg, type: 'error'});
resolve(payload);
});
}else{
Util.showNotify({title: 'Clipboard API', text: 'You denied read access', type: 'warning'});
resolve(payload);
}
});
} else {
console.warn('Clipboard API not supported by your browser');
resolve(payload);
}
};
return new Promise(readFromClipboardExecutor);
};
/**
* loads the map info data into an element
* @param mapData
@@ -115,58 +211,82 @@ define([
class: 'dl-horizontal',
css: {'float': 'left'}
}).append(
$('<dt>').text( 'Icon' )
$('<dt>').text('Icon')
).append(
$('<dd>').append(
$('<i>', {
class: ['fas', 'fa-fw', mapData.config.icon].join(' ')
})
)
).append(
$('<dt>').text('Name')
).append(
$('<dd>').text(mapData.config.name)
).append(
$('<dt>').text('Type')
).append(
$('<dd>', {
class: mapType.class
}).text(mapType.name)
).append(
$('<dt>').text('Link')
).append(
$('<dd>', {
class: [config.textActionIconClass, config.textActionIconCopyClass].join(' ')
}).append(
$('<span>', {
title: 'copy to clipboard',
}).text(MapUtil.getMapDeeplinkUrl(mapData.config.id) + ' ')
).append(
$('<dd>').append(
$('<i>', {
class: ['fas', 'fa-fw', mapData.config.icon].join(' ')
})
)
).append(
$('<dt>').text( 'Name' )
).append(
$('<dd>').text( mapData.config.name )
).append(
$('<dt>').text( 'Type' )
).append(
$('<dd>', {
class: mapType.class
}).text( mapType.name )
);
$('<i>', {
class: ['fas', 'fa-fw', 'fa-copy'].join(' ')
})
)
);
mapElement.append(dlElementLeft);
let dlElementRight = $('<dl>', {
class: 'dl-horizontal',
css: {'float': 'right'}
}).append(
$('<dt>').text( 'Systems' )
).append(
$('<dd>', {
class: ['txt-color', maxSystemsClass].join(' ')
}).text( countSystems + ' / ' + mapType.defaultConfig.max_systems )
).append(
$('<dt>').text( 'Connections' )
).append(
$('<dd>').text( countConnections )
).append(
$('<dt>').text( 'Lifetime' )
).append(
$('<dd>', {
class: config.mapInfoLifetimeCounterClass,
text: mapData.config.created
})
).append(
$('<dt>').text( 'Created' )
).append(
$('<dd>').text(Util.getObjVal(mapDataOrigin, 'config.created.character.name'))
);
}).append(
$('<dt>').text('Systems')
).append(
$('<dd>', {
class: ['txt-color', maxSystemsClass].join(' ')
}).text(countSystems + ' / ' + mapType.defaultConfig.max_systems)
).append(
$('<dt>').text('Connections')
).append(
$('<dd>').text(countConnections)
).append(
$('<dt>').text('Lifetime')
).append(
$('<dd>', {
class: config.mapInfoLifetimeCounterClass,
text: mapData.config.created
})
).append(
$('<dt>').text('Created')
).append(
$('<dd>').text(Util.getObjVal(mapDataOrigin, 'config.created.character.name'))
);
mapElement.append(dlElementRight);
// init map lifetime counter
$('.' + config.mapInfoLifetimeCounterClass).initTimestampCounter();
mapElement.find('.' + config.textActionIconCopyClass).on('click', function(){
let mapUrl = $(this).find('span').text().trim();
copyToClipboard(mapUrl).then(payload => {
if(payload.data){
Util.showNotify({title: 'Copied to clipbaord', text: mapUrl, type: 'success'});
}
});
});
mapElement.initTooltips();
mapElement.hideLoadingAnimation();
};

View File

@@ -1,5 +1,5 @@
/*!
* Bootstrap Confirmation v1.0.5
* Bootstrap Confirmation v1.0.7
* https://github.com/tavicu/bs-confirmation
*/
+function ($) {
@@ -15,62 +15,47 @@
this.init('confirmation', element, options);
$(element).on('show.bs.confirmation', function(e) {
that.options.onShow(e, this);
$(this).addClass('open');
var options = that.options;
var all = options.all_selector;
if(options.singleton)
{
$(all).not(that.$element).each(function()
{
if( $(this).hasClass('open') )
{
$(this).confirmation('hide');
}
});
}
});
$(element).on('hide.bs.confirmation', function(e) {
that.options.onHide(e, this);
$(this).removeClass('open');
});
$(element).on('shown.bs.confirmation', function(e) {
var options = that.options;
var all = options.all_selector;
if(that.isPopout()) {
if(!event_body) {
event_body = $('body').on('click', function (e) {
if(that.$element.is(e.target)) return;
if(that.$element.has(e.target).length) return;
if($('.popover').has(e.target).length) return;
that.hide();
that.inState.click = false;
$('body').unbind(e);
event_body = false;
return;
});
}
}
});
if(options.selector) {
if (options.selector) {
$(element).on('click.bs.confirmation', options.selector, function(e) {
e.preventDefault();
});
} else {
$(element).on('click.bs.confirmation', function(e) {
$(element).on('show.bs.confirmation', function(event) {
that.runCallback(that.options.onShow, event, that.$element);
that.$element.addClass('open');
if (that.options.singleton) {
$(that.options.all_selector).not(that.$element).each(function() {
if ($(this).hasClass('open')) {
$(this).confirmation('hide');
}
});
}
}).on('hide.bs.confirmation', function(event) {
that.runCallback(that.options.onHide, event, that.$element);
that.$element.removeClass('open');
}).on('shown.bs.confirmation', function(e) {
if (!that.isPopout() && !event_body) {
return;
}
event_body = $('body').on('click', function (e) {
if (that.$element.is(e.target)) return;
if (that.$element.has(e.target).length) return;
if ($('.popover').has(e.target).length) return;
that.hide();
that.inState.click = false;
$('body').unbind(e);
event_body = false;
return;
});
}).on('click.bs.confirmation', function(e) {
e.preventDefault();
});
}
@@ -78,30 +63,30 @@
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
Confirmation.VERSION = '1.0.5'
Confirmation.VERSION = '1.0.7'
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
placement : 'right',
title : 'Are you sure?',
btnOkClass : 'btn btn-sm btn-danger',
btnOkLabel : 'Delete',
btnOkIcon : 'glyphicon glyphicon-ok',
btnCancelClass : 'btn btn-sm btn-default',
btnCancelLabel : 'Cancel',
btnCancelIcon : 'glyphicon glyphicon-remove',
href : '#',
target : '_self',
singleton : true,
popout : true,
onShow : function(event, element){},
onHide : function(event, element){},
onConfirm : function(event, element){},
onCancel : function(event, element){},
template : '<div class="popover"><div class="arrow"></div>'
placement : 'right',
title : 'Are you sure?',
btnOkClass : 'btn btn-sm btn-danger',
btnOkLabel : 'Delete',
btnOkIcon : 'glyphicon glyphicon-ok',
btnCancelClass : 'btn btn-sm btn-default',
btnCancelLabel : 'Cancel',
btnCancelIcon : 'glyphicon glyphicon-remove',
href : '#',
target : '_self',
singleton : true,
popout : true,
onShow : function(event, element) {},
onHide : function(event, element) {},
onConfirm : function(event, element) {},
onCancel : function(event, element) {},
template : '<div class="popover"><div class="arrow"></div>'
+ '<h3 class="popover-title"></h3>'
+ '<div class="popover-content">'
+ '<a data-apply="confirmation">Yes</a>'
+ '<a data-dismiss="confirmation">No</a>'
+ ' <a data-apply="confirmation">Yes</a>'
+ ' <a data-dismiss="confirmation">No</a>'
+ '</div>'
+ '</div>'
});
@@ -131,24 +116,34 @@
.attr('href', this.getHref())
.attr('target', this.getTarget())
.off('click').on('click', function(event) {
options.onConfirm(event, that.$element);
that.runCallback(that.options.onConfirm, event, that.$element);
// If the button is a submit one
if (that.$element.attr('type') == 'submit')
that.$element.closest('form:first').submit();
if (that.$element.attr('type') == 'submit') {
var form = that.$element.closest('form');
var novalidate = form.attr('novalidate') !== undefined;
if (novalidate || form[0].checkValidity()) {
form.submit();
}
}
that.hide();
that.inState.click = false;
that.$element.trigger($.Event('confirm.bs.confirmation'));
});
$btnCancel.addClass(this.getBtnCancelClass())
.html(this.getBtnCancelLabel())
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
.off('click').on('click', function(event){
options.onCancel(event, that.$element);
.off('click').on('click', function(event) {
that.runCallback(that.options.onCancel, event, that.$element);
that.hide();
that.inState.click = false;
that.$element.trigger($.Event('cancel.bs.confirmation'));
});
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
@@ -161,73 +156,71 @@
}
Confirmation.prototype.getBtnOkClass = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnOkClass') || (typeof o.btnOkClass == 'function' ? o.btnOkClass.call(this, $e[0]) : o.btnOkClass);
return this.$element.data('btnOkClass') ||
(typeof this.options.btnOkClass == 'function' ? this.options.btnOkClass.call(this, this.$element) : this.options.btnOkClass);
}
Confirmation.prototype.getBtnOkLabel = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnOkLabel') || (typeof o.btnOkLabel == 'function' ? o.btnOkLabel.call(this, $e[0]) : o.btnOkLabel);
return this.$element.data('btnOkLabel') ||
(typeof this.options.btnOkLabel == 'function' ? this.options.btnOkLabel.call(this, this.$element) : this.options.btnOkLabel);
}
Confirmation.prototype.getBtnOkIcon = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnOkIcon') || (typeof o.btnOkIcon == 'function' ? o.btnOkIcon.call(this, $e[0]) : o.btnOkIcon);
return this.$element.data('btnOkIcon') ||
(typeof this.options.btnOkIcon == 'function' ? this.options.btnOkIcon.call(this, this.$element) : this.options.btnOkIcon);
}
Confirmation.prototype.getBtnCancelClass = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnCancelClass') || (typeof o.btnCancelClass == 'function' ? o.btnCancelClass.call(this, $e[0]) : o.btnCancelClass);
return this.$element.data('btnCancelClass') ||
(typeof this.options.btnCancelClass == 'function' ? this.options.btnCancelClass.call(this, this.$element) : this.options.btnCancelClass);
}
Confirmation.prototype.getBtnCancelLabel = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnCancelLabel') || (typeof o.btnCancelLabel == 'function' ? o.btnCancelLabel.call(this, $e[0]) : o.btnCancelLabel);
return this.$element.data('btnCancelLabel') ||
(typeof this.options.btnCancelLabel == 'function' ? this.options.btnCancelLabel.call(this, this.$element) : this.options.btnCancelLabel);
}
Confirmation.prototype.getBtnCancelIcon = function () {
var $e = this.$element;
var o = this.options;
return this.$element.data('btnCancelIcon') ||
(typeof this.options.btnCancelIcon == 'function' ? this.options.btnCancelIcon.call(this, this.$element) : this.options.btnCancelIcon);
}
return $e.attr('data-btnCancelIcon') || (typeof o.btnCancelIcon == 'function' ? o.btnCancelIcon.call(this, $e[0]) : o.btnCancelIcon);
Confirmation.prototype.getTitle = function () {
return this.$element.data('confirmation-title') ||
this.$element.data('title') ||
this.$element.attr('title') ||
(typeof this.options.title == 'function' ? this.options.title.call(this, this.$element) : this.options.title);
}
Confirmation.prototype.getHref = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-href') || (typeof o.href == 'function' ? o.href.call(this, $e[0]) : o.href);
return this.$element.data('href') ||
this.$element.attr('href') ||
(typeof this.options.href == 'function' ? this.options.href.call(this, this.$element) : this.options.href);
}
Confirmation.prototype.getTarget = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-target') || (typeof o.target == 'function' ? o.target.call(this, $e[0]) : o.target);
return this.$element.data('target') ||
this.$element.attr('target') ||
(typeof this.options.target == 'function' ? this.options.target.call(this, this.$element) : this.options.target);
}
Confirmation.prototype.isPopout = function () {
var popout;
var $e = this.$element;
var o = this.options;
var popout = this.$element.data('popout') ||
(typeof this.options.popout == 'function' ? this.options.popout.call(this, this.$element) : this.options.popout);
popout = $e.attr('data-popout') || (typeof o.popout == 'function' ? o.popout.call(this, $e[0]) : o.popout);
if(popout == 'false') popout = false;
if (popout == 'false') popout = false;
return popout
}
Confirmation.prototype.runCallback = function (callback, event, element) {
if (typeof callback == 'function') {
callback.call(this, event, element);
} else if (typeof callback == 'string') {
eval(callback);
}
}
// CONFIRMATION PLUGIN DEFINITION
// =========================

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -8,51 +8,51 @@ define(['jquery'], ($) => {
let Config = {
path: {
img: 'public/img/', // path for images
img: '/public/img/', // path for images
// user API
getCaptcha: 'api/user/getCaptcha', // ajax URL - get captcha image
getServerStatus: 'api/user/getEveServerStatus', // ajax URL - get EVE-Online server status
getCookieCharacterData: 'api/user/getCookieCharacter', // ajax URL - get character data from cookie
logIn: 'api/user/logIn', // ajax URL - login
logout: 'api/user/logout', // ajax URL - logout
deleteLog: 'api/user/deleteLog', // ajax URL - delete character log
openIngameWindow: 'api/user/openIngameWindow', // ajax URL - open inGame Window
saveUserConfig: 'api/user/saveAccount', // ajax URL - saves/update user account
deleteAccount: 'api/user/deleteAccount', // ajax URL - delete Account data
getCaptcha: '/api/user/getCaptcha', // ajax URL - get captcha image
getServerStatus: '/api/user/getEveServerStatus', // ajax URL - get EVE-Online server status
getCookieCharacterData: '/api/user/getCookieCharacter', // ajax URL - get character data from cookie
logIn: '/api/user/logIn', // ajax URL - login
logout: '/api/user/logout', // ajax URL - logout
deleteLog: '/api/user/deleteLog', // ajax URL - delete character log
openIngameWindow: '/api/user/openIngameWindow', // ajax URL - open inGame Window
saveUserConfig: '/api/user/saveAccount', // ajax URL - saves/update user account
deleteAccount: '/api/user/deleteAccount', // ajax URL - delete Account data
// access API
searchAccess: 'api/access/search', // ajax URL - search user/corporation/ally by name
searchAccess: '/api/access/search', // ajax URL - search user/corporation/ally by name
// main config/map ping API
initMap: 'api/map/init', // ajax URL - get static data
getAccessData: 'api/map/getAccessData', // ajax URL - get map access tokens (WebSocket)
updateMapData: 'api/map/updateData', // ajax URL - main map update trigger
updateUserData: 'api/map/updateUserData', // ajax URL - main map user data trigger
initMap: '/api/map/init', // ajax URL - get static data
getAccessData: '/api/map/getAccessData', // ajax URL - get map access tokens (WebSocket)
updateMapData: '/api/map/updateData', // ajax URL - main map update trigger
updateUserData: '/api/map/updateUserData', // ajax URL - main map user data trigger
// map API
saveMap: 'api/map/save', // ajax URL - save/update map
deleteMap: 'api/map/delete', // ajax URL - delete map
importMap: 'api/map/import', // ajax URL - import map
getMapConnectionData: 'api/map/getConnectionData', // ajax URL - get connection data
getMapLogData: 'api/map/getLogData', // ajax URL - get logs data
saveMap: '/api/map/save', // ajax URL - save/update map
deleteMap: '/api/map/delete', // ajax URL - delete map
importMap: '/api/map/import', // ajax URL - import map
getMapConnectionData: '/api/map/getConnectionData', // ajax URL - get connection data
getMapLogData: '/api/map/getLogData', // ajax URL - get logs data
// system API
searchSystem: 'api/system/search', // ajax URL - search system by name
saveSystem: 'api/system/save', // ajax URL - saves system to map
deleteSystem: 'api/system/delete', // ajax URL - delete system from map
getSystemGraphData: 'api/system/graphData', // ajax URL - get all system graph data
getConstellationData: 'api/system/constellationData', // ajax URL - get system constellation data
setDestination: 'api/system/setDestination', // ajax URL - set destination
pokeRally: 'api/system/pokeRally', // ajax URL - send rally point pokes
searchSystem: '/api/system/search', // ajax URL - search system by name
saveSystem: '/api/system/save', // ajax URL - saves system to map
deleteSystem: '/api/system/delete', // ajax URL - delete system from map
getSystemGraphData: '/api/system/graphData', // ajax URL - get all system graph data
getConstellationData: '/api/system/constellationData', // ajax URL - get system constellation data
setDestination: '/api/system/setDestination', // ajax URL - set destination
pokeRally: '/api/system/pokeRally', // ajax URL - send rally point pokes
// connection API
saveConnection: 'api/connection/save', // ajax URL - save new connection to map
deleteConnection: 'api/connection/delete', // ajax URL - delete connection from map
saveConnection: '/api/connection/save', // ajax URL - save new connection to map
deleteConnection: '/api/connection/delete', // ajax URL - delete connection from map
// signature API
getSignatures: 'api/signature/getAll', // ajax URL - get all signature data for system
saveSignatureData: 'api/signature/save', // ajax URL - save signature data for system
deleteSignatureData: 'api/signature/delete', // ajax URL - delete signature data for system
getSignatures: '/api/signature/getAll', // ajax URL - get all signature data for system
saveSignatureData: '/api/signature/save', // ajax URL - save signature data for system
deleteSignatureData: '/api/signature/delete', // ajax URL - delete signature data for system
// route API
searchRoute: 'api/route/search', // ajax URL - search system routes
searchRoute: '/api/route/search', // ajax URL - search system routes
// stats API
getStatisticsData: 'api/statistic/getData', // ajax URL - get statistics data (activity log)
getStatisticsData: '/api/statistic/getData', // ajax URL - get statistics data (activity log)
// GitHub API
gitHubReleases: 'api/github/releases' // ajax URL - get release info from GitHub
gitHubReleases: '/api/github/releases' // ajax URL - get release info from GitHub
},
breakpoints: [
{ name: 'desktop', width: Infinity },

View File

@@ -18,7 +18,7 @@ define([
'dialog/manual',
'dialog/changelog',
'dialog/credit'
], function($, Init, Util, Render, Gallery, bootbox) {
], ($, Init, Util, Render, Gallery, bootbox) => {
'use strict';
@@ -79,7 +79,7 @@ define([
/**
* set link observer for "version info" dialog
*/
let setVersionLinkObserver = function(){
let setVersionLinkObserver = () => {
$('.' + config.navigationVersionLinkClass).off('click').on('click', function(e){
$.fn.changelogsDialog();
});
@@ -94,13 +94,24 @@ define([
adminPanel.css({bottom: ((direction === 'up') ? '+' : '-') + '=35px'});
};
let setAcceptCookie = () => {
Util.setCookie('cookie', 1, config.defaultAcceptCookieExpire, 'd');
};
/**
* set page observer
*/
let setPageObserver = function(){
let setPageObserver = () => {
let ssoButtonElement = $('.' + config.ssoButtonClass);
let cookieHintElement = $('#' + config.cookieHintId);
// cookie hint --------------------------------------------------------
cookieHintElement.find('.btn-success').on('click', function(){
setAcceptCookie();
// confirmation no longer needed on SSO login button
ssoButtonElement.confirmation('destroy');
});
cookieHintElement.on('show.bs.collapse', function () {
// move admin panel upwards (prevents overlapping with cookie notice)
moveAdminPanel('up');
@@ -127,7 +138,7 @@ define([
btnCancelIcon: 'fas fa-fw fa-check',
onCancel: function(e, target){
// "Accept cookies"
Util.setCookie('cookie', 1, config.defaultAcceptCookieExpire, 'd');
setAcceptCookie();
// set "default" href
let href = $(target).data('bs.confirmation').getHref();
@@ -141,13 +152,9 @@ define([
}
};
$('.' + config.ssoButtonClass).confirmation(confirmationSettings);
ssoButtonElement.confirmation(confirmationSettings);
}
cookieHintElement.find('.btn-success').on('click', function(){
Util.setCookie('cookie', 1, config.defaultAcceptCookieExpire, 'd');
});
// manual -------------------------------------------------------------
$('.' + config.navigationLinkManualClass).on('click', function(e){
e.preventDefault();
@@ -179,7 +186,7 @@ define([
/**
* init image carousel
*/
let initCarousel = function(){
let initCarousel = () => {
// check if carousel exists
if($('#' + config.galleryCarouselId).length === 0){
@@ -313,7 +320,7 @@ define([
* get all thumbnail elements
* @returns {*|jQuery|HTMLElement}
*/
let getThumbnailElements = function(){
let getThumbnailElements = () => {
return $('a[data-gallery="#' + config.galleryId + '"]').not('.disabled');
};
@@ -321,14 +328,14 @@ define([
* init gallery for thumbnail elements
* @param newElements
*/
let initGallery = function(newElements){
let initGallery = (newElements) => {
if( newElements.length > 0){
// We have to add ALL thumbnail elements to the gallery!
// -> even those wthat are invisible (not lazyLoaded) now!
// -> This is required for "swipe" through all images
let allThumbLinks = getThumbnailElements();
requirejs(['blueImpGalleryBootstrap'], function() {
requirejs(['blueImpGalleryBootstrap'], () => {
$(newElements).each(function() {
let borderless = false;
@@ -360,7 +367,7 @@ define([
/**
* init "YouTube" video preview
*/
let initYoutube = function(){
let initYoutube = () => {
$('.youtube').each(function() {
// Based on the YouTube ID, we can easily find the thumbnail image
@@ -395,11 +402,11 @@ define([
/**
* init scrollSpy for navigation bar
*/
let initScrollSpy = function(){
let initScrollSpy = () => {
// init scrollspy
// show elements that are currently in the viewport
let showVisibleElements = function(){
let showVisibleElements = () => {
// find all elements that should be animated
let visibleElements = $('.' + config.animateElementClass).isInViewport();
@@ -421,7 +428,7 @@ define([
});
};
$( window ).scroll(function() {
$( window ).scroll(() => {
// check for new visible elements
showVisibleElements();
});
@@ -446,7 +453,7 @@ define([
* get current EVE-Online server status
* -> show "server panel"
*/
let initServerStatus = function(){
let initServerStatus = () => {
$.ajax({
type: 'POST',
url: Init.path.getServerStatus,
@@ -485,16 +492,16 @@ define([
* show "notification panel" to user
* -> checks if panel not already shown
*/
let initNotificationPanel = function(){
let initNotificationPanel = () => {
let storageKey = 'notification_panel';
let currentVersion = Util.getVersion();
let showNotificationPanel = function(){
let showNotificationPanel = () => {
let data = {
version: Util.getVersion()
};
requirejs(['text!templates/ui/notice.html', 'mustache'], function(template, Mustache) {
requirejs(['text!templates/ui/notice.html', 'mustache'], (template, Mustache) => {
let content = Mustache.render(template, data);
let notificationPanel = $('#' + config.notificationPanelId);
@@ -704,7 +711,7 @@ define([
* @param status
* @param error
*/
let handleAjaxErrorResponse = function(jqXHR, status, error){
let handleAjaxErrorResponse = (jqXHR, status, error) => {
let type = status;
let title = 'Status ' + jqXHR.status + ': ' + error;
@@ -734,7 +741,7 @@ define([
/**
* main init "landing" page
*/
$(function(){
$(() => {
// clear sessionStorage
Util.clearSessionStorage();
@@ -816,9 +823,9 @@ define([
initYoutube();
// draw header logo
$('#' + config.logoContainerId).drawLogo(function(){
$('#' + config.logoContainerId).drawLogo(() => {
// init header animation
$('#' + config.headerContainerId).initHeader(function(){
$('#' + config.headerContainerId).initHeader(() => {
});
}, false);

View File

@@ -1039,6 +1039,18 @@ define([
return hasAccess;
};
/**
* get a unique map url for deeplinking
* @param mapId
* @returns {string}
*/
let getMapDeeplinkUrl = (mapId) => {
let url = location.protocol + '//' + location.host + '/map';
url += mapId ? '/' + encodeURIComponent(window.btoa(mapId)) : '';
return url;
};
return {
config: config,
mapOptions: mapOptions,
@@ -1073,6 +1085,7 @@ define([
storeLocalData: storeLocalData,
deleteLocalData: deleteLocalData,
getSystemId: getSystemId,
checkRight: checkRight
checkRight: checkRight,
getMapDeeplinkUrl: getMapDeeplinkUrl
};
});

View File

@@ -628,6 +628,12 @@ define([
let mapElement = $(mapConfig.map.getContainer());
let mapWrapperElement = mapElement.closest('.mCustomScrollbar');
mapWrapperElement.mCustomScrollbar('update');
// change url to unique map URL
if (history.pushState) {
let mapUrl = MapUtil.getMapDeeplinkUrl(mapConfig.config.id);
history.pushState({}, '', mapUrl);
}
});
}
});
@@ -937,6 +943,15 @@ define([
return Promise.all(promiseDeleteTab);
};
/**
* get last URL segment e.g. https://pathfinder/map/test -> test
* @returns {string | undefined}
*/
let getLastUrlSegment = () => {
let parts = window.location.pathname.split('/');
return parts.pop() || parts.pop();
};
/**
* set "default" map tab
* -> default mapId might be available in local storage
@@ -946,6 +961,10 @@ define([
*/
let showDefaultTab = (tabMapElement, currentUserData) => {
let getActiveTabLinkElement = (mapId) => {
return tabMapElement.find('.' + config.mapTabClass + '[data-mapid="' + mapId + '"] > a');
};
/**
* show default tab promise
* @param resolve
@@ -956,13 +975,31 @@ define([
promiseStore.then((data) => {
let activeTabLinkElement = false;
if(data && data.defaultMapId){
// make specific map tab active
activeTabLinkElement = tabMapElement.find('.' + config.mapTabClass + '[data-mapid="' + data.defaultMapId + '"] > a');
// check for existing mapId URL identifier ------------------------------------------------------------
let lastURLSegment = getLastUrlSegment();
let defaultMapId = 0;
try{
defaultMapId = parseInt(atob(decodeURIComponent(lastURLSegment)));
}catch(e){
// defaultMapID could not be extracted from URL -> ignore
}
if(defaultMapId){
activeTabLinkElement = getActiveTabLinkElement(defaultMapId);
}
// ... else check for existing cached default mapId ---------------------------------------------------
if(
(!activeTabLinkElement || !activeTabLinkElement.length) &&
data && data.defaultMapId
){
// make specific map tab active
activeTabLinkElement = getActiveTabLinkElement(data.defaultMapId);
}
// ... else make first map tab active (default) -------------------------------------------------------
if(!activeTabLinkElement || !activeTabLinkElement.length){
// make first map tab active (default)
activeTabLinkElement = tabMapElement.find('.' + config.mapTabClass + ':not(.pull-right):first > a');
}

View File

@@ -42,6 +42,9 @@ define([
tableCellEllipsisClass: 'pf-table-cell-ellipses-auto', // class for table "ellipsis" cells
tableCellActionIconClass: 'pf-table-action-icon-cell', // class for table "action" icon (icon is part of cell content)
textActionIconClass: 'pf-module-icon-button', // class for text action
textActionIconCopyClass: 'pf-module-icon-button-copy', // class for text action "copy"
loadingOptions: { // config for loading overlay
icon: {
size: 'fa-2x'
@@ -79,6 +82,99 @@ define([
return icon.length ? '<i class="fas fa-fw ' + icon + ' ' + config.tableCellActionIconClass + '" title="' + type + '" data-toggle="tooltip"></i>' : '';
};
/**
* write clipboard text
* @param text
* @returns {Promise<any>}
*/
let copyToClipboard = (text) => {
let copyToClipboardExecutor = (resolve, reject) => {
let payload = {
action: 'copyToClipboard',
data: false
};
if (navigator.clipboard) {
// get current permission status
navigator.permissions.query({
name: 'clipboard-write'
}).then(permissionStatus => {
// will be 'granted', 'denied' or 'prompt'
if(
permissionStatus.state === 'granted' ||
permissionStatus.state === 'prompt'
){
navigator.clipboard.writeText(text)
.then(() => {
payload.data = true;
resolve(payload); })
.catch(err => {
let errorMsg = 'Failed to write clipboard content';
console.error(errorMsg, err);
Util.showNotify({title: 'Clipboard API', text: errorMsg, type: 'error'});
resolve(payload);
});
}else{
Util.showNotify({title: 'Clipboard API', text: 'You denied write access', type: 'warning'});
resolve(payload);
}
});
} else {
console.warn('Clipboard API not supported by your browser');
resolve(payload);
}
};
return new Promise(copyToClipboardExecutor);
};
/**
* read clipboard text
* @returns {Promise<any>}
*/
let readFromClipboard = () => {
let readFromClipboardExecutor = (resolve, reject) => {
let payload = {
action: 'readFromClipboard',
data: false
};
if (navigator.clipboard) {
// get current permission status
navigator.permissions.query({
name: 'clipboard-read'
}).then(permissionStatus => {
// will be 'granted', 'denied' or 'prompt'
if(
permissionStatus.state === 'granted' ||
permissionStatus.state === 'prompt'
){
navigator.clipboard.readText()
.then(text => {
payload.data = text;
resolve(payload); })
.catch(err => {
let errorMsg = 'Failed to read clipboard content';
console.error(errorMsg, err);
Util.showNotify({title: 'Clipboard API', text: errorMsg, type: 'error'});
resolve(payload);
});
}else{
Util.showNotify({title: 'Clipboard API', text: 'You denied read access', type: 'warning'});
resolve(payload);
}
});
} else {
console.warn('Clipboard API not supported by your browser');
resolve(payload);
}
};
return new Promise(readFromClipboardExecutor);
};
/**
* loads the map info data into an element
* @param mapData
@@ -115,58 +211,82 @@ define([
class: 'dl-horizontal',
css: {'float': 'left'}
}).append(
$('<dt>').text( 'Icon' )
$('<dt>').text('Icon')
).append(
$('<dd>').append(
$('<i>', {
class: ['fas', 'fa-fw', mapData.config.icon].join(' ')
})
)
).append(
$('<dt>').text('Name')
).append(
$('<dd>').text(mapData.config.name)
).append(
$('<dt>').text('Type')
).append(
$('<dd>', {
class: mapType.class
}).text(mapType.name)
).append(
$('<dt>').text('Link')
).append(
$('<dd>', {
class: [config.textActionIconClass, config.textActionIconCopyClass].join(' ')
}).append(
$('<span>', {
title: 'copy to clipboard',
}).text(MapUtil.getMapDeeplinkUrl(mapData.config.id) + ' ')
).append(
$('<dd>').append(
$('<i>', {
class: ['fas', 'fa-fw', mapData.config.icon].join(' ')
})
)
).append(
$('<dt>').text( 'Name' )
).append(
$('<dd>').text( mapData.config.name )
).append(
$('<dt>').text( 'Type' )
).append(
$('<dd>', {
class: mapType.class
}).text( mapType.name )
);
$('<i>', {
class: ['fas', 'fa-fw', 'fa-copy'].join(' ')
})
)
);
mapElement.append(dlElementLeft);
let dlElementRight = $('<dl>', {
class: 'dl-horizontal',
css: {'float': 'right'}
}).append(
$('<dt>').text( 'Systems' )
).append(
$('<dd>', {
class: ['txt-color', maxSystemsClass].join(' ')
}).text( countSystems + ' / ' + mapType.defaultConfig.max_systems )
).append(
$('<dt>').text( 'Connections' )
).append(
$('<dd>').text( countConnections )
).append(
$('<dt>').text( 'Lifetime' )
).append(
$('<dd>', {
class: config.mapInfoLifetimeCounterClass,
text: mapData.config.created
})
).append(
$('<dt>').text( 'Created' )
).append(
$('<dd>').text(Util.getObjVal(mapDataOrigin, 'config.created.character.name'))
);
}).append(
$('<dt>').text('Systems')
).append(
$('<dd>', {
class: ['txt-color', maxSystemsClass].join(' ')
}).text(countSystems + ' / ' + mapType.defaultConfig.max_systems)
).append(
$('<dt>').text('Connections')
).append(
$('<dd>').text(countConnections)
).append(
$('<dt>').text('Lifetime')
).append(
$('<dd>', {
class: config.mapInfoLifetimeCounterClass,
text: mapData.config.created
})
).append(
$('<dt>').text('Created')
).append(
$('<dd>').text(Util.getObjVal(mapDataOrigin, 'config.created.character.name'))
);
mapElement.append(dlElementRight);
// init map lifetime counter
$('.' + config.mapInfoLifetimeCounterClass).initTimestampCounter();
mapElement.find('.' + config.textActionIconCopyClass).on('click', function(){
let mapUrl = $(this).find('span').text().trim();
copyToClipboard(mapUrl).then(payload => {
if(payload.data){
Util.showNotify({title: 'Copied to clipbaord', text: mapUrl, type: 'success'});
}
});
});
mapElement.initTooltips();
mapElement.hideLoadingAnimation();
};

View File

@@ -1,5 +1,5 @@
/*!
* Bootstrap Confirmation v1.0.5
* Bootstrap Confirmation v1.0.7
* https://github.com/tavicu/bs-confirmation
*/
+function ($) {
@@ -15,62 +15,47 @@
this.init('confirmation', element, options);
$(element).on('show.bs.confirmation', function(e) {
that.options.onShow(e, this);
$(this).addClass('open');
var options = that.options;
var all = options.all_selector;
if(options.singleton)
{
$(all).not(that.$element).each(function()
{
if( $(this).hasClass('open') )
{
$(this).confirmation('hide');
}
});
}
});
$(element).on('hide.bs.confirmation', function(e) {
that.options.onHide(e, this);
$(this).removeClass('open');
});
$(element).on('shown.bs.confirmation', function(e) {
var options = that.options;
var all = options.all_selector;
if(that.isPopout()) {
if(!event_body) {
event_body = $('body').on('click', function (e) {
if(that.$element.is(e.target)) return;
if(that.$element.has(e.target).length) return;
if($('.popover').has(e.target).length) return;
that.hide();
that.inState.click = false;
$('body').unbind(e);
event_body = false;
return;
});
}
}
});
if(options.selector) {
if (options.selector) {
$(element).on('click.bs.confirmation', options.selector, function(e) {
e.preventDefault();
});
} else {
$(element).on('click.bs.confirmation', function(e) {
$(element).on('show.bs.confirmation', function(event) {
that.runCallback(that.options.onShow, event, that.$element);
that.$element.addClass('open');
if (that.options.singleton) {
$(that.options.all_selector).not(that.$element).each(function() {
if ($(this).hasClass('open')) {
$(this).confirmation('hide');
}
});
}
}).on('hide.bs.confirmation', function(event) {
that.runCallback(that.options.onHide, event, that.$element);
that.$element.removeClass('open');
}).on('shown.bs.confirmation', function(e) {
if (!that.isPopout() && !event_body) {
return;
}
event_body = $('body').on('click', function (e) {
if (that.$element.is(e.target)) return;
if (that.$element.has(e.target).length) return;
if ($('.popover').has(e.target).length) return;
that.hide();
that.inState.click = false;
$('body').unbind(e);
event_body = false;
return;
});
}).on('click.bs.confirmation', function(e) {
e.preventDefault();
});
}
@@ -78,30 +63,30 @@
if (!$.fn.popover || !$.fn.tooltip) throw new Error('Confirmation requires popover.js and tooltip.js');
Confirmation.VERSION = '1.0.5'
Confirmation.VERSION = '1.0.7'
Confirmation.DEFAULTS = $.extend({}, $.fn.popover.Constructor.DEFAULTS, {
placement : 'right',
title : 'Are you sure?',
btnOkClass : 'btn btn-sm btn-danger',
btnOkLabel : 'Delete',
btnOkIcon : 'glyphicon glyphicon-ok',
btnCancelClass : 'btn btn-sm btn-default',
btnCancelLabel : 'Cancel',
btnCancelIcon : 'glyphicon glyphicon-remove',
href : '#',
target : '_self',
singleton : true,
popout : true,
onShow : function(event, element){},
onHide : function(event, element){},
onConfirm : function(event, element){},
onCancel : function(event, element){},
template : '<div class="popover"><div class="arrow"></div>'
placement : 'right',
title : 'Are you sure?',
btnOkClass : 'btn btn-sm btn-danger',
btnOkLabel : 'Delete',
btnOkIcon : 'glyphicon glyphicon-ok',
btnCancelClass : 'btn btn-sm btn-default',
btnCancelLabel : 'Cancel',
btnCancelIcon : 'glyphicon glyphicon-remove',
href : '#',
target : '_self',
singleton : true,
popout : true,
onShow : function(event, element) {},
onHide : function(event, element) {},
onConfirm : function(event, element) {},
onCancel : function(event, element) {},
template : '<div class="popover"><div class="arrow"></div>'
+ '<h3 class="popover-title"></h3>'
+ '<div class="popover-content">'
+ '<a data-apply="confirmation">Yes</a>'
+ '<a data-dismiss="confirmation">No</a>'
+ ' <a data-apply="confirmation">Yes</a>'
+ ' <a data-dismiss="confirmation">No</a>'
+ '</div>'
+ '</div>'
});
@@ -131,24 +116,34 @@
.attr('href', this.getHref())
.attr('target', this.getTarget())
.off('click').on('click', function(event) {
options.onConfirm(event, that.$element);
that.runCallback(that.options.onConfirm, event, that.$element);
// If the button is a submit one
if (that.$element.attr('type') == 'submit')
that.$element.closest('form:first').submit();
if (that.$element.attr('type') == 'submit') {
var form = that.$element.closest('form');
var novalidate = form.attr('novalidate') !== undefined;
if (novalidate || form[0].checkValidity()) {
form.submit();
}
}
that.hide();
that.inState.click = false;
that.$element.trigger($.Event('confirm.bs.confirmation'));
});
$btnCancel.addClass(this.getBtnCancelClass())
.html(this.getBtnCancelLabel())
.prepend($('<i></i>').addClass(this.getBtnCancelIcon()), " ")
.off('click').on('click', function(event){
options.onCancel(event, that.$element);
.off('click').on('click', function(event) {
that.runCallback(that.options.onCancel, event, that.$element);
that.hide();
that.inState.click = false;
that.$element.trigger($.Event('cancel.bs.confirmation'));
});
$tip.find('.popover-title')[this.options.html ? 'html' : 'text'](title);
@@ -161,73 +156,71 @@
}
Confirmation.prototype.getBtnOkClass = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnOkClass') || (typeof o.btnOkClass == 'function' ? o.btnOkClass.call(this, $e[0]) : o.btnOkClass);
return this.$element.data('btnOkClass') ||
(typeof this.options.btnOkClass == 'function' ? this.options.btnOkClass.call(this, this.$element) : this.options.btnOkClass);
}
Confirmation.prototype.getBtnOkLabel = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnOkLabel') || (typeof o.btnOkLabel == 'function' ? o.btnOkLabel.call(this, $e[0]) : o.btnOkLabel);
return this.$element.data('btnOkLabel') ||
(typeof this.options.btnOkLabel == 'function' ? this.options.btnOkLabel.call(this, this.$element) : this.options.btnOkLabel);
}
Confirmation.prototype.getBtnOkIcon = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnOkIcon') || (typeof o.btnOkIcon == 'function' ? o.btnOkIcon.call(this, $e[0]) : o.btnOkIcon);
return this.$element.data('btnOkIcon') ||
(typeof this.options.btnOkIcon == 'function' ? this.options.btnOkIcon.call(this, this.$element) : this.options.btnOkIcon);
}
Confirmation.prototype.getBtnCancelClass = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnCancelClass') || (typeof o.btnCancelClass == 'function' ? o.btnCancelClass.call(this, $e[0]) : o.btnCancelClass);
return this.$element.data('btnCancelClass') ||
(typeof this.options.btnCancelClass == 'function' ? this.options.btnCancelClass.call(this, this.$element) : this.options.btnCancelClass);
}
Confirmation.prototype.getBtnCancelLabel = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-btnCancelLabel') || (typeof o.btnCancelLabel == 'function' ? o.btnCancelLabel.call(this, $e[0]) : o.btnCancelLabel);
return this.$element.data('btnCancelLabel') ||
(typeof this.options.btnCancelLabel == 'function' ? this.options.btnCancelLabel.call(this, this.$element) : this.options.btnCancelLabel);
}
Confirmation.prototype.getBtnCancelIcon = function () {
var $e = this.$element;
var o = this.options;
return this.$element.data('btnCancelIcon') ||
(typeof this.options.btnCancelIcon == 'function' ? this.options.btnCancelIcon.call(this, this.$element) : this.options.btnCancelIcon);
}
return $e.attr('data-btnCancelIcon') || (typeof o.btnCancelIcon == 'function' ? o.btnCancelIcon.call(this, $e[0]) : o.btnCancelIcon);
Confirmation.prototype.getTitle = function () {
return this.$element.data('confirmation-title') ||
this.$element.data('title') ||
this.$element.attr('title') ||
(typeof this.options.title == 'function' ? this.options.title.call(this, this.$element) : this.options.title);
}
Confirmation.prototype.getHref = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-href') || (typeof o.href == 'function' ? o.href.call(this, $e[0]) : o.href);
return this.$element.data('href') ||
this.$element.attr('href') ||
(typeof this.options.href == 'function' ? this.options.href.call(this, this.$element) : this.options.href);
}
Confirmation.prototype.getTarget = function () {
var $e = this.$element;
var o = this.options;
return $e.attr('data-target') || (typeof o.target == 'function' ? o.target.call(this, $e[0]) : o.target);
return this.$element.data('target') ||
this.$element.attr('target') ||
(typeof this.options.target == 'function' ? this.options.target.call(this, this.$element) : this.options.target);
}
Confirmation.prototype.isPopout = function () {
var popout;
var $e = this.$element;
var o = this.options;
var popout = this.$element.data('popout') ||
(typeof this.options.popout == 'function' ? this.options.popout.call(this, this.$element) : this.options.popout);
popout = $e.attr('data-popout') || (typeof o.popout == 'function' ? o.popout.call(this, $e[0]) : o.popout);
if(popout == 'false') popout = false;
if (popout == 'false') popout = false;
return popout
}
Confirmation.prototype.runCallback = function (callback, event, element) {
if (typeof callback == 'function') {
callback.call(this, event, element);
} else if (typeof callback == 'string') {
eval(callback);
}
}
// CONFIRMATION PLUGIN DEFINITION
// =========================

View File

@@ -138,7 +138,12 @@ em{
&:hover, &.active{
color: $orange !important;
}
}
.pf-module-icon-button-copy{
cursor: copy;
-moz-user-select: text;
user-select: text;
}
// links ==========================================================================================