- new "deep links" added, custom URLs for e.g. system rally poke notifications, closed #682

This commit is contained in:
Mark Friedrich
2018-09-06 19:12:41 +02:00
parent 4afd3b6707
commit 4385c4a3d0
19 changed files with 412 additions and 288 deletions

View File

@@ -98,10 +98,20 @@ class SlackRallyWebhookHandler extends AbstractSlackWebhookHandler {
$attachment['fields'][] = $this->generateAttachmentField('TrueSec', $objectData['objTrueSec']);
}
if(!empty($objectData['objCountPlanets'])){
// System planet count
$attachment['fields'][] = $this->generateAttachmentField('Planets', $objectData['objCountPlanets']);
}
if(!empty($objectData['objDescription'])){
// System trueSec
$attachment['fields'][] = $this->generateAttachmentField('System description', '```' . $objectData['objDescription'] . '```', false, false);
}
if(!empty($objectData['objUrl'])){
// System deeeplink
$attachment['fields'][] = $this->generateAttachmentField('', $objectData['objUrl'] , false, false);
}
}
}

View File

@@ -1210,7 +1210,7 @@ class MapModel extends AbstractMapTrackingModel {
* checks whether this map is private map
* @return bool
*/
public function isPrivate(){
public function isPrivate() : bool {
return ($this->typeId->id === 2);
}
@@ -1218,7 +1218,7 @@ class MapModel extends AbstractMapTrackingModel {
* checks whether this map is corporation map
* @return bool
*/
public function isCorporation(){
public function isCorporation() : bool {
return ($this->typeId->id === 3);
}
@@ -1226,7 +1226,7 @@ class MapModel extends AbstractMapTrackingModel {
* checks whether this map is alliance map
* @return bool
*/
public function isAlliance(){
public function isAlliance() : bool {
return ($this->typeId->id === 4);
}
@@ -1242,6 +1242,22 @@ class MapModel extends AbstractMapTrackingModel {
return $scope;
}
/**
* get deeplink url for map
* -> optional return link for map + system
* @param int $systemId
* @return string
*/
public function getDeeplinkUrl(int $systemId = 0) : string {
$url = '';
if( !$this->dry() ){
$param = rawurlencode(base64_encode($this->_id));
$param .= $systemId ? '_' . rawurlencode(base64_encode($systemId)) : '';
$url = $this->getF3()->get('SCHEME') . '://' . $this->getF3()->get('HOST') . $this->getF3()->alias('map', ['*' => '/' . $param]);
}
return $url;
}
/**
* get log file data
* @param int $offset

View File

@@ -738,12 +738,14 @@ class SystemModel extends AbstractMapTrackingModel {
];
if($fullData){
$objectData['objUrl'] = $this->getMap()->getDeeplinkUrl($this->_id);
$objectData['objAlias'] = $this->alias;
$objectData['objRegion'] = $this->region;
$objectData['objIsWormhole'] = $this->isWormhole();
$objectData['objEffect'] = $this->effect;
$objectData['objSecurity'] = $this->security;
$objectData['objTrueSec'] = $this->trueSec;
$objectData['objCountPlanets'] = count((array)$this->planets);
$objectData['objDescription'] = $this->description;
}

View File

@@ -12,8 +12,6 @@ define([
// all Datatables stuff is available...
let initDefaultDatatablesConfig = () => {
$.extend(true, $.fn.dataTable.defaults, {
pageLength: -1,
pagingType: 'simple_numbers',

View File

@@ -48,7 +48,9 @@ define([
* @param system
*/
$.fn.showRallyPointDialog = (system) => {
let mapData = Util.getCurrentMapData(system.data('mapid'));
let mapId = system.data('mapid');
let systemId = system.data('id');
let mapData = Util.getCurrentMapData(mapId);
requirejs(['text!templates/dialog/system_rally.html', 'mustache'], function(template, Mustache) {
@@ -108,7 +110,8 @@ define([
mailRallyEnabled: Boolean(Util.getObjVal(mapData, 'config.logging.mailRally')),
dialogRallyMessageDefault: config.dialogRallyMessageDefault,
systemId: system.data('id')
systemUrl: MapUtil.getMapDeeplinkUrl(mapId, systemId),
systemId: systemId
};
let content = Mustache.render(template, data);

View File

@@ -570,6 +570,7 @@ define([
/**
* set system visibility e.g. or filtered systems
* @param system
* @param map
* @param visible
*/
let setSystemVisible = (system, map, visible) => {
@@ -1585,12 +1586,13 @@ define([
/**
* get a unique map url for deeplinking
* @param mapId
* @param systemId
* @returns {string}
*/
let getMapDeeplinkUrl = (mapId) => {
let getMapDeeplinkUrl = (mapId, systemId) => {
let url = location.protocol + '//' + location.host + '/map';
url += mapId ? '/' + encodeURIComponent(window.btoa(mapId)) : '';
url += systemId ? '_' + encodeURIComponent(window.btoa(systemId)) : '';
return url;
};

View File

@@ -246,7 +246,7 @@ define([
*/
let showPanel = (parentElement, Module, mapId, data) => {
let moduleElement = Module.getModule(parentElement, mapId, data);
if (moduleElement) {
if(moduleElement) {
// store Module object to DOM element for further access
moduleElement.data('module', Module);
moduleElement.data('data', data);
@@ -265,12 +265,12 @@ define([
// check for stored module order in indexDB (client) ----------------------------------------------
let key = 'modules_cell_' + this.parentElement.attr('data-position');
if (
if(
dataStore &&
dataStore[key]
) {
){
let positionIndex = dataStore[key].indexOf(Module.config.moduleName);
if (positionIndex !== -1) {
if(positionIndex !== -1) {
// first index (0) => is position 1
defaultPosition = positionIndex + 1;
}
@@ -284,13 +284,13 @@ define([
// insert at correct position ---------------------------------------------------------------------
let prevModuleElement = this.parentElement.find('.' + config.moduleClass + ':nth-child(' + position + ')');
if (prevModuleElement.length) {
if(prevModuleElement.length) {
this.moduleElement.insertAfter(prevModuleElement);
} else {
this.parentElement.prepend(this.moduleElement);
}
if (typeof Module.beforeShow === 'function') {
if(typeof Module.beforeShow === 'function') {
Module.beforeShow(this.moduleElement, moduleElement.data('data'));
}
@@ -304,7 +304,7 @@ define([
complete: function (moduleElement) {
moduleElement = $(moduleElement);
let Module = $(moduleElement).data('module');
if (typeof Module.initModule === 'function') {
if(typeof Module.initModule === 'function') {
Module.initModule(moduleElement, mapId, moduleElement.data('data'));
}
@@ -328,7 +328,7 @@ define([
// check if module already exists
let moduleElement = parentElement.find('.' + Module.config.moduleTypeClass);
if (moduleElement.length > 0) {
if(moduleElement.length > 0) {
removeModule(moduleElement, Module, () => {
showPanel(parentElement, Module, mapId, data);
}, true);
@@ -714,7 +714,7 @@ define([
if(mapTabChangeBlocked === false){
let tabLinkElement = $(this);
let mapId = tabLinkElement.data('map-id');
let mapId = tabLinkElement.data('mapId');
// ignore "add" tab. no need for map change
if(mapId > 0){
@@ -741,7 +741,7 @@ define([
// tab switch --------------------------------------------------------------------------------------------
$(tabListElement).on('show.bs.tab', 'a', function(e){
let mapId = $(e.target).data('map-id');
let mapId = $(e.target).data('mapId');
if(mapId > 0){
// save mapId as new "default" (local storage)
@@ -755,7 +755,9 @@ define([
$(tabListElement).on('shown.bs.tab', 'a', function(e){
// load new map right after tab-change
let mapId = $(e.target).data('map-id');
let tabLinkElement = $(e.target);
let mapId = tabLinkElement.data('mapId');
let defaultSystemId = tabLinkElement.data('defaultSystemId');
let tabMapData = Util.getCurrentMapData(mapId);
if(tabMapData !== false){
@@ -773,10 +775,19 @@ define([
let activeSystem = mapElement.find('.' + MapUtil.config.systemActiveClass + ':first');
if(activeSystem.length){
MapUtil.setSystemActive(mapConfig.map, activeSystem);
}else if(defaultSystemId){
// currently no system "active" check if there is a default system set for this mapTab
// -> e.g. from URL link
let systemId = MapUtil.getSystemId(mapConfig.config.id, defaultSystemId);
let system = mapElement.find('#' + systemId);
if(system.length){
// system exists on map -> make active and show panels
MapUtil.showSystemInfo(mapConfig.map, system);
}
}
// change url to unique map URL
if (history.pushState) {
if(history.pushState) {
let mapUrl = MapUtil.getMapDeeplinkUrl(mapConfig.config.id);
history.pushState({}, '', mapUrl);
}
@@ -788,8 +799,8 @@ define([
});
$(tabListElement).on('hide.bs.tab', 'a', function(e){
let newMapId = $(e.relatedTarget).data('map-id');
let oldMapId = $(e.target).data('map-id');
let newMapId = $(e.relatedTarget).data('mapId');
let oldMapId = $(e.target).data('mapId');
// skip "add button"
if(newMapId > 0){
@@ -823,7 +834,7 @@ define([
*/
let updateTabExecutor = (resolve, reject) => {
// set "main" data
tabElement.data('map-id', options.id);
tabElement.data('mapId', options.id);
// add updated timestamp (not available for "add" tab
if(Util.getObjVal(options, 'updated.updated')){
@@ -988,7 +999,7 @@ define([
let key = 'maps_list_' + tabBar.attr('data-position');
if(dataStore && dataStore[key]){
let positionIndex = dataStore[key].indexOf(this.options.id);
if (positionIndex !== -1) {
if(positionIndex !== -1) {
// first index (0) => is position 1
defaultPosition = positionIndex + 1;
}
@@ -1000,7 +1011,7 @@ define([
// insert at correct position -------------------------------------------------------------------------
let prevListElement = tabBar.find('li' + '' + ':nth-child(' + position + ')');
if (prevListElement.length) {
if(prevListElement.length) {
tabListElement.insertAfter(prevListElement);
} else {
tabBar.prepend(tabListElement);
@@ -1085,7 +1096,7 @@ define([
let tabElements = mapModule.getMapTabElements();
for(let i = 0; i < tabElements.length; i++){
let tabElement = $(tabElements[i]);
let mapId = tabElement.data('map-id');
let mapId = tabElement.data('mapId');
if(mapId > 0){
promiseDeleteTab.push(deleteTab(tabMapElement, mapId));
}
@@ -1104,6 +1115,23 @@ define([
return parts.pop() || parts.pop();
};
/**
* extract data from map url
* @returns {Array}
*/
let getMapDataFromUrl = () => {
let data = [];
let lastURLSegment = getLastUrlSegment();
if(lastURLSegment.length){
try{
data = lastURLSegment.split('_').map(part => parseInt(atob(decodeURIComponent(part))) || 0);
}catch(e){
// data could not be extracted from URL -> ignore
}
}
return data;
};
/**
* set "default" map tab
* -> default mapId might be available in local storage
@@ -1128,17 +1156,15 @@ define([
let activeTabLinkElement = false;
// 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
}
let urlData = getMapDataFromUrl();
let defaultMapId = urlData[0] || 0;
let defaultSystemId = urlData[1] || 0;
if(defaultMapId){
activeTabLinkElement = getActiveTabLinkElement(defaultMapId);
if(defaultSystemId && activeTabLinkElement.length){
activeTabLinkElement.data('defaultSystemId', defaultSystemId);
}
}
// ... else check for existing cached default mapId ---------------------------------------------------
@@ -1218,7 +1244,7 @@ define([
// check whether a tab/map is still active
for(let i = 0; i < tabElements.length; i++){
let tabElement = $(tabElements[i]);
let mapId = tabElement.data('map-id');
let mapId = tabElement.data('mapId');
if(mapId > 0){
let tabMapData = Util.getCurrentMapData(mapId);

View File

@@ -92,99 +92,6 @@ define([
return '<span class="' + config.tableCellUnknownDataClass + '">unknown</span>';
};
/**
* 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
@@ -289,7 +196,7 @@ define([
mapElement.find('.' + config.textActionIconCopyClass).on('click', function(){
let mapUrl = $(this).find('span').text().trim();
copyToClipboard(mapUrl).then(payload => {
Util.copyToClipboard(mapUrl).then(payload => {
if(payload.data){
Util.showNotify({title: 'Copied to clipbaord', text: mapUrl, type: 'success'});
}

View File

@@ -19,10 +19,14 @@ define([
// system info module
moduleTypeClass: 'pf-system-info-module', // class for this module
// headline toolbar
moduleHeadlineIconClass: 'pf-module-icon-button', // class for toolbar icons in the head
// breadcrumb
constellationLinkClass: 'pf-system-info-constellation', // class for "constellation" name
regionLinkClass: 'pf-system-info-region', // class for "region" name
typeLinkClass: 'pf-system-info-type', // class for "type" name
urlLinkClass: 'pf-system-info-url', // class for "url" copy link
// info table
systemInfoTableClass: 'pf-module-table', // class for system info table
@@ -185,13 +189,10 @@ define([
functions: {
after: function(conf){
let tempModuleElement = conf.position;
// lock "description" field until first update
tempModuleElement.find('.' + config.descriptionArea).showLoadingAnimation();
// "add description" button
let descriptionButton = tempModuleElement.find('.' + config.addDescriptionButtonClass);
// description textarea element
let descriptionTextareaElement = tempModuleElement.find('.' + config.descriptionTextareaElementClass);
@@ -302,13 +303,16 @@ define([
// init tooltips ----------------------------------------------------------------------------------
let tooltipElements = tempModuleElement.find('[data-toggle="tooltip"]');
tooltipElements.tooltip();
tooltipElements.tooltip({
container: 'body',
placement: 'top'
});
// init system effect popover ---------------------------------------------------------------------
$(moduleElement).find('.' + config.systemInfoEffectClass).addSystemEffectTooltip(systemData.security, systemData.effect);
tempModuleElement.find('.' + config.systemInfoEffectClass).addSystemEffectTooltip(systemData.security, systemData.effect);
// init planets popover ---------------------------------------------------------------------------
$(moduleElement).find('.' + config.systemInfoPlanetsClass).addSystemPlanetsTooltip(systemData.planets);
tempModuleElement.find('.' + config.systemInfoPlanetsClass).addSystemPlanetsTooltip(systemData.planets);
// init static wormhole information ---------------------------------------------------------------
for(let staticData of staticsData){
@@ -316,6 +320,16 @@ define([
staticRowElement.addWormholeInfoTooltip(staticData);
}
// copy system deeplink URL -----------------------------------------------------------------------
tempModuleElement.find('.' + config.urlLinkClass).on('click', function(){
let mapUrl = $(this).attr('data-url');
Util.copyToClipboard(mapUrl).then(payload => {
if(payload.data){
Util.showNotify({title: 'Copied to clipbaord', text: mapUrl, type: 'success'});
}
});
});
// constellation popover --------------------------------------------------------------------------
tempModuleElement.find('a.popup-ajax').popover({
html: true,
@@ -351,6 +365,7 @@ define([
let moduleData = {
system: systemData,
static: staticsData,
moduleHeadlineIconClass: config.moduleHeadlineIconClass,
tableClass: config.systemInfoTableClass,
nameInfoClass: config.systemInfoNameClass,
effectInfoClass: config.systemInfoEffectClass,
@@ -359,6 +374,7 @@ define([
statusInfoClass: config.systemInfoStatusLabelClass,
popoverTriggerClass: Util.config.popoverTriggerClass,
systemUrl: MapUtil.getMapDeeplinkUrl(mapId, systemData.id),
systemTypeName: MapUtil.getSystemTypeInfo(systemData.type.id, 'name'),
systemIsWormhole: MapUtil.getSystemTypeInfo(systemData.type.id, 'name') === 'w-space',
systemStatusId: systemData.status.id,
@@ -389,8 +405,8 @@ define([
systemConstellationLinkClass: config.constellationLinkClass,
systemRegionLinkClass: config.regionLinkClass,
systemTypeLinkClass: config.typeLinkClass
systemTypeLinkClass: config.typeLinkClass,
systemUrlLinkClass: config.urlLinkClass
};
Render.showModule(moduleConfig, moduleData);

View File

@@ -1560,7 +1560,7 @@ define([
if(mapId){
// search for a specific tab element
mapTabElements = mapTabElements.filter(function(i, el){
return ( $(el).data('map-id') === mapId );
return ( $(el).data('mapId') === mapId );
});
}
@@ -2398,6 +2398,100 @@ define([
});
};
/**
* 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);
showNotify({title: 'Clipboard API', text: errorMsg, type: 'error'});
resolve(payload);
});
}else{
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);
showNotify({title: 'Clipboard API', text: errorMsg, type: 'error'});
resolve(payload);
});
}else{
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);
};
/**
* set currentSystemData as "global" variable
* @param systemData
@@ -2786,6 +2880,8 @@ define([
getNearBySystemData: getNearBySystemData,
getNearByCharacterData: getNearByCharacterData,
setDestination: setDestination,
copyToClipboard: copyToClipboard,
readFromClipboard: readFromClipboard,
convertDateToUTC: convertDateToUTC,
convertDateToString: convertDateToString,
getOpenDialogs: getOpenDialogs,

View File

@@ -12,8 +12,6 @@ define([
// all Datatables stuff is available...
let initDefaultDatatablesConfig = () => {
$.extend(true, $.fn.dataTable.defaults, {
pageLength: -1,
pagingType: 'simple_numbers',

View File

@@ -48,7 +48,9 @@ define([
* @param system
*/
$.fn.showRallyPointDialog = (system) => {
let mapData = Util.getCurrentMapData(system.data('mapid'));
let mapId = system.data('mapid');
let systemId = system.data('id');
let mapData = Util.getCurrentMapData(mapId);
requirejs(['text!templates/dialog/system_rally.html', 'mustache'], function(template, Mustache) {
@@ -108,7 +110,8 @@ define([
mailRallyEnabled: Boolean(Util.getObjVal(mapData, 'config.logging.mailRally')),
dialogRallyMessageDefault: config.dialogRallyMessageDefault,
systemId: system.data('id')
systemUrl: MapUtil.getMapDeeplinkUrl(mapId, systemId),
systemId: systemId
};
let content = Mustache.render(template, data);

View File

@@ -570,6 +570,7 @@ define([
/**
* set system visibility e.g. or filtered systems
* @param system
* @param map
* @param visible
*/
let setSystemVisible = (system, map, visible) => {
@@ -1585,12 +1586,13 @@ define([
/**
* get a unique map url for deeplinking
* @param mapId
* @param systemId
* @returns {string}
*/
let getMapDeeplinkUrl = (mapId) => {
let getMapDeeplinkUrl = (mapId, systemId) => {
let url = location.protocol + '//' + location.host + '/map';
url += mapId ? '/' + encodeURIComponent(window.btoa(mapId)) : '';
url += systemId ? '_' + encodeURIComponent(window.btoa(systemId)) : '';
return url;
};

View File

@@ -246,7 +246,7 @@ define([
*/
let showPanel = (parentElement, Module, mapId, data) => {
let moduleElement = Module.getModule(parentElement, mapId, data);
if (moduleElement) {
if(moduleElement) {
// store Module object to DOM element for further access
moduleElement.data('module', Module);
moduleElement.data('data', data);
@@ -265,12 +265,12 @@ define([
// check for stored module order in indexDB (client) ----------------------------------------------
let key = 'modules_cell_' + this.parentElement.attr('data-position');
if (
if(
dataStore &&
dataStore[key]
) {
){
let positionIndex = dataStore[key].indexOf(Module.config.moduleName);
if (positionIndex !== -1) {
if(positionIndex !== -1) {
// first index (0) => is position 1
defaultPosition = positionIndex + 1;
}
@@ -284,13 +284,13 @@ define([
// insert at correct position ---------------------------------------------------------------------
let prevModuleElement = this.parentElement.find('.' + config.moduleClass + ':nth-child(' + position + ')');
if (prevModuleElement.length) {
if(prevModuleElement.length) {
this.moduleElement.insertAfter(prevModuleElement);
} else {
this.parentElement.prepend(this.moduleElement);
}
if (typeof Module.beforeShow === 'function') {
if(typeof Module.beforeShow === 'function') {
Module.beforeShow(this.moduleElement, moduleElement.data('data'));
}
@@ -304,7 +304,7 @@ define([
complete: function (moduleElement) {
moduleElement = $(moduleElement);
let Module = $(moduleElement).data('module');
if (typeof Module.initModule === 'function') {
if(typeof Module.initModule === 'function') {
Module.initModule(moduleElement, mapId, moduleElement.data('data'));
}
@@ -328,7 +328,7 @@ define([
// check if module already exists
let moduleElement = parentElement.find('.' + Module.config.moduleTypeClass);
if (moduleElement.length > 0) {
if(moduleElement.length > 0) {
removeModule(moduleElement, Module, () => {
showPanel(parentElement, Module, mapId, data);
}, true);
@@ -714,7 +714,7 @@ define([
if(mapTabChangeBlocked === false){
let tabLinkElement = $(this);
let mapId = tabLinkElement.data('map-id');
let mapId = tabLinkElement.data('mapId');
// ignore "add" tab. no need for map change
if(mapId > 0){
@@ -741,7 +741,7 @@ define([
// tab switch --------------------------------------------------------------------------------------------
$(tabListElement).on('show.bs.tab', 'a', function(e){
let mapId = $(e.target).data('map-id');
let mapId = $(e.target).data('mapId');
if(mapId > 0){
// save mapId as new "default" (local storage)
@@ -755,7 +755,9 @@ define([
$(tabListElement).on('shown.bs.tab', 'a', function(e){
// load new map right after tab-change
let mapId = $(e.target).data('map-id');
let tabLinkElement = $(e.target);
let mapId = tabLinkElement.data('mapId');
let defaultSystemId = tabLinkElement.data('defaultSystemId');
let tabMapData = Util.getCurrentMapData(mapId);
if(tabMapData !== false){
@@ -773,10 +775,19 @@ define([
let activeSystem = mapElement.find('.' + MapUtil.config.systemActiveClass + ':first');
if(activeSystem.length){
MapUtil.setSystemActive(mapConfig.map, activeSystem);
}else if(defaultSystemId){
// currently no system "active" check if there is a default system set for this mapTab
// -> e.g. from URL link
let systemId = MapUtil.getSystemId(mapConfig.config.id, defaultSystemId);
let system = mapElement.find('#' + systemId);
if(system.length){
// system exists on map -> make active and show panels
MapUtil.showSystemInfo(mapConfig.map, system);
}
}
// change url to unique map URL
if (history.pushState) {
if(history.pushState) {
let mapUrl = MapUtil.getMapDeeplinkUrl(mapConfig.config.id);
history.pushState({}, '', mapUrl);
}
@@ -788,8 +799,8 @@ define([
});
$(tabListElement).on('hide.bs.tab', 'a', function(e){
let newMapId = $(e.relatedTarget).data('map-id');
let oldMapId = $(e.target).data('map-id');
let newMapId = $(e.relatedTarget).data('mapId');
let oldMapId = $(e.target).data('mapId');
// skip "add button"
if(newMapId > 0){
@@ -823,7 +834,7 @@ define([
*/
let updateTabExecutor = (resolve, reject) => {
// set "main" data
tabElement.data('map-id', options.id);
tabElement.data('mapId', options.id);
// add updated timestamp (not available for "add" tab
if(Util.getObjVal(options, 'updated.updated')){
@@ -988,7 +999,7 @@ define([
let key = 'maps_list_' + tabBar.attr('data-position');
if(dataStore && dataStore[key]){
let positionIndex = dataStore[key].indexOf(this.options.id);
if (positionIndex !== -1) {
if(positionIndex !== -1) {
// first index (0) => is position 1
defaultPosition = positionIndex + 1;
}
@@ -1000,7 +1011,7 @@ define([
// insert at correct position -------------------------------------------------------------------------
let prevListElement = tabBar.find('li' + '' + ':nth-child(' + position + ')');
if (prevListElement.length) {
if(prevListElement.length) {
tabListElement.insertAfter(prevListElement);
} else {
tabBar.prepend(tabListElement);
@@ -1085,7 +1096,7 @@ define([
let tabElements = mapModule.getMapTabElements();
for(let i = 0; i < tabElements.length; i++){
let tabElement = $(tabElements[i]);
let mapId = tabElement.data('map-id');
let mapId = tabElement.data('mapId');
if(mapId > 0){
promiseDeleteTab.push(deleteTab(tabMapElement, mapId));
}
@@ -1104,6 +1115,19 @@ define([
return parts.pop() || parts.pop();
};
let getMapDataFromUrl = () => {
let data = [];
let lastURLSegment = getLastUrlSegment();
if(lastURLSegment.length){
try{
data = lastURLSegment.split('_').map(part => parseInt(atob(decodeURIComponent(part))) || 0);
}catch(e){
// data could not be extracted from URL -> ignore
}
}
return data;
};
/**
* set "default" map tab
* -> default mapId might be available in local storage
@@ -1128,17 +1152,15 @@ define([
let activeTabLinkElement = false;
// 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
}
let urlData = getMapDataFromUrl();
let defaultMapId = urlData[0] || 0;
let defaultSystemId = urlData[1] || 0;
if(defaultMapId){
activeTabLinkElement = getActiveTabLinkElement(defaultMapId);
if(defaultSystemId && activeTabLinkElement.length){
activeTabLinkElement.data('defaultSystemId', defaultSystemId);
}
}
// ... else check for existing cached default mapId ---------------------------------------------------
@@ -1218,7 +1240,7 @@ define([
// check whether a tab/map is still active
for(let i = 0; i < tabElements.length; i++){
let tabElement = $(tabElements[i]);
let mapId = tabElement.data('map-id');
let mapId = tabElement.data('mapId');
if(mapId > 0){
let tabMapData = Util.getCurrentMapData(mapId);

View File

@@ -92,99 +92,6 @@ define([
return '<span class="' + config.tableCellUnknownDataClass + '">unknown</span>';
};
/**
* 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
@@ -289,7 +196,7 @@ define([
mapElement.find('.' + config.textActionIconCopyClass).on('click', function(){
let mapUrl = $(this).find('span').text().trim();
copyToClipboard(mapUrl).then(payload => {
Util.copyToClipboard(mapUrl).then(payload => {
if(payload.data){
Util.showNotify({title: 'Copied to clipbaord', text: mapUrl, type: 'success'});
}

View File

@@ -19,10 +19,14 @@ define([
// system info module
moduleTypeClass: 'pf-system-info-module', // class for this module
// headline toolbar
moduleHeadlineIconClass: 'pf-module-icon-button', // class for toolbar icons in the head
// breadcrumb
constellationLinkClass: 'pf-system-info-constellation', // class for "constellation" name
regionLinkClass: 'pf-system-info-region', // class for "region" name
typeLinkClass: 'pf-system-info-type', // class for "type" name
urlLinkClass: 'pf-system-info-url', // class for "url" copy link
// info table
systemInfoTableClass: 'pf-module-table', // class for system info table
@@ -185,13 +189,10 @@ define([
functions: {
after: function(conf){
let tempModuleElement = conf.position;
// lock "description" field until first update
tempModuleElement.find('.' + config.descriptionArea).showLoadingAnimation();
// "add description" button
let descriptionButton = tempModuleElement.find('.' + config.addDescriptionButtonClass);
// description textarea element
let descriptionTextareaElement = tempModuleElement.find('.' + config.descriptionTextareaElementClass);
@@ -302,13 +303,16 @@ define([
// init tooltips ----------------------------------------------------------------------------------
let tooltipElements = tempModuleElement.find('[data-toggle="tooltip"]');
tooltipElements.tooltip();
tooltipElements.tooltip({
container: 'body',
placement: 'top'
});
// init system effect popover ---------------------------------------------------------------------
$(moduleElement).find('.' + config.systemInfoEffectClass).addSystemEffectTooltip(systemData.security, systemData.effect);
tempModuleElement.find('.' + config.systemInfoEffectClass).addSystemEffectTooltip(systemData.security, systemData.effect);
// init planets popover ---------------------------------------------------------------------------
$(moduleElement).find('.' + config.systemInfoPlanetsClass).addSystemPlanetsTooltip(systemData.planets);
tempModuleElement.find('.' + config.systemInfoPlanetsClass).addSystemPlanetsTooltip(systemData.planets);
// init static wormhole information ---------------------------------------------------------------
for(let staticData of staticsData){
@@ -316,6 +320,16 @@ define([
staticRowElement.addWormholeInfoTooltip(staticData);
}
// copy system deeplink URL -----------------------------------------------------------------------
tempModuleElement.find('.' + config.urlLinkClass).on('click', function(){
let mapUrl = $(this).attr('data-url');
Util.copyToClipboard(mapUrl).then(payload => {
if(payload.data){
Util.showNotify({title: 'Copied to clipbaord', text: mapUrl, type: 'success'});
}
});
});
// constellation popover --------------------------------------------------------------------------
tempModuleElement.find('a.popup-ajax').popover({
html: true,
@@ -351,6 +365,7 @@ define([
let moduleData = {
system: systemData,
static: staticsData,
moduleHeadlineIconClass: config.moduleHeadlineIconClass,
tableClass: config.systemInfoTableClass,
nameInfoClass: config.systemInfoNameClass,
effectInfoClass: config.systemInfoEffectClass,
@@ -359,6 +374,7 @@ define([
statusInfoClass: config.systemInfoStatusLabelClass,
popoverTriggerClass: Util.config.popoverTriggerClass,
systemUrl: MapUtil.getMapDeeplinkUrl(mapId, systemData.id),
systemTypeName: MapUtil.getSystemTypeInfo(systemData.type.id, 'name'),
systemIsWormhole: MapUtil.getSystemTypeInfo(systemData.type.id, 'name') === 'w-space',
systemStatusId: systemData.status.id,
@@ -389,8 +405,8 @@ define([
systemConstellationLinkClass: config.constellationLinkClass,
systemRegionLinkClass: config.regionLinkClass,
systemTypeLinkClass: config.typeLinkClass
systemTypeLinkClass: config.typeLinkClass,
systemUrlLinkClass: config.urlLinkClass
};
Render.showModule(moduleConfig, moduleData);

View File

@@ -1560,7 +1560,7 @@ define([
if(mapId){
// search for a specific tab element
mapTabElements = mapTabElements.filter(function(i, el){
return ( $(el).data('map-id') === mapId );
return ( $(el).data('mapId') === mapId );
});
}
@@ -2398,6 +2398,100 @@ define([
});
};
/**
* 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);
showNotify({title: 'Clipboard API', text: errorMsg, type: 'error'});
resolve(payload);
});
}else{
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);
showNotify({title: 'Clipboard API', text: errorMsg, type: 'error'});
resolve(payload);
});
}else{
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);
};
/**
* set currentSystemData as "global" variable
* @param systemData
@@ -2786,6 +2880,8 @@ define([
getNearBySystemData: getNearBySystemData,
getNearByCharacterData: getNearByCharacterData,
setDestination: setDestination,
copyToClipboard: copyToClipboard,
readFromClipboard: readFromClipboard,
convertDateToUTC: convertDateToUTC,
convertDateToString: convertDateToString,
getOpenDialogs: getOpenDialogs,

View File

@@ -32,11 +32,14 @@
</div>
<div class="col-xs-8 col-sm-9">
<div class="form-group">
<div class="form-group" style="margin-bottom: 10px;">
<label for="{{dialogRallyMessageId}}" class="col-sm-2 control-label">Message <span class="txt-color txt-color-grayLight">[optional]</span></label>
<div class="col-sm-10">
<textarea id="{{dialogRallyMessageId}}" name="message" class="form-control" rows="5" placeholder="{{dialogRallyMessageDefault}}"></textarea>
<div class="note help-block with-errors"></div>
<div class="note help-block with-errors">
Attach deeplink:
<a target="_blank" href="{{systemUrl}}" rel="noopener">{{systemUrl}}</a>
</div>
</div>
</div>

View File

@@ -1,5 +1,5 @@
<div class="pf-module-head">
<h5 class="pull-right {{#systemNameClass}}{{system.security}}{{/systemNameClass}}" data-toggle="tooltip" data-placement="top" data-container="body" title="alias">
<h5 class="pull-right {{#systemNameClass}}{{system.security}}{{/systemNameClass}}" data-toggle="tooltip" title="alias">
{{#system.alias}}
{{system.alias}}
{{/system.alias}}
@@ -10,25 +10,26 @@
<h5 class="pf-module-handler-drag"></h5>
<h5><span class="{{systemTypeLinkClass}}" data-toggle="tooltip" data-placement="top" data-container="body" title="type">{{systemTypeName}}</span>&nbsp;<i class="fas fa-fw fa-angle-double-right"></i></h5>
<h5><span class="{{systemRegionLinkClass}} {{#systemNameClass}}{{system.security}}{{/systemNameClass}}" data-toggle="tooltip" data-placement="top" data-container="body" title="region">{{system.region.name}}</span>&nbsp;<i class="fas fa-fw fa-angle-double-right"></i></h5>
<h5><span class="{{systemTypeLinkClass}}" data-toggle="tooltip" title="type">{{systemTypeName}}</span>&nbsp;<i class="fas fa-fw fa-angle-double-right"></i></h5>
<h5><span class="{{systemRegionLinkClass}} {{#systemNameClass}}{{system.security}}{{/systemNameClass}}" data-toggle="tooltip" title="region">{{system.region.name}}</span>&nbsp;<i class="fas fa-fw fa-angle-double-right"></i></h5>
<h5><a href="javascript:void(0);" data-url="{{ajaxConstellationInfoUrl}}/{{system.constellation.id}}" class="{{systemConstellationLinkClass}} popup-ajax {{popoverTriggerClass}} {{#systemNameClass}}{{system.security}}{{/systemNameClass}}" title="constellation">{{system.constellation.name}}</a>&nbsp;<i class="fas fa-fw fa-angle-double-right"></i></h5>
<h5>
<span data-toggle="tooltip" data-placement="top" data-container="body" title="system" class="{{#systemNameClass}}{{system.security}}{{/systemNameClass}}">{{system.name}}</span>
<span data-toggle="tooltip" title="system" class="{{#systemNameClass}}{{system.security}}{{/systemNameClass}}">{{system.name}}</span>
<i class="fas fa-fw fa-copy {{moduleHeadlineIconClass}} {{systemUrlLinkClass}}" data-toggle="tooltip" title="copy link" data-url="{{systemUrl}}"></i>
{{#system.locked}}
<i class="fas fa-fw fa-lock"></i>
<i class="fas fa-fw fa-lock" data-toggle="tooltip" title="locked"></i>
{{/system.locked}}
</h5>
{{#systemIsWormhole}}
<a href="{{#formatUrl}}http://evemaps.dotlan.net/system/{{system.name}}{{/formatUrl}}" class="pf-icon pf-icon-dotlan" data-toggle="tooltip" data-placement="top" data-container="body" title="dotlan" target="_blank" rel="noopener"></a>
<a href="{{#formatUrl}}http://evemaps.dotlan.net/system/{{system.name}}{{/formatUrl}}" class="pf-icon pf-icon-dotlan" data-toggle="tooltip" title="dotlan" target="_blank" rel="noopener"></a>
{{/systemIsWormhole}}
{{^systemIsWormhole}}
<a href="{{#formatUrl}}http://evemaps.dotlan.net/map/{{system.region.name}}/{{system.name}}{{/formatUrl}}" class="pf-icon pf-icon-dotlan" data-toggle="tooltip" data-placement="top" data-container="body" title="dotlan" target="_blank" rel="noopener"></a>
<a href="{{#formatUrl}}http://evemaps.dotlan.net/map/{{system.region.name}}/{{system.name}}{{/formatUrl}}" class="pf-icon pf-icon-dotlan" data-toggle="tooltip" title="dotlan" target="_blank" rel="noopener"></a>
{{/systemIsWormhole}}
{{#systemIsWormhole}}
<a href="{{#formatUrl}}http://anoik.is/systems/{{system.name}}{{/formatUrl}}" class="pf-icon pf-icon-anoik" data-toggle="tooltip" data-placement="top" data-container="body" title="anoik" target="_blank" rel="noopener"></a>
<a href="{{#formatUrl}}http://anoik.is/systems/{{system.name}}{{/formatUrl}}" class="pf-icon pf-icon-anoik" data-toggle="tooltip" title="anoik" target="_blank" rel="noopener"></a>
{{/systemIsWormhole}}
</div>
@@ -37,7 +38,7 @@
{{! info text ================================================================================================ }}
<div class="col-xs-12 col-sm-7">
<div class="pf-dynamic-area pf-system-info-description-area">
<i class="fas fa-fw fa-lg fa-pen pull-right pf-module-icon-button {{descriptionButtonClass}}" data-toggle="tooltip" data-container="body" title="edit description"></i>
<i class="fas fa-fw fa-lg fa-pen pull-right {{moduleHeadlineIconClass}} {{descriptionButtonClass}}" data-toggle="tooltip" title="edit description"></i>
<div class="{{tableToolsActionClass}}">
<a href="#" class="{{descriptionTextareaClass}}"></a>
@@ -48,7 +49,7 @@
{{! info table ================================================================================================ }}
<div class="col-xs-12 col-sm-5">
<span data-toggle="tooltip" data-placement="top" data-container="body" title="status" data-status="{{systemStatusId}}" class="label center-block {{statusInfoClass}} {{systemStatusClass}}">
<span data-toggle="tooltip" title="status" data-status="{{systemStatusId}}" class="label center-block {{statusInfoClass}} {{systemStatusClass}}">
{{systemStatusLabel}}
</span>
@@ -60,7 +61,7 @@
<th>Name</th>
<th class="text-right">
{{#system.shattered}}
<i class="fas fa-fw fa-skull {{shatteredClass}}" data-toggle="tooltip" data-container="body" title="shattered"></i>&nbsp;
<i class="fas fa-fw fa-skull {{shatteredClass}}" data-toggle="tooltip" title="shattered"></i>&nbsp;
{{/system.shattered}}
<span class="pf-help-default {{nameInfoClass}} {{#systemNameClass}}{{system.security}}{{/systemNameClass}}">{{system.name}}</span>
</th>