- fixed "online" status for characters, closed #507
This commit is contained in:
@@ -17,6 +17,7 @@ use lib\Config;
|
||||
class Admin extends Controller{
|
||||
|
||||
const ERROR_SSO_CHARACTER_EXISTS = 'No character found. Please login first.';
|
||||
const ERROR_SSO_CHARACTER_SCOPES = 'Additional ESI scopes are required for "%s". Use the SSO button below.';
|
||||
const ERROR_SSO_CHARACTER_ROLES = 'Insufficient in-game roles. "%s" requires at least one of these corp roles: %s.';
|
||||
|
||||
const LOG_TEXT_KICK_BAN = '%s "%s" from corporation "%s", by "%s"';
|
||||
@@ -86,13 +87,19 @@ class Admin extends Controller{
|
||||
if($character->role != 'MEMBER'){
|
||||
// current character is admin
|
||||
$adminCharacter = $character;
|
||||
}elseif( !$character->hasAdminScopes() ){
|
||||
$f3->set(Sso::SESSION_KEY_SSO_ERROR,
|
||||
sprintf(
|
||||
self::ERROR_SSO_CHARACTER_SCOPES,
|
||||
$character->name
|
||||
));
|
||||
}else{
|
||||
$f3->set(Sso::SESSION_KEY_SSO_ERROR,
|
||||
sprintf(
|
||||
self::ERROR_SSO_CHARACTER_ROLES,
|
||||
$character->name,
|
||||
implode(', ', CorporationModel::ADMIN_ROLES
|
||||
)));
|
||||
implode(', ', CorporationModel::ADMIN_ROLES)
|
||||
));
|
||||
}
|
||||
}else{
|
||||
$f3->set(Sso::SESSION_KEY_SSO_ERROR, self::ERROR_SSO_CHARACTER_EXISTS);
|
||||
@@ -107,9 +114,9 @@ class Admin extends Controller{
|
||||
* @param CharacterModel $character
|
||||
*/
|
||||
protected function setCharacterRole(CharacterModel $character){
|
||||
$character->virtual('role', function($character){
|
||||
$character->virtual('role', function ($character){
|
||||
// default role based on roleId (auto-detected)
|
||||
if( ($role = array_search ($character->roleId, CharacterModel::ROLES)) === false ){
|
||||
if(($role = array_search($character->roleId, CharacterModel::ROLES)) === false){
|
||||
$role = 'MEMBER';
|
||||
}
|
||||
|
||||
@@ -119,9 +126,9 @@ class Admin extends Controller{
|
||||
*/
|
||||
if($this->getF3()->exists('PATHFINDER.ADMIN.CHARACTER', $globalAdminData)){
|
||||
foreach((array)$globalAdminData as $adminData){
|
||||
if($adminData['ID'] === $character->_id){
|
||||
if( CharacterModel::ROLES[$adminData['ROLE']] ){
|
||||
$role = $adminData['ROLE'];
|
||||
if($adminData[ 'ID' ] === $character->_id){
|
||||
if(CharacterModel::ROLES[ $adminData[ 'ROLE' ] ]){
|
||||
$role = $adminData[ 'ROLE' ];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ class Sso extends Api\User{
|
||||
public function requestAdminAuthorization($f3){
|
||||
$f3->set(self::SESSION_KEY_SSO_FROM, 'admin');
|
||||
|
||||
$scopes = $this->getScopesByAuthType('admin');
|
||||
$scopes = self::getScopesByAuthType('admin');
|
||||
$this->rerouteAuthorization($f3, $scopes, 'admin');
|
||||
}
|
||||
|
||||
@@ -105,7 +105,7 @@ class Sso extends Api\User{
|
||||
|
||||
if($loginCheck){
|
||||
// set "login" cookie
|
||||
$this->setLoginCookie($character, $this->generateHashFromScopes($this->getScopesByAuthType()) );
|
||||
$this->setLoginCookie($character);
|
||||
|
||||
// -> pass current character data to target page
|
||||
$f3->set(Api\User::SESSION_KEY_TEMP_CHARACTER_ID, $character->_id);
|
||||
@@ -122,7 +122,7 @@ class Sso extends Api\User{
|
||||
}
|
||||
|
||||
// redirect to CCP SSO ----------------------------------------------------------------------
|
||||
$scopes = $this->getScopesByAuthType();
|
||||
$scopes = self::getScopesByAuthType();
|
||||
$this->rerouteAuthorization($f3, $scopes);
|
||||
}
|
||||
|
||||
@@ -207,9 +207,10 @@ class Sso extends Api\User{
|
||||
|
||||
if( isset($characterData->character) ){
|
||||
// add "ownerHash" and SSO tokens
|
||||
$characterData->character['ownerHash'] = $verificationCharacterData->CharacterOwnerHash;
|
||||
$characterData->character['crestAccessToken'] = $accessData->accessToken;
|
||||
$characterData->character['crestRefreshToken'] = $accessData->refreshToken;
|
||||
$characterData->character['ownerHash'] = $verificationCharacterData->CharacterOwnerHash;
|
||||
$characterData->character['crestAccessToken'] = $accessData->accessToken;
|
||||
$characterData->character['crestRefreshToken'] = $accessData->refreshToken;
|
||||
$characterData->character['esiScopes'] = Lib\Util::convertScopesString($verificationCharacterData->Scopes);
|
||||
|
||||
// add/update static character data
|
||||
$characterModel = $this->updateCharacter($characterData);
|
||||
@@ -255,7 +256,7 @@ class Sso extends Api\User{
|
||||
|
||||
if($loginCheck){
|
||||
// set "login" cookie
|
||||
$this->setLoginCookie($characterModel, $this->generateHashFromScopes( explode(' ', $verificationCharacterData->Scopes) ));
|
||||
$this->setLoginCookie($characterModel);
|
||||
|
||||
// -> pass current character data to target page
|
||||
$f3->set(Api\User::SESSION_KEY_TEMP_CHARACTER_ID, $characterModel->_id);
|
||||
@@ -569,7 +570,9 @@ class Sso extends Api\User{
|
||||
*/
|
||||
$characterModel = Model\BasicModel::getNew('CharacterModel');
|
||||
$characterModel->getById((int)$characterData->character['id'], 0);
|
||||
$characterModel->copyfrom($characterData->character, ['id', 'name', 'ownerHash', 'crestAccessToken', 'crestRefreshToken', 'securityStatus']);
|
||||
$characterModel->copyfrom($characterData->character, [
|
||||
'id', 'name', 'ownerHash', 'crestAccessToken', 'crestRefreshToken', 'esiScopes', 'securityStatus'
|
||||
]);
|
||||
$characterModel->corporationId = $characterData->corporation;
|
||||
$characterModel->allianceId = $characterData->alliance;
|
||||
$characterModel = $characterModel->save();
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace Controller;
|
||||
use Controller\Api as Api;
|
||||
use lib\Config;
|
||||
use lib\Socket;
|
||||
use Lib\Util;
|
||||
use Model;
|
||||
use DB;
|
||||
|
||||
@@ -187,9 +188,8 @@ class Controller {
|
||||
* set/update logged in cookie by character model
|
||||
* -> store validation data in DB
|
||||
* @param Model\CharacterModel $character
|
||||
* @param string $scopeHash
|
||||
*/
|
||||
protected function setLoginCookie(Model\CharacterModel $character, $scopeHash = ''){
|
||||
protected function setLoginCookie(Model\CharacterModel $character){
|
||||
|
||||
if( $this->getCookieState() ){
|
||||
$expireSeconds = (int) $this->getF3()->get('PATHFINDER.LOGIN.COOKIE_EXPIRE');
|
||||
@@ -221,8 +221,7 @@ class Controller {
|
||||
'characterId' => $character,
|
||||
'selector' => $selector,
|
||||
'token' => $token,
|
||||
'expires' => $expireTime->format('Y-m-d H:i:s'),
|
||||
'scopeHash' => $scopeHash
|
||||
'expires' => $expireTime->format('Y-m-d H:i:s')
|
||||
];
|
||||
|
||||
$authenticationModel = $character->rel('characterAuthentications');
|
||||
@@ -276,10 +275,6 @@ class Controller {
|
||||
// "expire data" and "validate token"
|
||||
if( !$characterAuth->dry() ){
|
||||
if(
|
||||
(
|
||||
$characterAuth->scopeHash === $this->generateHashFromScopes($this->getScopesByAuthType()) ||
|
||||
$characterAuth->scopeHash === $this->generateHashFromScopes($this->getScopesByAuthType('admin'))
|
||||
) &&
|
||||
strtotime($characterAuth->expires) >= $currentTime->getTimestamp() &&
|
||||
hash_equals($characterAuth->token, hash('sha256', $data[1]))
|
||||
){
|
||||
@@ -297,20 +292,32 @@ class Controller {
|
||||
$character = $characterAuth->rel('characterId');
|
||||
$character->getById( $characterAuth->get('characterId', true) );
|
||||
|
||||
// check if character still has user (is not the case of "ownerHash" changed
|
||||
// check if character is still authorized to log in (e.g. corp/ally or config has changed
|
||||
// -> do NOT remove cookie on failure. This can be a temporary problem (e.g. ESI is down,..)
|
||||
if( $character->hasUserCharacter() ){
|
||||
$authStatus = $character->isAuthorized();
|
||||
// check ESI scopes
|
||||
$scopeHash = Util::getHashFromScopes($character->esiScopes);
|
||||
|
||||
if(
|
||||
$authStatus == 'OK' ||
|
||||
!$checkAuthorization
|
||||
){
|
||||
$character->virtual( 'authStatus', $authStatus);
|
||||
if(
|
||||
$scopeHash === Util::getHashFromScopes(self::getScopesByAuthType()) ||
|
||||
$scopeHash === Util::getHashFromScopes(self::getScopesByAuthType('admin'))
|
||||
){
|
||||
// check if character still has user (is not the case of "ownerHash" changed
|
||||
// check if character is still authorized to log in (e.g. corp/ally or config has changed
|
||||
// -> do NOT remove cookie on failure. This can be a temporary problem (e.g. ESI is down,..)
|
||||
if( $character->hasUserCharacter() ){
|
||||
$authStatus = $character->isAuthorized();
|
||||
|
||||
if(
|
||||
$authStatus == 'OK' ||
|
||||
!$checkAuthorization
|
||||
){
|
||||
$character->virtual( 'authStatus', $authStatus);
|
||||
}
|
||||
|
||||
$characters[$name] = $character;
|
||||
}
|
||||
|
||||
$characters[$name] = $character;
|
||||
}else{
|
||||
// outdated/invalid ESI scopes
|
||||
$characterAuth->erase();
|
||||
$invalidCookie = true;
|
||||
}
|
||||
}else{
|
||||
$invalidCookie = true;
|
||||
@@ -434,35 +441,6 @@ class Controller {
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* get scope array by a "role"
|
||||
* @param string $authType
|
||||
* @return array
|
||||
*/
|
||||
protected function getScopesByAuthType($authType = ''){
|
||||
$scopes = (array)self::getEnvironmentData('CCP_ESI_SCOPES');
|
||||
|
||||
switch($authType){
|
||||
case 'admin':
|
||||
$scopesAdmin = (array)self::getEnvironmentData('CCP_ESI_SCOPES_ADMIN');
|
||||
$scopes = array_merge($scopes, $scopesAdmin);
|
||||
break;
|
||||
}
|
||||
sort($scopes, SORT_NUMERIC);
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get hash from an array of ESI scopes
|
||||
* @param array $scopes
|
||||
* @return string
|
||||
*/
|
||||
protected function generateHashFromScopes($scopes){
|
||||
$scopes = (array)$scopes;
|
||||
sort($scopes);
|
||||
return md5(serialize( $scopes ));
|
||||
}
|
||||
|
||||
/**
|
||||
* log out current character
|
||||
* @param \Base $f3
|
||||
@@ -715,6 +693,25 @@ class Controller {
|
||||
return $controller;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get scope array by a "role"
|
||||
* @param string $authType
|
||||
* @return array
|
||||
*/
|
||||
static function getScopesByAuthType($authType = ''){
|
||||
$scopes = (array)self::getEnvironmentData('CCP_ESI_SCOPES');
|
||||
|
||||
switch($authType){
|
||||
case 'admin':
|
||||
$scopesAdmin = (array)self::getEnvironmentData('CCP_ESI_SCOPES_ADMIN');
|
||||
$scopes = array_merge($scopes, $scopesAdmin);
|
||||
break;
|
||||
}
|
||||
sort($scopes);
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to return all headers because
|
||||
* getallheaders() is not available under nginx
|
||||
|
||||
@@ -8,7 +8,6 @@
|
||||
|
||||
namespace Lib;
|
||||
|
||||
|
||||
class Util {
|
||||
|
||||
/**
|
||||
@@ -38,4 +37,36 @@ class Util {
|
||||
}, array_keys($arr)), $arr
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* convert a string with multiple scopes into an array
|
||||
* @param string $scopes
|
||||
* @return array|null
|
||||
*/
|
||||
static function convertScopesString($scopes){
|
||||
$scopes = array_filter(
|
||||
array_map('strtolower',
|
||||
(array)explode(' ', $scopes)
|
||||
)
|
||||
);
|
||||
|
||||
if($scopes){
|
||||
sort($scopes);
|
||||
}else{
|
||||
$scopes = null;
|
||||
}
|
||||
|
||||
return $scopes;
|
||||
}
|
||||
|
||||
/**
|
||||
* get hash from an array of ESI scopes
|
||||
* @param array $scopes
|
||||
* @return string
|
||||
*/
|
||||
static function getHashFromScopes($scopes){
|
||||
$scopes = (array)$scopes;
|
||||
sort($scopes);
|
||||
return md5(serialize($scopes));
|
||||
}
|
||||
}
|
||||
@@ -11,6 +11,7 @@ namespace Model;
|
||||
use Controller\Ccp\Sso as Sso;
|
||||
use Controller\Api\User as User;
|
||||
use DB\SQL\Schema;
|
||||
use Lib\Util;
|
||||
|
||||
class CharacterModel extends BasicModel {
|
||||
|
||||
@@ -90,6 +91,9 @@ class CharacterModel extends BasicModel {
|
||||
'crestRefreshToken' => [
|
||||
'type' => Schema::DT_VARCHAR256
|
||||
],
|
||||
'esiScopes' => [
|
||||
'type' => self::DT_JSON
|
||||
],
|
||||
'corporationId' => [
|
||||
'type' => Schema::DT_INT,
|
||||
'index' => true,
|
||||
@@ -611,12 +615,16 @@ class CharacterModel extends BasicModel {
|
||||
*/
|
||||
protected function requestRoles(){
|
||||
$rolesData = [];
|
||||
if( $accessToken = $this->getAccessToken() ){
|
||||
// check if corporation exists (should never fail)
|
||||
if( $corporation = $this->getCorporation() ){
|
||||
$characterRolesData = $corporation->getCharactersRoles($accessToken);
|
||||
if( !empty($characterRolesData[$this->_id]) ){
|
||||
$rolesData = $characterRolesData[$this->_id];
|
||||
|
||||
// check if character has accepted all admin scopes (one of them is required for "role" request)
|
||||
if( $this->hasAdminScopes() ){
|
||||
if( $accessToken = $this->getAccessToken() ){
|
||||
// check if corporation exists (should never fail)
|
||||
if( $corporation = $this->getCorporation() ){
|
||||
$characterRolesData = $corporation->getCharactersRoles($accessToken);
|
||||
if( !empty($characterRolesData[$this->_id]) ){
|
||||
$rolesData = $characterRolesData[$this->_id];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -624,11 +632,19 @@ class CharacterModel extends BasicModel {
|
||||
return $rolesData;
|
||||
}
|
||||
|
||||
/**
|
||||
* check whether this char has accepted all admin api scopes
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAdminScopes(){
|
||||
return empty( array_diff(Sso::getScopesByAuthType('admin'), $this->esiScopes) );
|
||||
}
|
||||
|
||||
/**
|
||||
* update character log (active system, ...)
|
||||
* -> API request for character log data
|
||||
* @param array $additionalOptions (optional) request options for cURL request
|
||||
* @return $this
|
||||
* @return CharacterModel
|
||||
*/
|
||||
public function updateLog($additionalOptions = []){
|
||||
$deleteLog = false;
|
||||
@@ -806,8 +822,9 @@ class CharacterModel extends BasicModel {
|
||||
$characterData = $ssoController->getCharacterData($this->_id);
|
||||
if( !empty($characterData->character) ){
|
||||
$characterData->character['ownerHash'] = $verificationCharacterData->CharacterOwnerHash;
|
||||
$characterData->character['esiScopes'] = Util::convertScopesString($verificationCharacterData->Scopes);
|
||||
|
||||
$this->copyfrom($characterData->character, ['ownerHash', 'securityStatus']);
|
||||
$this->copyfrom($characterData->character, ['ownerHash', 'esiScopes', 'securityStatus']);
|
||||
$this->corporationId = $characterData->corporation;
|
||||
$this->allianceId = $characterData->alliance;
|
||||
$this->save();
|
||||
|
||||
@@ -12,7 +12,7 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var config = {
|
||||
let config = {
|
||||
title: '',
|
||||
text: '',
|
||||
type: '', // 'info', 'success', error, 'warning'
|
||||
@@ -38,13 +38,13 @@ define([
|
||||
};
|
||||
|
||||
// initial page title (cached)
|
||||
var initialPageTitle = document.title;
|
||||
let initialPageTitle = document.title;
|
||||
|
||||
// global blink timeout cache
|
||||
var blinkTimer;
|
||||
let blinkTimer;
|
||||
|
||||
// stack container for all notifications
|
||||
var stack = {
|
||||
let stack = {
|
||||
bottomRight: {
|
||||
stack: {
|
||||
dir1: 'up',
|
||||
@@ -76,7 +76,7 @@ define([
|
||||
* @param customConfig
|
||||
* @param settings
|
||||
*/
|
||||
var showNotify = function(customConfig, settings){
|
||||
let showNotify = function(customConfig, settings){
|
||||
|
||||
customConfig = $.extend(true, {}, config, customConfig );
|
||||
|
||||
@@ -140,13 +140,13 @@ define([
|
||||
* change document.title and make the browsers tab blink
|
||||
* @param blinkTitle
|
||||
*/
|
||||
var startTabBlink = function(blinkTitle){
|
||||
var initBlink = (function(blinkTitle){
|
||||
let startTabBlink = function(blinkTitle){
|
||||
let initBlink = (function(blinkTitle){
|
||||
|
||||
// count blinks if tab is currently active
|
||||
var activeTabBlinkCount = 0;
|
||||
let activeTabBlinkCount = 0;
|
||||
|
||||
var blink = function(){
|
||||
let blink = function(){
|
||||
// number of "blinks" should be limited if tab is currently active
|
||||
if(window.isVisible){
|
||||
activeTabBlinkCount++;
|
||||
@@ -173,7 +173,7 @@ define([
|
||||
/**
|
||||
* stop blinking document.title
|
||||
*/
|
||||
var stopTabBlink = function(){
|
||||
let stopTabBlink = function(){
|
||||
if(blinkTimer){
|
||||
clearInterval(blinkTimer);
|
||||
document.title = initialPageTitle;
|
||||
|
||||
@@ -1005,7 +1005,7 @@ define([
|
||||
let initTabChangeObserver = function(){
|
||||
|
||||
// increase the timer if a user is inactive
|
||||
let increaseTimer = 10000;
|
||||
let increaseTimer = 5000;
|
||||
|
||||
// timer keys
|
||||
let mapUpdateKey = 'UPDATE_SERVER_MAP';
|
||||
|
||||
@@ -581,8 +581,9 @@ define([
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
let easeEffect = $(this).attr('data-easein');
|
||||
let popoverData = $(this).data('bs.popover');
|
||||
let button = $(this);
|
||||
let easeEffect = button.attr('data-easein');
|
||||
let popoverData = button.data('bs.popover');
|
||||
let popoverElement = null;
|
||||
|
||||
let velocityOptions = {
|
||||
@@ -591,8 +592,16 @@ define([
|
||||
|
||||
if(popoverData === undefined){
|
||||
|
||||
button.on('shown.bs.popover', function (e) {
|
||||
let tmpPopupElement = $(this).data('bs.popover').tip();
|
||||
tmpPopupElement.find('.btn').on('click', function(e){
|
||||
// close popover
|
||||
$('body').click();
|
||||
});
|
||||
});
|
||||
|
||||
// init popover and add specific class to it (for styling)
|
||||
$(this).popover({
|
||||
button.popover({
|
||||
html: true,
|
||||
title: 'select character',
|
||||
trigger: 'manual',
|
||||
@@ -602,17 +611,17 @@ define([
|
||||
animation: false
|
||||
}).data('bs.popover').tip().addClass('pf-popover');
|
||||
|
||||
$(this).popover('show');
|
||||
button.popover('show');
|
||||
|
||||
popoverElement = $(this).data('bs.popover').tip();
|
||||
popoverElement = button.data('bs.popover').tip();
|
||||
popoverElement.velocity('transition.' + easeEffect, velocityOptions);
|
||||
popoverElement.initTooltips();
|
||||
}else{
|
||||
popoverElement = $(this).data('bs.popover').tip();
|
||||
popoverElement = button.data('bs.popover').tip();
|
||||
if(popoverElement.is(':visible')){
|
||||
popoverElement.velocity('reverse');
|
||||
}else{
|
||||
$(this).popover('show');
|
||||
button.popover('show');
|
||||
popoverElement.initTooltips();
|
||||
popoverElement.velocity('transition.' + easeEffect, velocityOptions);
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ define([
|
||||
|
||||
'use strict';
|
||||
|
||||
var config = {
|
||||
let config = {
|
||||
title: '',
|
||||
text: '',
|
||||
type: '', // 'info', 'success', error, 'warning'
|
||||
@@ -38,13 +38,13 @@ define([
|
||||
};
|
||||
|
||||
// initial page title (cached)
|
||||
var initialPageTitle = document.title;
|
||||
let initialPageTitle = document.title;
|
||||
|
||||
// global blink timeout cache
|
||||
var blinkTimer;
|
||||
let blinkTimer;
|
||||
|
||||
// stack container for all notifications
|
||||
var stack = {
|
||||
let stack = {
|
||||
bottomRight: {
|
||||
stack: {
|
||||
dir1: 'up',
|
||||
@@ -76,7 +76,7 @@ define([
|
||||
* @param customConfig
|
||||
* @param settings
|
||||
*/
|
||||
var showNotify = function(customConfig, settings){
|
||||
let showNotify = function(customConfig, settings){
|
||||
|
||||
customConfig = $.extend(true, {}, config, customConfig );
|
||||
|
||||
@@ -140,13 +140,13 @@ define([
|
||||
* change document.title and make the browsers tab blink
|
||||
* @param blinkTitle
|
||||
*/
|
||||
var startTabBlink = function(blinkTitle){
|
||||
var initBlink = (function(blinkTitle){
|
||||
let startTabBlink = function(blinkTitle){
|
||||
let initBlink = (function(blinkTitle){
|
||||
|
||||
// count blinks if tab is currently active
|
||||
var activeTabBlinkCount = 0;
|
||||
let activeTabBlinkCount = 0;
|
||||
|
||||
var blink = function(){
|
||||
let blink = function(){
|
||||
// number of "blinks" should be limited if tab is currently active
|
||||
if(window.isVisible){
|
||||
activeTabBlinkCount++;
|
||||
@@ -173,7 +173,7 @@ define([
|
||||
/**
|
||||
* stop blinking document.title
|
||||
*/
|
||||
var stopTabBlink = function(){
|
||||
let stopTabBlink = function(){
|
||||
if(blinkTimer){
|
||||
clearInterval(blinkTimer);
|
||||
document.title = initialPageTitle;
|
||||
|
||||
@@ -1005,7 +1005,7 @@ define([
|
||||
let initTabChangeObserver = function(){
|
||||
|
||||
// increase the timer if a user is inactive
|
||||
let increaseTimer = 10000;
|
||||
let increaseTimer = 5000;
|
||||
|
||||
// timer keys
|
||||
let mapUpdateKey = 'UPDATE_SERVER_MAP';
|
||||
|
||||
@@ -581,8 +581,9 @@ define([
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
||||
let easeEffect = $(this).attr('data-easein');
|
||||
let popoverData = $(this).data('bs.popover');
|
||||
let button = $(this);
|
||||
let easeEffect = button.attr('data-easein');
|
||||
let popoverData = button.data('bs.popover');
|
||||
let popoverElement = null;
|
||||
|
||||
let velocityOptions = {
|
||||
@@ -591,8 +592,16 @@ define([
|
||||
|
||||
if(popoverData === undefined){
|
||||
|
||||
button.on('shown.bs.popover', function (e) {
|
||||
let tmpPopupElement = $(this).data('bs.popover').tip();
|
||||
tmpPopupElement.find('.btn').on('click', function(e){
|
||||
// close popover
|
||||
$('body').click();
|
||||
});
|
||||
});
|
||||
|
||||
// init popover and add specific class to it (for styling)
|
||||
$(this).popover({
|
||||
button.popover({
|
||||
html: true,
|
||||
title: 'select character',
|
||||
trigger: 'manual',
|
||||
@@ -602,17 +611,17 @@ define([
|
||||
animation: false
|
||||
}).data('bs.popover').tip().addClass('pf-popover');
|
||||
|
||||
$(this).popover('show');
|
||||
button.popover('show');
|
||||
|
||||
popoverElement = $(this).data('bs.popover').tip();
|
||||
popoverElement = button.data('bs.popover').tip();
|
||||
popoverElement.velocity('transition.' + easeEffect, velocityOptions);
|
||||
popoverElement.initTooltips();
|
||||
}else{
|
||||
popoverElement = $(this).data('bs.popover').tip();
|
||||
popoverElement = button.data('bs.popover').tip();
|
||||
if(popoverElement.is(':visible')){
|
||||
popoverElement.velocity('reverse');
|
||||
}else{
|
||||
$(this).popover('show');
|
||||
button.popover('show');
|
||||
popoverElement.initTooltips();
|
||||
popoverElement.velocity('transition.' + easeEffect, velocityOptions);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user