Created
September 24, 2014 05:02
-
-
Save lacostej/1945c375ca2d3ae9629f to your computer and use it in GitHub Desktop.
Beautified GameAnalytics.com Angular JS client side (v 1411390919231). From https://go.gameanalytics.com/static/ga-app/scripts/1411390919231.app.js
This file has been truncated, but you can view the full file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
"use strict"; | |
angular.module("ga.app", ["ngCookies", "ngRoute", "ngAnimate", "ngSanitize", "ngTouch", "swipe", "ui.router", "pasvaz.bindonce", "ga.app.routes.admin", "ga.app.routes.studio", "ga.app.routes.game", "ga.app.routes.user", "ga.app.routes.public", "ga.app.routes.error", "ga.app.partials.toolHeader", "ga.app.springboard", "ga.app.footer", "ga.services.user", "ga.services.tracking", "ga.services.pardot", "ga.services.announcement", "ga.pages.templates", "ga.pages.content", "ga.app.headerContent", "ga.components.rollbar", "ga.utils.tracking", "ga.cache-buster", "ga.api.statuspage", "ga.ui.tour", "ga.ui.notify", "ga.ui.modal", "ga.config", "ga.services.user"]).config(function($locationProvider, $stateProvider, $urlRouterProvider, $provide, $httpProvider) { | |
var SILENT_USER_RESOLVE = function($q, gaServicesUser) { | |
return gaServicesUser.resolveUser().catch(function() { | |
return $q.when(null) | |
}) | |
}; | |
$provide.decorator("$exceptionHandler", function($delegate, $injector, gaComponentsRollbar) { | |
return function(exception, cause) { | |
$delegate(exception, cause), gaComponentsRollbar.put(exception), $injector.invoke(["gaServicesTracking", | |
function(gaServicesTracking) { | |
gaServicesTracking.submitEvent("error", null, { | |
severity: "error", | |
message: exception.stack | |
}) | |
} | |
]) | |
} | |
}), window.location.host.match("guides.*?") ? $stateProvider.state("root", { | |
url: "/", | |
resolve: { | |
redirect: function($timeout, $state) { | |
return $timeout(function() { | |
$state.go("content.section", { | |
section: "sdk" | |
}, { | |
location: "replace" | |
}) | |
}), !1 | |
} | |
} | |
}) : $stateProvider.state("root", { | |
url: "/", | |
resolve: { | |
user: SILENT_USER_RESOLVE, | |
redirect: function(user, $timeout, $state) { | |
return user ? ($state.go("user.home", {}, { | |
location: "replace" | |
}), !1) : ($state.go("public.login", {}, { | |
location: "replace" | |
}), !1) | |
} | |
} | |
}), $stateProvider.state("templates", { | |
url: "/templates", | |
resolve: { | |
user: SILENT_USER_RESOLVE | |
}, | |
views: { | |
main: { | |
templateUrl: "/static/ga-app/modules/pages/templates/templates.html", | |
controller: "gaPagesTemplatesController" | |
}, | |
header: { | |
template: "" | |
}, | |
footer: { | |
template: "" | |
} | |
} | |
}), $stateProvider.state("templates.show", { | |
url: "/:category/:item" | |
}), $stateProvider.state("content", { | |
url: "/content", | |
resolve: { | |
user: SILENT_USER_RESOLVE | |
}, | |
views: { | |
main: { | |
templateUrl: "/static/ga-app/modules/pages/content/content.html", | |
controller: "gaPagesContentController" | |
}, | |
header: { | |
templateUrl: "/static/ga-app/modules/app/partials/public/header-content.html", | |
controller: "gaAppHeaderContentController" | |
}, | |
footer: { | |
template: "" | |
} | |
} | |
}), $stateProvider.state("content.section", { | |
url: "/:section?page&step" | |
}), $locationProvider.html5Mode(!0); | |
var interceptor = function($q, $injector, $window, gaConfig) { | |
var responseError = function(response) { | |
var redirect, isUserApi; | |
switch (response.status) { | |
case 401: | |
redirect = "login", response.config.url.match("v1/user/data") && (redirect = !1), isUserApi = !!response.config.url.match(new RegExp("(^/|" + gaConfig.userApi.baseUrl + ")")), isUserApi || (redirect = !1), redirect && $injector.get("$state").go("public.login", null, { | |
inherit: !1 | |
}); | |
break; | |
case 403: | |
redirect = !0, isUserApi = !!response.config.url.match(new RegExp("(^/|" + gaConfig.userApi.baseUrl + ")")), isUserApi || (redirect = !1), $window.location.href = "/home"; | |
break; | |
case 500: | |
response.data = { | |
results: [], | |
errors: [{ | |
msg: "Internal server error", | |
type: "internalServerError" | |
}] | |
}; | |
break; | |
case 0: | |
response = { | |
data: { | |
error: "cancel" | |
}, | |
status: 0 | |
} | |
} | |
return $q.reject(response) | |
}; | |
return { | |
responseError: responseError | |
} | |
}; | |
$httpProvider.interceptors.push(interceptor) | |
}).run(function($rootScope, $window, $timeout, $state, gaUtilsTracking, gaApiStatuspage, gaServicesTracking, gaUiTour, gaUiNotify, gaServicesPardot, gaServicesUser, gaServicesAnnouncement, gaUiModal) { | |
$timeout(gaApiStatuspage.updateStatus.bind(gaApiStatuspage), 500), $rootScope.$on("$stateChangeStart", function() { | |
gaUiNotify.loading(!0) | |
}), $rootScope.$on("$stateChangeSuccess", function(event, to, toParams, from, fromParams) { | |
return gaServicesTracking.init(), gaUiTour.stop(), $rootScope.$broadcast("killTour"), gaUiModal.hideAll(), $state.current.data && $state.current.data.alias ? void $state.go($state.current.data.alias, {}, { | |
location: "replace" | |
}) : (toParams.alert && (gaUiNotify.show(toParams.alert, 5e3, "default"), $timeout($state.go.bind($state, $state.$current.self.name, { | |
alert: null | |
}, { | |
notify: !1 | |
}))), gaUtilsTracking.trackPage(from, fromParams), gaServicesTracking.trackState(), $state.includes("public.login") || $state.includes("public.signup") ? gaServicesPardot.trackPage("loginSignup") : $state.includes("public.create-account") && null !== $state.params.invite && gaServicesPardot.trackPage("invited"), gaServicesUser.token && $state.includes("game") && gaServicesUser.game(parseInt($state.params.gameId, 10)) && gaServicesUser.game(parseInt($state.params.gameId, 10)).demo ? gaServicesAnnouncement.add({ | |
id: "demo-game", | |
style: "yellow", | |
icon: "ga-icon-severity-error", | |
content: "<strong>DEMO GAME</strong> - Please be aware that the changes you make will not be saved and certain features have been disabled. Have fun!", | |
replace: !1, | |
close: !1 | |
}) : gaServicesAnnouncement.hide("demo-game"), gaUiNotify.loading(!1), void(gaServicesUser.token && $state.params.gameId && gaServicesAnnouncement.add({ | |
id: "release-2014-08-06", | |
style: "light-blue", | |
icon: "ga-icon-logo", | |
content: 'Brand new Funnels: Completely rebuilt with greater possibilities to slice your data the way you want it – <a href="/game/' + $state.params.gameId + '/funnel" class="hide-me">Learn more</a>.', | |
replace: !1, | |
close: !0, | |
cookie: !0 | |
}))) | |
}) | |
}), angular.module("ga.config", []).value("gaConfig", { | |
getUrlInc: {}, | |
getUrl: function(batch, realtime, funnels) { | |
var type = realtime ? "realtime" : "regular", | |
servers = "realtime" === type ? this.data.operationsBaseDomain : this.data.baseDomain; | |
"object" != typeof servers && (servers = [servers]), this.getUrlInc[type] = ++this.getUrlInc[type] || 0, this.getUrlInc[type] > servers.length - 1 && (this.getUrlInc[type] = 0); | |
var baseUrl = servers[this.getUrlInc[type]] + (batch ? this.data.batchPath : funnels ? this.data.funnelPath : this.data.basePath); | |
return baseUrl | |
}, | |
data: { | |
baseDomain: ["https://query-0.gameanalytics.com", "https://query-1.gameanalytics.com", "https://query-2.gameanalytics.com", "https://query-3.gameanalytics.com"], | |
operationsBaseDomain: ["https://ops-query-0.gameanalytics.com", "https://ops-query-1.gameanalytics.com", "https://ops-query-2.gameanalytics.com", "https://ops-query-3.gameanalytics.com"], | |
basePath: "/v1/games/", | |
batchPath: "/v1/batch/", | |
funnelPath: "/v2/games/" | |
}, | |
baseUrl: window.location.protocol + "//" + window.location.host + "/", | |
userApi: { | |
baseUrl: window.location.protocol + "//" + window.location.host + "/v1/" | |
}, | |
images: { | |
baseUrl: "https://s3.amazonaws.com/images.gameanalytics.com/" | |
}, | |
cache: { | |
type: "angular", | |
id: "ga", | |
expire: 3e5 | |
}, | |
cacheBuster: function() { | |
return "1411390919231" | |
}, | |
demoGame: { | |
id: 6788, | |
token: "priv-eyJhbGciOiAiSFMyNTYiLCAidHlwIjogIkpXVCJ9.eyJ0b2tlbiI6ICJleUpoYkdjaU9pQWlTRk15TlRZaUxDQWlkSGx3SWpvZ0lrcFhWQ0o5LmV5SmxlSEFpT2lBeE16azBOekEzTXpBM2ZRLk9VQnZnbmN4blB1NDAwWDBhcVpFT2RvREk2NWpFUmZVbXlRSVhESHNGNFkifQ.LMfTob9YZm71Z3B2PKBjtDJysxOUN4ddEuEt5E8mhVk" | |
}, | |
gaPlatform: "production", | |
gaKey: "WXpnNU9ERmhOVEk1TlRCbE56STRPVEUwTldZNFlXSmhabUV3WVRoaU4yUT0=", | |
gaSecret: "TnpjMk56SmpOR05pWkRrM1pEbGpPRFl4TjJGaE9UazRNak14TW1SalpEbGtaVEF6WWpZeU5nPT0=" | |
}), angular.module("ga.app.routes.studio", ["ui.router", "ga.app.mainMenu", "ga.services.user", "ga.pages.studio.settings.information", "ga.pages.studio.settings.users", "ga.pages.studio.settings.games", "ga.pages.user.subscriptions"]).config(function($stateProvider) { | |
var USER_RESOLVE = function($q, $state, gaServicesUser) { | |
return gaServicesUser.resolveUser().catch($state.go.bind($state, "public.login", null, { | |
inherit: !1, | |
replace: !0 | |
})) | |
}; | |
$stateProvider.state("studio", { | |
"abstract": !0, | |
url: "/studio/:studioId?alert", | |
resolve: { | |
userResolve: USER_RESOLVE | |
}, | |
views: { | |
main: { | |
template: '<div style="margin-left: 80px;" ui-view></div>' | |
}, | |
header: { | |
templateUrl: "/static/ga-app/modules/app/partials/menu/menu.html", | |
controller: "gaAppMainMenuController" | |
}, | |
footer: { | |
template: "" | |
} | |
} | |
}), $stateProvider.state("studio.settings", { | |
url: "/settings", | |
templateUrl: "/static/ga-app/modules/pages/general/tabbed/tabbed.html", | |
controller: "gaPagesGeneralTabbedController", | |
data: { | |
tabs: [{ | |
title: "Studio information", | |
state: "studio.settings.information" | |
}, { | |
title: "Users", | |
state: "studio.settings.users" | |
}, { | |
title: "Games", | |
state: "studio.settings.games" | |
}] | |
} | |
}), $stateProvider.state("studio.settings.information", { | |
url: "/information", | |
templateUrl: "/static/ga-app/modules/pages/studio/settings/information/information.html", | |
controller: "gaPagesStudioSettingsInformationController" | |
}), $stateProvider.state("studio.settings.users", { | |
url: "/users", | |
templateUrl: "/static/ga-app/modules/pages/studio/settings/users/users.html", | |
controller: "gaPagesStudioSettingsUsersController" | |
}), $stateProvider.state("studio.settings.games", { | |
url: "/games", | |
templateUrl: "/static/ga-app/modules/pages/studio/settings/games/games.html", | |
controller: "gaPagesStudioSettingsGamesController" | |
}) | |
}), angular.module("ga.app.routes.game", ["ga.app.mainMenu", "ui.router", "ga.services.user", "ga.api.userDb.authenticated.heatmap", "ga.pages.dashboards", "ga.pages.explore2", "ga.pages.explore", "ga.pages.heatmap", "ga.pages.cohorts", "ga.pages.game.funnel.list", "ga.pages.game.funnel.view", "ga.pages.game.funnel.edit", "ga.pages.querybuilder", "ga.pages.game.initialize", "ga.pages.querytester", "ga.pages.game.settings.information", "ga.pages.game.settings.users", "ga.pages.game.settings.emailReports", "ga.pages.game.settings.services", "ga.pages.game.settings.exportData", "ga.pages.amt"]).config(function($stateProvider) { | |
var SILENT_USER_RESOLVE = function($q, gaServicesUser) { | |
return gaServicesUser.resolveUser().catch(function() { | |
return $q.when(null) | |
}) | |
}, | |
DASHBOARDS_RESOLVE = function(gameResolve, $q, $timeout, $stateParams, $state, gaServicesUser, gaApiUserDbAuthenticatedDashboards) { | |
return gaApiUserDbAuthenticatedDashboards.getDashboards($stateParams.gameId).catch(function() { | |
return $state.go("user.home", null, { | |
inherit: !1, | |
location: "replace" | |
}), $q.reject() | |
}).then(function() { | |
return gaApiUserDbAuthenticatedDashboards.resolve($stateParams).catch(function(newParams) { | |
return $state.go("game.dashboards.dashboard", newParams, { | |
location: "replace" | |
}), $q.reject() | |
}) | |
}) | |
}, | |
GAME_RESOLVE = function(user, $q, $state, $stateParams, $window, gaServicesUser, gaUtilsCache) { | |
if (user) { | |
var game = gaServicesUser.game(parseInt($stateParams.gameId || 0, 10)); | |
return game ? $q.when() : ($state.go("user.home"), $q.reject("rejected")) | |
} | |
var path = $window.location.href.replace($window.location.origin, ""); | |
return gaUtilsCache.put("goToOnNextLogin", path, "localStorage", 3e5), $state.go("public.login", null, { | |
inherit: !1 | |
}), $q.reject() | |
}, | |
GAME_SETTINGS_RESOLVE = function($stateParams, $timeout, $q, $state, gameResolve, gaServicesUser) { | |
var gameId = parseInt($stateParams.gameId || 0, 10), | |
game = gaServicesUser.game(gameId); | |
if (game) { | |
var adminStatus = game.admin; | |
if (adminStatus === !1) return $timeout(function() { | |
$state.go("game.settingsview", { | |
gameId: gameId | |
}) | |
}), $q.reject() | |
} | |
}, | |
AUTH_HEATMAP = function(gameResolve, gaApiUserDbAuthenticatedHeatmap, $stateParams) { | |
return gaApiUserDbAuthenticatedHeatmap.authHeatmap($stateParams.gameId, $stateParams.firsttime) | |
}, | |
GAME_STATUS = function(gameResolve, $stateParams, gaServicesGame) { | |
return gaServicesGame.getStatus($stateParams.gameId, !0) | |
}; | |
$stateProvider.state("game", { | |
resolve: { | |
user: SILENT_USER_RESOLVE, | |
gameResolve: GAME_RESOLVE | |
}, | |
url: "/game/:gameId?alert", | |
"abstract": !0, | |
views: { | |
main: { | |
template: '<div class="ga wrapper tool" ui-view></div>' | |
}, | |
header: { | |
templateUrl: "/static/ga-app/modules/app/partials/menu/menu.html", | |
controller: "gaAppMainMenuController" | |
}, | |
footer: { | |
template: "" | |
} | |
} | |
}), $stateProvider.state("game.content", { | |
"abstract": !0, | |
url: "/content", | |
templateUrl: "/static/ga-app/modules/pages/content/content.html", | |
controller: "gaPagesContentController" | |
}), $stateProvider.state("game.content.section", { | |
url: "/:section?page&step" | |
}), $stateProvider.state("game.settings", { | |
resolve: { | |
resolveGameSettings: GAME_SETTINGS_RESOLVE | |
}, | |
url: "/settings", | |
templateUrl: "/static/ga-app/modules/pages/general/tabbed/tabbed.html", | |
controller: "gaPagesGeneralTabbedController", | |
data: { | |
tabs: [{ | |
title: "Game information", | |
state: "game.settings.information" | |
}, { | |
title: "Users", | |
state: "game.settings.users" | |
}, { | |
title: "Email reports", | |
state: "game.settings.emailReports" | |
}, { | |
title: "Services", | |
state: "game.settings.services" | |
}, { | |
title: "Export data", | |
state: "game.settings.exportData" | |
}] | |
} | |
}), $stateProvider.state("game.settingsview", { | |
url: "/settings/view", | |
templateUrl: "/static/ga-app/modules/pages/general/tabbed/tabbed.html", | |
controller: "gaPagesGeneralTabbedController", | |
data: { | |
tabs: [{ | |
title: "Game information", | |
state: "game.settingsview.information" | |
}] | |
} | |
}), $stateProvider.state("game.settings.emailReports", { | |
url: "/email-reports", | |
templateUrl: "/static/ga-app/modules/pages/game/settings/email-reports/email-reports.html", | |
controller: "gaPagesGameSettingsEmailReportsController" | |
}), $stateProvider.state("game.settings.exportData", { | |
url: "/export-data", | |
templateUrl: "/static/ga-app/modules/pages/game/settings/export-data/export-data.html", | |
controller: "gaPagesGameSettingsExportDataController" | |
}), $stateProvider.state("game.settings.information", { | |
url: "/information", | |
templateUrl: "/static/ga-app/modules/pages/game/settings/information/information.html", | |
controller: "gaPagesGameSettingsInformationController" | |
}), $stateProvider.state("game.settingsview.information", { | |
url: "/information", | |
templateUrl: "/static/ga-app/modules/pages/game/settings/information/information.html", | |
controller: "gaPagesGameSettingsInformationController", | |
data: { | |
showViewOnly: !0 | |
} | |
}), $stateProvider.state("game.settings.users", { | |
url: "/users", | |
templateUrl: "/static/ga-app/modules/pages/game/settings/users/users.html", | |
controller: "gaPagesGameSettingsUsersController" | |
}), $stateProvider.state("game.settings.services", { | |
url: "/services?pop", | |
templateUrl: "/static/ga-app/modules/pages/game/settings/services/services.html", | |
controller: "gaPagesGameSettingsServicesController" | |
}), $stateProvider.state("game.initialize", { | |
url: "/initialize?skip", | |
resolve: { | |
resolveGameStatus: GAME_STATUS | |
}, | |
templateUrl: "/static/ga-app/modules/pages/game/initialize/initialize.html", | |
controller: "gaPagesGameInitializeController" | |
}), $stateProvider.state("game.explore", { | |
url: "/explore", | |
templateUrl: "/static/ga-app/modules/pages/game/explore/explore.html", | |
controller: "gaPagesExploreController" | |
}), $stateProvider.state("game.heatmap", { | |
resolve: { | |
resolveHeatmap: AUTH_HEATMAP | |
}, | |
url: "/heatmap?firsttime", | |
templateUrl: "/static/ga-app/modules/pages/game/heatmap/heatmap.html", | |
controller: "gaPagesHeatmapController" | |
}), $stateProvider.state("game.heatmap-firsttime", { | |
url: "/heatmap/firsttime", | |
templateUrl: "/static/ga-app/modules/pages/game/heatmap/heatmap-firsttime.html", | |
controller: "gaPagesHeatmapFirstTimeController" | |
}), $stateProvider.state("game.heatmap-nodata", { | |
url: "/heatmap/nodata", | |
templateUrl: "/static/ga-app/modules/pages/game/heatmap/heatmap-nodata.html", | |
controller: "gaPagesHeatmapNodataController" | |
}), $stateProvider.state("game.funnel", { | |
"abstract": !0, | |
template: "<ui-view />" | |
}), $stateProvider.state("game.funnel.list", { | |
url: "/funnel?reload", | |
templateUrl: "/static/ga-app/modules/pages/game/funnel/list/funnel-list.html", | |
controller: "gaPagesFunnelListController" | |
}), $stateProvider.state("game.funnel.list-safe", { | |
url: "/funnel/", | |
templateUrl: "/static/ga-app/modules/pages/game/funnel/list/funnel-list.html", | |
controller: "gaPagesFunnelListController" | |
}), $stateProvider.state("game.funnel.view-backend", { | |
url: "/funnel/:funnelId", | |
templateUrl: "/static/ga-app/modules/pages/game/funnel/view/funnel-view.html", | |
controller: "gaPagesFunnelViewController" | |
}), $stateProvider.state("game.funnel.edit", { | |
url: "/funnel/:funnelId/edit", | |
templateUrl: "/static/ga-app/modules/pages/game/funnel/edit/funnel-edit.html", | |
controller: "gaPagesFunnelEditController" | |
}), $stateProvider.state("game.funnel.view", { | |
url: "/funnel/:funnelId/:dateRangeId", | |
templateUrl: "/static/ga-app/modules/pages/game/funnel/view/funnel-view.html", | |
controller: "gaPagesFunnelViewController" | |
}), $stateProvider.state("game.cohort", { | |
url: "/cohort", | |
templateUrl: "/static/ga-app/modules/pages/game/cohorts/cohorts.html", | |
controller: "gaPagesCohortsController" | |
}), $stateProvider.state("game.querytester", { | |
url: "/querytester?state", | |
templateUrl: "/static/ga-app/modules/pages/game/querytester/querytester.html", | |
controller: "gaPagesQuerytesterController" | |
}), $stateProvider.state("game.querybuilder", { | |
url: "/querybuilder", | |
templateUrl: "/static/ga-app/modules/pages/game/querybuilder/querybuilder.html", | |
controller: "gaPagesQuerybuilderController" | |
}), $stateProvider.state("game.amt", { | |
url: "/amt", | |
templateUrl: "/static/ga-app/modules/pages/game/amt/amt.html", | |
controller: "gaPagesAmtController" | |
}), $stateProvider.state("game.mock", { | |
url: "/mock", | |
templateUrl: "/static/ga-app/modules/pages/game/mock/mock.html", | |
controller: "gaPagesMockController" | |
}), $stateProvider.state("game.dashboardsFix", { | |
url: "/dashboards/", | |
data: { | |
alias: "game.dashboards" | |
} | |
}), $stateProvider.state("game.dashboards", { | |
url: "/dashboards", | |
templateUrl: "/static/ga-app/modules/pages/game/dashboards/dashboards.html", | |
controller: "gaPagesDashboardsController" | |
}), $stateProvider.state("game.dashboards.dashboard", { | |
url: "/:action/:dashboardId?state", | |
resolve: { | |
dashboardsResolve: DASHBOARDS_RESOLVE | |
} | |
}), $stateProvider.state("game.explore2", { | |
url: "/explore2", | |
templateUrl: "/static/ga-app/modules/pages/game/explore2/explore2.html", | |
controller: "gaPagesExplore2Controller" | |
}), $stateProvider.state("game.dashboards2.dashboard", { | |
url: "/:action/:dashboardId?state", | |
resolve: { | |
dashboardsResolve: DASHBOARDS_RESOLVE | |
} | |
}) | |
}), angular.module("ga.app.routes.user", ["ga.app.mainMenu", "ui.router", "ga.services.user", "ga.pages.general.tabbed", "ga.pages.user.home", "ga.pages.user.profile", "ga.pages.user.locale", "ga.pages.user.subscriptions"]).config(function($stateProvider) { | |
var USER_RESOLVE = function($q, $state, gaServicesUser) { | |
return gaServicesUser.resolveUser().catch($state.go.bind($state, "public.login", null, { | |
inherit: !1, | |
replace: !0 | |
})) | |
}, | |
USER_SUBSCRIPTIONS = function($q, gaApiUserDbAuthenticatedUser) { | |
return gaApiUserDbAuthenticatedUser.subscriptions() | |
}; | |
$stateProvider.state("user", { | |
"abstract": !0, | |
url: "?alert", | |
resolve: { | |
userResolve: USER_RESOLVE | |
}, | |
views: { | |
main: { | |
template: '<div style="margin-left: 80px;" ui-view></div>' | |
}, | |
header: { | |
templateUrl: "/static/ga-app/modules/app/partials/menu/menu.html", | |
controller: "gaAppMainMenuController" | |
}, | |
footer: { | |
template: "" | |
} | |
} | |
}), $stateProvider.state("user.home", { | |
url: "/home?archive", | |
templateUrl: "/static/ga-app/modules/pages/user/home/home.html", | |
controller: "gaPagesUserHomeController" | |
}), $stateProvider.state("user.settings", { | |
url: "/settings", | |
templateUrl: "/static/ga-app/modules/pages/general/tabbed/tabbed.html", | |
controller: "gaPagesGeneralTabbedController", | |
data: { | |
tabs: [{ | |
title: "Profile", | |
state: "user.settings.profile" | |
}, { | |
title: "Email reports", | |
state: "user.settings.subscriptions" | |
}, { | |
title: "Locale settings", | |
state: "user.settings.locale" | |
}] | |
} | |
}), $stateProvider.state("user.settings.profile", { | |
url: "/profile?source&link_token", | |
templateUrl: "/static/ga-app/modules/pages/user/profile/profile.html", | |
controller: "gaPagesUserProfileController" | |
}), $stateProvider.state("user.settings.locale", { | |
url: "/locale", | |
templateUrl: "/static/ga-app/modules/pages/user/locale/locale.html", | |
controller: "gaPagesUserLocaleController" | |
}), $stateProvider.state("user.settings.subscriptions", { | |
url: "/subscriptions", | |
resolve: { | |
resolveSubscriptions: USER_SUBSCRIPTIONS | |
}, | |
templateUrl: "/static/ga-app/modules/pages/user/subscriptions/subscriptions.html", | |
controller: "gaPagesUserSubscriptionsController" | |
}) | |
}), angular.module("ga.app.routes.public", ["ui.router", "ga.services.user", "ga.pages.public.linkAccount", "ga.pages.public.createAccount", "ga.pages.public.activateAccount", "ga.pages.public.signup", "ga.pages.public.login", "ga.pages.public.invite", "ga.pages.public.passwordReset", "ga.pages.public.releaseNotes", "ga.utils.cache", "ga.ui.notify", "ngRoute", "ga.api.userDb.public.passwordReset", "ga.api.userDb.public.invite", "ga.api.userDb.public.unsubscribe", "ga.api.userDb.public.activate"]).config(function($stateProvider) { | |
var SILENT_USER_RESOLVE = function($q, $stateParams, $state, gaServicesUser, gaUiNotify) { | |
return null !== $stateParams.logout ? (gaServicesUser.logout(), gaUiNotify.show("You are now logged out", 4e3, "default"), $q.when(null)) : gaServicesUser.resolveUser().catch(function() { | |
return $q.when(null) | |
}) | |
}, | |
INVITE_RESOLVE = function(user, $q, $state, $stateParams, gaServicesUser, gaApiUserDbPublicInvite) { | |
return gaApiUserDbPublicInvite.getInviteInfo($stateParams.email, $stateParams.resource, $stateParams.token).then(function(response) { | |
if (user) { | |
if (response.inviteFound && response.userFound && gaServicesUser.details.email === $stateParams.email) return $state.go("user.home", {}, { | |
location: "replace", | |
inherit: !1 | |
}), $q.reject() | |
} else { | |
var params; | |
if (response.inviteFound && !response.userFound) return params = { | |
token: response.createToken, | |
invite: "", | |
email: $stateParams.email, | |
emailmismatch: $stateParams.emailmismatch | |
}, $state.go("public.create-account", params, { | |
location: "replace", | |
inherit: !1 | |
}), $q.reject(); | |
if (response.inviteFound && response.userFound) return params = { | |
invite: "", | |
logout: "", | |
email: $stateParams.email | |
}, $state.go("public.login", params, { | |
location: "replace", | |
inherit: !1 | |
}), $q.reject() | |
} | |
return $q.when(response) | |
}) | |
}, | |
ACTIVATE_RESOLVE = function(user, $q, $state, $stateParams, gaServicesUser, gaApiUserDbPublicActivate) { | |
return gaApiUserDbPublicActivate.checkActivation($stateParams.email).then(function() { | |
return user && (gaServicesUser.token = null), $q.when() | |
}).catch(function(errors) { | |
return $state.go("public.login", { | |
error: errors[0].msg | |
}), $q.reject() | |
}) | |
}, | |
HOME_RESOLVE = function(user, $timeout, $q, $state) { | |
return user ? ($timeout(function() { | |
$state.go("user.home", {}, { | |
location: "replace" | |
}) | |
}), $q.reject()) : !0 | |
}, | |
LOGIN_RESOLVE = function(user, $window, $q, $timeout, $state, $stateParams, gaServicesUser, gaUtilsCache, $location) { | |
if (null !== $stateParams.logout) return $state.go("public.login", { | |
logout: null | |
}, { | |
inherit: !0, | |
replace: !0, | |
notify: !0 | |
}), $q.reject("logged out"); | |
if (user) { | |
if (null !== $stateParams.support) gaServicesUser.supportToken().then(function(token) { | |
var returnTo = $stateParams.return_to || "/home"; | |
$window.location.href = "http://support.gameanalytics.com/access/jwt?jwt=" + token.support_token + "&return_to=" + returnTo | |
}).catch(function() { | |
$state.go("user.home", {}, { | |
location: "replace" | |
}) | |
}); | |
else { | |
var goToPath = $stateParams.goto; | |
goToPath ? $timeout(function() { | |
$location.url(goToPath), $location.replace() | |
}) : $state.go("user.home", {}, { | |
location: "replace" | |
}) | |
} | |
return $q.reject() | |
} | |
return $stateParams.token && $stateParams.exp ? (gaServicesUser.token = { | |
token: $stateParams.token, | |
exp: $stateParams.exp | |
}, gaServicesUser.resolveUser().then(function() { | |
if (null !== $stateParams.support) gaServicesUser.supportToken().then(function(token) { | |
var returnTo = $stateParams.return_to || "/home"; | |
$window.location.href = "http://support.gameanalytics.com/access/jwt?jwt=" + token.support_token + "&return_to=" + returnTo | |
}).catch(function() { | |
$state.go("user.home", {}, { | |
location: "replace" | |
}) | |
}); | |
else { | |
var goTo = $stateParams.goto || gaUtilsCache.get("goToOnNextLogin", "localStorage"); | |
goTo ? $timeout(function() { | |
$location.url(goTo), $location.replace() | |
}) : $state.go("user.home", {}, { | |
location: "replace" | |
}) | |
} | |
gaUtilsCache.remove("goToOnNextLogin", "localStorage") | |
}).catch(function() { | |
$state.go("public.login", { | |
token: null, | |
exp: null | |
}, { | |
location: "replace", | |
reload: !0 | |
}) | |
}), $q.reject()) : $q.when() | |
}, | |
PASSWORD_RESET_TOKEN_RESOLVE = function(user, $q, $stateParams, gaApiUserDbPublicPasswordReset, gaServicesUser) { | |
return gaApiUserDbPublicPasswordReset.info($stateParams.token).then(function() { | |
return gaServicesUser.token = null, $q.when(!0) | |
}).catch(function() { | |
return $q.when(!1) | |
}) | |
}, | |
USER_SUBSCRIPTIONS = function($q, $stateParams, gaApiUserDbPublicUnsubscribe) { | |
return gaApiUserDbPublicUnsubscribe.getSubscriptions($stateParams.email, $stateParams.token).catch(function(errors) { | |
return $q.when({ | |
errors: errors | |
}) | |
}) | |
}; | |
$stateProvider.state("public", { | |
"abstract": !0, | |
resolve: { | |
user: SILENT_USER_RESOLVE | |
}, | |
url: "?alert&logout", | |
views: { | |
main: { | |
template: "<ui-view />" | |
}, | |
header: { | |
templateUrl: "/static/ga-app/modules/app/partials/public/header.html" | |
}, | |
footer: { | |
template: "" | |
} | |
} | |
}), $stateProvider.state("public2", { | |
"abstract": !0, | |
resolve: { | |
user: SILENT_USER_RESOLVE | |
}, | |
url: "?alert&logout", | |
views: { | |
main: { | |
template: "<ui-view />" | |
}, | |
header: { | |
templateUrl: "/static/ga-app/modules/app/partials/public/header-content.html", | |
controller: "gaAppHeaderContentController" | |
}, | |
footer: { | |
template: "" | |
} | |
} | |
}), $stateProvider.state("public2.release-notes", { | |
url: "/release-notes", | |
templateUrl: "/static/ga-app/modules/pages/public/release-notes/release-notes.html", | |
controller: "gaPagesPublicReleaseNotesController", | |
data: { | |
title: "Release Notes", | |
link: "/release-notes" | |
} | |
}), $stateProvider.state("public.login", { | |
resolve: { | |
token: LOGIN_RESOLVE | |
}, | |
url: "/login?source&token&exp&email&invite&error&linkedother¬found&passwordreset¬verified&support&return_to&goto&showreset", | |
templateUrl: "/static/ga-app/modules/pages/public/login/login.html", | |
controller: "gaPagesPublicLoginController" | |
}), $stateProvider.state("public.invite", { | |
resolve: { | |
inviteResolve: INVITE_RESOLVE | |
}, | |
url: "/invite/:resource/:token/:email", | |
templateUrl: "/static/ga-app/modules/pages/public/invite/invite.html", | |
controller: "gaPagesPublicInviteController" | |
}), $stateProvider.state("public.link-account", { | |
url: "/link-account/:email/:token?source", | |
templateUrl: "/static/ga-app/modules/pages/public/link-account/link-account.html", | |
controller: "gaPagesPublicLinkAccountController" | |
}), $stateProvider.state("public.signup", { | |
resolve: { | |
token: HOME_RESOLVE | |
}, | |
url: "/signup?email&linkeduserfound&ref¬verified&source&nr", | |
templateUrl: "/static/ga-app/modules/pages/public/signup/signup.html", | |
controller: "gaPagesPublicSignupController" | |
}), $stateProvider.state("public.create-account", { | |
url: "/create-account/:email/:token?source&invite&emailmismatch¬verified&firstname&lastname", | |
templateUrl: "/static/ga-app/modules/pages/public/create-account/create-account.html", | |
controller: "gaPagesPublicCreateAccountController" | |
}), $stateProvider.state("public.activate", { | |
url: "/activate/:email/:token", | |
resolve: { | |
resolveActivate: ACTIVATE_RESOLVE | |
}, | |
templateUrl: "/static/ga-app/modules/pages/public/activate-account/activate-account.html", | |
controller: "gaPagesPublicActivateAccountController" | |
}), $stateProvider.state("public.password-reset", { | |
url: "/reset-password/:token", | |
resolve: { | |
resolveValidToken: PASSWORD_RESET_TOKEN_RESOLVE | |
}, | |
templateUrl: "/static/ga-app/modules/pages/public/password-reset/password-reset.html", | |
controller: "gaPagesPublicPasswordResetController" | |
}), $stateProvider.state("public.wrapper", { | |
"abstract": !0, | |
template: '<div class="ga page box normal" ui-view></div>' | |
}), $stateProvider.state("public.wrapper.unsubscribe", { | |
url: "/reports/unsubscribe/:email/:token", | |
resolve: { | |
resolveSubscriptions: USER_SUBSCRIPTIONS | |
}, | |
templateUrl: "/static/ga-app/modules/pages/user/subscriptions/subscriptions.html", | |
controller: "gaPagesUserSubscriptionsController" | |
}) | |
}), angular.module("ga.app.routes.admin", ["ui.router", "ga.services.user", "ga.pages.admin.layout.header", "ga.pages.admin.home", "ga.pages.admin.search", "ga.pages.admin.logs", "ga.pages.admin.user", "ga.pages.admin.game", "ga.pages.admin.studio", "ga.pages.admin.haystack", "ga.pages.admin.export"]).config(function($stateProvider) { | |
var USER_RESOLVE = ["$state", "gaServicesUser", | |
function($state, gaServicesUser) { | |
return gaServicesUser.resolveUser().catch($state.go.bind($state, "public.login", null, { | |
inherit: !1 | |
})) | |
} | |
], | |
ADMIN_RESOLVE = function(user, $q, $state, gaServicesUser) { | |
if (user) { | |
if (user.admin !== !0 || user.adminLoggedIn !== !0) return $state.go("user.home", null, { | |
inherit: !1 | |
}), $q.reject("rejected"); | |
var now_ts = Math.round((new Date).getTime() / 1e3); | |
return now_ts > user.adminExpires ? gaServicesUser.getUserData(!0, !0).then(function() { | |
return $state.go("user.home", null, { | |
inherit: !1 | |
}), $q.reject() | |
}).catch(function() { | |
return $state.go("public.login", null, { | |
inherit: !1 | |
}), $q.reject() | |
}) : $q.when() | |
} | |
return $state.go($state, "public.login", null, { | |
inherit: !1 | |
}), $q.reject() | |
}; | |
$stateProvider.state("admin", { | |
resolve: { | |
user: USER_RESOLVE, | |
admin: ADMIN_RESOLVE | |
}, | |
url: "/admin", | |
"abstract": !0, | |
views: { | |
main: { | |
template: "<ui-view/>" | |
}, | |
header: { | |
templateUrl: "/static/ga-app/modules/pages/admin/layout/header/header.html", | |
controller: "gaPagesAdminLayoutHeaderController" | |
} | |
} | |
}), $stateProvider.state("admin.home", { | |
url: "", | |
templateUrl: "/static/ga-app/modules/pages/admin/home/home.html", | |
controller: "gaPagesAdminHomeController" | |
}), $stateProvider.state("admin.haystack", { | |
url: "/haystack", | |
templateUrl: "/static/ga-app/modules/pages/admin/haystack/haystack.html", | |
controller: "gaPagesAdminHaystackController" | |
}), $stateProvider.state("admin.search", { | |
url: "/search", | |
templateUrl: "/static/ga-app/modules/pages/admin/search/search.html", | |
controller: "gaPagesAdminSearchController" | |
}), $stateProvider.state("admin.logs", { | |
url: "/logs", | |
templateUrl: "/static/ga-app/modules/pages/admin/logs/logs.html", | |
controller: "gaPagesAdminLogsController" | |
}), $stateProvider.state("admin.user", { | |
url: "/user/:userId", | |
templateUrl: "/static/ga-app/modules/pages/admin/user/user.html", | |
controller: "gaPagesAdminUserController" | |
}), $stateProvider.state("admin.game", { | |
url: "/game/:gameId", | |
templateUrl: "/static/ga-app/modules/pages/admin/game/game.html", | |
controller: "gaPagesAdminGameController" | |
}), $stateProvider.state("admin.studio", { | |
url: "/studio/:studioId", | |
templateUrl: "/static/ga-app/modules/pages/admin/studio/studio.html", | |
controller: "gaPagesAdminStudioController" | |
}), $stateProvider.state("admin.export", { | |
url: "/export", | |
templateUrl: "/static/ga-app/modules/pages/admin/export/export.html", | |
controller: "gaPagesAdminExportController" | |
}) | |
}), angular.module("ga.app.routes.error", ["ngRoute", "ui.router"]).config(function($urlRouterProvider, $stateProvider) { | |
$urlRouterProvider.otherwise("/error/404"), $stateProvider.state("error", { | |
url: "/error", | |
"abstract": !0, | |
views: { | |
main: { | |
template: '<div class="ga-error-page"><div class="ga sections inside"><section class="ga" ui-view></section></div></div>' | |
}, | |
header: { | |
template: "" | |
}, | |
footer: { | |
template: "" | |
} | |
} | |
}), $stateProvider.state("error.404", { | |
url: "/404", | |
template: '<h1>Page not found</h1><p>The page you\'ve requested isn\'t here. <br />Contact <a class="ga color white" href="mailto:support@gameanalytics.com">support@gameanalytics.com</a> if you believe this is an error.</p><p><a href="/home" class="ga color orange">← Go back home</a></p>' | |
}), $stateProvider.state("error.500", { | |
url: "/500", | |
template: '<h1>Internal server error</h1><p>An unexpected error occured.</p><p><a href="/home" class="ga color orange">← Go back home</a></p>' | |
}), $stateProvider.state("error.maintenance", { | |
url: "/maintenance", | |
template: '<h1>We\'re temporarily unavailable</h1><p>We are currently performing maintenance and will be back shortly.<br/>Don\'t worry about your data - our servers are gathering it without interruptions.</p><p>We\'re sorry for the inconvenience.</p><p><a href="https://gameanalytics.statuspage.io/" target="_blank" class="ga color orange">Get updates on our statuspage</a></p>' | |
}) | |
}), angular.module("ga.app.mainMenu", ["ui.router", "ga.services.user", "ga.ui.menu", "ga.ui.tooltip", "ga.utils.detect", "ga.ui.modal", "ga.ui.notify", "ga.services.dialogs", "ga.api.admin", "ga.pages.admin.controller"]).controller("gaAppMainMenuController", function($rootScope, $scope, $state, gaUiModal, gaUiNotify, gaServicesUser, gaDetect, gaPagesAdminController) { | |
var updateUserSettings = function() { | |
$scope.user = { | |
studios: gaServicesUser.studios, | |
admin: gaServicesUser.admin, | |
adminLoggedIn: gaServicesUser.adminLoggedIn, | |
impersonated: gaServicesUser.impersonated | |
} | |
}; | |
$scope.logout = "", updateUserSettings(), $scope.$on("userStudiosChange", function() { | |
$scope.user.studios = gaServicesUser.studios, selectGame(parseInt($state.params.gameId, 10) || 0) | |
}), $scope.iframeFix = $state.includes("game.heatmap") && "windows" === gaDetect.OS(), $scope.$on("$stateChangeSuccess", function() { | |
$scope.iframeFix = $state.includes("game.heatmap") && "windows" === gaDetect.OS() | |
}), $scope.goTo = function(gameId) { | |
$state.includes("game.settings") ? $state.go("game.settings", { | |
gameId: gameId, | |
state: null | |
}) : $state.includes("game.heatmap") || $state.includes("game.heatmap-nodata") || $state.includes("game.heatmap-firsttime") ? $state.go("game.heatmap", { | |
gameId: gameId, | |
state: null | |
}) : $state.includes("game.explore") ? $state.go("game.explore", { | |
gameId: gameId, | |
state: null | |
}) : $state.includes("game.funnel") ? $state.go("game.funnel.list", { | |
gameId: gameId, | |
state: null | |
}) : $state.includes("game.cohort") ? $state.go("game.cohort", { | |
gameId: gameId, | |
state: null | |
}) : $state.includes("game.querybuilder") ? $state.go("game.querybuilder", { | |
gameId: gameId, | |
state: null | |
}) : isNaN(parseInt($state.params.dashboardId, 10)) ? $state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: gameId, | |
dashboardId: $state.params.dashboardId, | |
state: null | |
}) : $state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: gameId, | |
dashboardId: 0, | |
state: null | |
}) | |
}; | |
var selectGame = function(gameId) { | |
if ($scope.gameId = gameId, gameId) { | |
var game = gaServicesUser.game(gameId); | |
$scope.gameTitle = game.title, $scope.imagePath = game.imagePath, $scope.isDemo = game.demo | |
} | |
}; | |
selectGame(parseInt($state.params.gameId, 10) || 0); | |
var _setMenu = function() { | |
if ($state.current && $state.current.name) { | |
var active = $state.current.name.split("."); | |
$scope.activeMenuItem = active.length > 1 ? active[1] : "", ("heatmap-nodata" === $scope.activeMenuItem || "heatmap-firsttime" === $scope.activeMenuItem) && ($scope.activeMenuItem = "heatmap") | |
} else $scope.activeMenuItem = "" | |
}; | |
$rootScope.$on("$stateChangeSuccess", function() { | |
_setMenu() | |
}), $scope.adminLoginModal = function() { | |
gaPagesAdminController.loginModal().then(function() { | |
updateUserSettings(), gaUiNotify.show("admin successfully logged in!", 4e3, "default"), $state.go("admin.home") | |
}) | |
}, $scope.adminLogout = function() { | |
gaPagesAdminController.logout().then(function() { | |
gaServicesUser.getUserData(!0, !0).then(function() { | |
updateUserSettings(), gaUiNotify.show("admin logged out!", 4e3, "default") | |
}) | |
}) | |
}, $scope.adminResetImpersonate = function() { | |
gaPagesAdminController.resetImpersonate().then(function() { | |
gaServicesUser.getUserData(!1, !0).then(function() { | |
updateUserSettings(), gaUiNotify.show("user impersonation stopped!", 4e3, "default"), $state.go("admin.search") | |
}) | |
}) | |
}, _setMenu() | |
}), angular.module("ga.app.springboard", ["ui.router", "ga.config", "ga.services.user", "ga.services.tracking", "ga.ui.popdown", "ga.api.statuspage"]).controller("gaAppSpringboardController", function($scope, $rootScope, $state, $route, gaConfig, gaServicesTracking, gaServicesUser) { | |
$scope.menuVisible = !1, $scope.gameId = parseInt($state.params.gameId, 10) || 0, $scope.userCanEditGame = (gaServicesUser.game($scope.gameId) || {}).admin, ($state.includes("game.initialize") || $state.includes("game.content")) && ($scope.homeOnly = !0), $scope.imageBaseUrl = gaConfig.images.baseUrl, $scope.gameId && ($scope.game = gaServicesUser.game($scope.gameId)), $scope.isAdmin = gaServicesUser.admin, $scope.isAdminLoggedIn = gaServicesUser.adminLoggedIn, $scope.isUserImpersonated = $scope.isAdminLoggedIn ? gaServicesUser.userImpersonated : !1, $scope.user = { | |
name: gaServicesUser.details.name, | |
studios: gaServicesUser.studios, | |
activated: gaServicesUser.activated, | |
admin: gaServicesUser.admin, | |
adminLoggedIn: gaServicesUser.adminLoggedIn, | |
impersonated: gaServicesUser.impersonated | |
}, $scope.$on("userStudiosChange", function() { | |
$scope.user.studios = gaServicesUser.studios | |
}), $scope.$on("userDetailsChange", function() { | |
$scope.user.name = gaServicesUser.details.name, $scope.user.studios = gaServicesUser.studios | |
}), $scope.$on("currentGameChange", function() { | |
$scope.user.studios = gaServicesUser.studios, $scope.game = gaServicesUser.game($scope.gameId) | |
}), $scope.$on("studioChange", function() { | |
$scope.user.studios = gaServicesUser.studios | |
}), $scope.logout = function() { | |
$state.go("public.login", { | |
logout: "" | |
}, { | |
inherit: !1 | |
}) | |
}, $scope.goToFunnel = function() { | |
gaServicesTracking.addEvent("design", "state.game.funnel", { | |
value: 1 | |
}, !0).then(function() { | |
window.location.href = "/game/" + $scope.gameId + "/funnel" | |
}).catch(function() { | |
window.location.href = "/game/" + $scope.gameId + "/funnel" | |
}) | |
}, $scope.goTo = function(gameId) { | |
$state.includes("game.heatmap") || $state.includes("game.heatmap-nodata") || $state.includes("game.heatmap-firsttime") ? $state.go("game.heatmap", { | |
gameId: gameId, | |
state: null | |
}) : $state.includes("game.explore") ? $state.go("game.explore", { | |
gameId: gameId, | |
state: null | |
}) : $state.includes("game.cohort") ? $state.go("game.cohort", { | |
gameId: gameId, | |
state: null | |
}) : $state.includes("game.querybuilder") ? $state.go("game.querybuilder", { | |
gameId: gameId, | |
state: null | |
}) : isNaN(parseInt($state.params.dashboardId, 10)) ? $state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: gameId, | |
dashboardId: $state.params.dashboardId, | |
state: null | |
}) : $state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: gameId, | |
dashboardId: 0, | |
state: null | |
}), $route.reload() | |
}; | |
var _setMenu = function() { | |
if ($state.current && $state.current.name) { | |
var active = $state.current.name.split("."); | |
$scope.activeMenuItem = active.length > 1 ? active[1] : "", ("heatmap-nodata" === $scope.activeMenuItem || "heatmap-firsttime" === $scope.activeMenuItem) && ($scope.activeMenuItem = "heatmap") | |
} else $scope.activeMenuItem = "" | |
}; | |
$rootScope.$on("$stateChangeSuccess", function() { | |
_setMenu() | |
}), _setMenu() | |
}), angular.module("ga.app.headerContent", ["ui.router", "ga.values.user"]).controller("gaAppHeaderContentController", function($scope, $state, gaValuesUser) { | |
$scope.userLoggedIn = !!gaValuesUser.token, $scope.guides = window.location.host.match("guides.*?"), $state.current.data && $state.current.data.title ? ($scope.title = $state.current.data.title, $scope.link = $state.current.data.link) : ($scope.title = "GameAnalytics guides", $scope.link = "/content/sdk") | |
}), angular.module("ga.app.footer", ["ui.router"]).controller("gaAppFooterController", function($scope, $rootScope, $timeout, $state) { | |
$scope.year = (new Date).getFullYear(), $scope.links = [{ | |
title: "About", | |
href: "http://www.gameanalytics.com/aboutus.html", | |
target: "_blank" | |
}, { | |
title: "Blog", | |
href: "http://blog.gameanalytics.com/", | |
target: "_blank" | |
}, { | |
title: "Support", | |
href: "http://support.gameanalytics.com/", | |
target: "_blank" | |
}, { | |
title: "Guides", | |
href: "/content/sdk" | |
}], $scope.visible = !1, $rootScope.$on("$stateChangeStart", function() { | |
$scope.visible = !1 | |
}), $rootScope.$on("$stateChangeSuccess", function() { | |
"edit" !== $state.params.action && $timeout(function() { | |
$scope.visible = !0 | |
}, 500) | |
}), "edit" !== $state.params.action && $timeout(function() { | |
$scope.visible = !0 | |
}, 500) | |
}), angular.module("ga.app.partials.toolHeader", ["ga.services.user"]).controller("gaAppPartialsToolHeader", function($scope, gaServicesUser) { | |
$scope.studios = gaServicesUser.studios, $scope.userDetails = gaServicesUser.details | |
}), angular.module("ga.api.admin", ["ga.api.userDb", "ga.config", "ga.utils.cache"]).factory("gaApiAdmin", function($rootScope, $location, $injector, $q, $cookieStore, $cookies, gaApiUserDb, gaUtilsCache) { | |
var adminLogin = function(authKey) { | |
var url = "admin/login/" + authKey; | |
return gaApiUserDb.post(url) | |
}, | |
adminLogout = function() { | |
var url = "admin/logout"; | |
return gaApiUserDb.post(url) | |
}, | |
adminResetImpersonate = function() { | |
var url = "admin/reset_impersonating"; | |
return gaApiUserDb.post(url) | |
}, | |
impersonateUser = function(userId) { | |
var url = "admin/users/" + userId + "/impersonate"; | |
return gaApiUserDb.put(url) | |
}, | |
getUsersBySearch = function(filters, force) { | |
var url = "admin/users", | |
cacheString = "adminSearchUsers" + JSON.stringify(filters), | |
users = force ? null : gaUtilsCache.get(cacheString); | |
return users && $.when(users), gaApiUserDb.post(url, filters).then(function(results) { | |
return gaUtilsCache.put(cacheString, results), $.when(results || null) | |
}) | |
}, | |
getUser = function(userId) { | |
var url = "admin/users/" + userId; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $.when(results[0] || null) | |
}) | |
}, | |
getStudiosBySearch = function(filters, force) { | |
var url = "admin/studios", | |
cacheString = "adminSearchGames" + JSON.stringify(filters), | |
studios = force ? null : gaUtilsCache.get(cacheString); | |
return studios && $.when(studios), gaApiUserDb.post(url, filters).then(function(results) { | |
return gaUtilsCache.put(cacheString, results), $.when(results || null) | |
}) | |
}, | |
getStudio = function(studioId) { | |
var url = "admin/studios/" + studioId; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $.when(results[0] || null) | |
}) | |
}, | |
getGamesBySearch = function(filters, force) { | |
var url = "admin/games", | |
cacheString = "adminSearchGames" + JSON.stringify(filters), | |
games = force ? null : gaUtilsCache.get(cacheString); | |
return games && $.when(games), gaApiUserDb.post(url, filters).then(function(results) { | |
return gaUtilsCache.put(cacheString, results), $.when(results || null) | |
}) | |
}, | |
getGame = function(gameId) { | |
var url = "admin/games/" + gameId; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $.when(results[0] || null) | |
}) | |
}, | |
getUserLogs = function(filters, force) { | |
var url = "admin/userlogs", | |
cacheString = "adminToolUserLogs" + JSON.stringify(filters), | |
usersLogs = force ? null : gaUtilsCache.get(cacheString); | |
return usersLogs ? $.when(usersLogs) : gaApiUserDb.post(url, filters).then(function(results) { | |
return gaUtilsCache.put(cacheString, results), $.when(results || null) | |
}) | |
}, | |
getHomeStats = function(force) { | |
var url = "admin/all", | |
cacheString = "adminToolHomeStats", | |
homeStatsCached = force ? null : gaUtilsCache.get(cacheString); | |
return homeStatsCached ? $.when(homeStatsCached) : gaApiUserDb.get(url).then(function(results) { | |
return gaUtilsCache.put(cacheString, results[0]), $.when(results[0] || null) | |
}) | |
}, | |
getRedshiftStatus = function() { | |
var url = "admin/redshift/status"; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $.when(results[0] || null) | |
}) | |
}, | |
getRedshiftIdentifiers = function(idType, rankCriterion, gameType, targetGameId, targetSimilarGames, countryType, targetCountries) { | |
var url = "admin/redshift/export?type=" + idType + "&rank=" + rankCriterion + "&gameType=" + gameType + "&targetGameId=" + targetGameId + "&targetSimilarGames=" + targetSimilarGames + "&countryType=" + countryType + "&targetCountries=" + targetCountries; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $.when(results[0] || null) | |
}) | |
}, | |
getSimilarityScoresForGame = function(targetGameId) { | |
var url = "admin/redshift/similarity/" + targetGameId; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $.when(results || null) | |
}) | |
}, | |
changeUserEmail = function(userId, email) { | |
var emailData = { | |
email: email | |
}, | |
url = "admin/users/" + userId + "/email"; | |
return gaApiUserDb.put(url, emailData) | |
}, | |
changeStudioOwner = function(studioId, userId) { | |
var userIdData = { | |
user_id: userId | |
}, | |
url = "admin/studios/" + studioId + "/owner"; | |
return gaApiUserDb.put(url, userIdData) | |
}; | |
return { | |
adminLogin: adminLogin, | |
adminLogout: adminLogout, | |
adminResetImpersonate: adminResetImpersonate, | |
impersonateUser: impersonateUser, | |
getUsersBySearch: getUsersBySearch, | |
getUser: getUser, | |
getStudiosBySearch: getStudiosBySearch, | |
getStudio: getStudio, | |
getGamesBySearch: getGamesBySearch, | |
getGame: getGame, | |
getUserLogs: getUserLogs, | |
getHomeStats: getHomeStats, | |
getRedshiftStatus: getRedshiftStatus, | |
getRedshiftIdentifiers: getRedshiftIdentifiers, | |
getSimilarityScoresForGame: getSimilarityScoresForGame, | |
changeUserEmail: changeUserEmail, | |
changeStudioOwner: changeStudioOwner | |
} | |
}), angular.module("ga.api.data", ["ga.config", "ga.utils.date", "ga.utils.cache", "ga.api.meta", "ga.values.user", "ga.utils.transform", "ga.utils.urlState", "ga.services.tracking"]).factory("gaApiData", function($window, $rootScope, $http, $q, $state, $timeout, gaUtilsCache, gaValuesUser, gaConfig, gaApiMeta, gaUtilsTransform, gaUtilsDate, gaServicesTracking) { | |
var requestPromises = {}, | |
get = function(requestQuery, UID, sortArray) { | |
var deferred = $q.defer(); | |
if ("daily" === requestQuery.rollup && delete requestQuery.rollup, !gaValuesUser.token) return $q.reject({ | |
error: "no_user" | |
}); | |
if (!requestQuery.gameId && !$state.params.gameId) return $q.reject({ | |
error: "no_game" | |
}); | |
if (!requestQuery.metric || angular.isArray(requestQuery.metric) && !requestQuery.metric.length) return $q.reject({ | |
error: "no_metric" | |
}); | |
if ("dimension" === requestQuery.group && !requestQuery.filter) return $q.reject({ | |
error: "group_dimension_with_no_filter" | |
}); | |
if (angular.isArray(requestQuery.metric) || (requestQuery.metric = [requestQuery.metric]), "Virtual" === requestQuery.metric[0].currency && !requestQuery.isVirtualCurrency) return _getVirtualCurrencies(requestQuery).then(function(virtualCurrencies) { | |
0 === virtualCurrencies.length && (virtualCurrencies = ["null"]); | |
var newMetrics = []; | |
return angular.forEach(virtualCurrencies, function(currency) { | |
var metric = angular.copy(requestQuery.metric[0]); | |
metric.currency = currency, newMetrics.push(metric) | |
}), requestQuery.isVirtualCurrency = !0, requestQuery.metric = newMetrics, get(requestQuery, UID, sortArray).then(function(response) { | |
return $q.when(response) | |
}) | |
}); | |
requestQuery.compareInterval === !0 && (requestQuery.compareInterval = gaUtilsDate.getPreviousPeriod(requestQuery.interval)), requestQuery.mergeCompare = requestQuery.mergeCompare !== !1, requestQuery.filter && angular.isString(requestQuery.filter.dimension) && requestQuery.filter.dimension.indexOf("cohort_") > -1 && (requestQuery.compareInterval = null, "dimension" === requestQuery.group && (requestQuery.group = "time", requestQuery.normalized = !0)); | |
var request = createQueryObject(requestQuery), | |
response = function(fromCache) { | |
if (request.mainQuery.isVirtualCurrency && angular.forEach(request.queries, function(query, index) { | |
var newResponse = {}, | |
type = request.response[index].timeseries ? "timeseries" : "aggregated"; | |
newResponse[type] = {}, angular.forEach(request.response[index][type], function(data, event) { | |
newResponse[type][event + " - " + query.metric.currency] = data | |
}), request.response[index] = newResponse | |
}), request.mainQuery.noParse) deferred.resolve(request); | |
else { | |
var newParsedPromise = gaUtilsTransform.parse(request, null, sortArray); | |
newParsedPromise.then(function(parsed) { | |
fromCache === !0 && (parsed.fromCache = !0), request.mainQuery.returnAll ? (request.parsed = parsed, deferred.resolve(request)) : deferred.resolve(parsed) | |
}) | |
} | |
}; | |
if (request.response = request.mainQuery.noCache ? [] : gaUtilsCache.get(request.hash) || [], request.response.length) response(!0); | |
else { | |
UID && (removeUID(UID), requestPromises[UID] = $q.defer()); | |
var get_config = { | |
headers: { | |
Authorization: gaValuesUser.gameToken(request.mainQuery.gameId) | |
}, | |
timeout: requestPromises[UID] ? requestPromises[UID].promise : null | |
}, | |
successCallback = function(collection) { | |
removeUID(UID); | |
var hasError = !1; | |
collection.data.forEach(function(data) { | |
request.response.push(data.body), 200 !== data.code && (hasError = !0) | |
}), hasError ? (request.mainQuery.error = !0, deferred.reject(request)) : (request.mainQuery.realtime || gaUtilsCache.put(request.hash, request.response), response(request.response)) | |
}, | |
errorCallback = function(response) { | |
removeUID(UID), deferred.reject(response.data) | |
}; | |
if (1 === request.mainQuery.metric.length && "null" === request.mainQuery.metric[0].category) { | |
var event = request.mainQuery.metric[0].event, | |
responseData = [{ | |
body: { | |
timeseries: {} | |
} | |
}, { | |
body: { | |
aggregated: {} | |
} | |
}]; | |
responseData[0].body.timeseries[event] = []; | |
var interval = gaUtilsDate.getInterval(request.mainQuery.interval.start, request.mainQuery.interval.end, 864e5, 0); | |
angular.forEach(interval, function(timestamp) { | |
responseData[0].body.timeseries[event].push({ | |
timestamp: timestamp / 1e3 | |
}) | |
}), responseData[1].body.aggregated[event] = {}, successCallback({ | |
data: responseData | |
}) | |
} else { | |
var baseUrl = gaConfig.getUrl(!0, request.mainQuery.realtime), | |
time = (new Date).getTime(); | |
$http.post(baseUrl + request.mainQuery.gameId, request.urls, get_config).then(function(response) { | |
return time = (new Date).getTime() - time, "core" === request.mainQuery.metric[0].category || "operations" === request.mainQuery.metric[0].category ? gaServicesTracking.addEvent("design", "perf:data-api:batch:" + request.mainQuery.metric[0].category + ":load-time-ms", { | |
value: time | |
}) : gaServicesTracking.addEvent("design", "perf:data-api:batch:" + request.mainQuery.metric[0].category + ":load-time-ms", { | |
value: time | |
}), $q.when(response) | |
}).then(successCallback, errorCallback) | |
} | |
} | |
return deferred.promise | |
}, | |
createQueryObject = function(requestQuery) { | |
var request = { | |
mainQuery: {}, | |
queries: [], | |
urls: [], | |
response: [] | |
}; | |
return request.mainQuery = angular.copy(requestQuery), request.mainQuery.top = angular.isNumber(request.mainQuery.top) ? request.mainQuery.top : 15, request.mainQuery.aggregation = request.mainQuery.aggregation || "mean", request.mainQuery.aggregation_aggregated = request.mainQuery.aggregation || "mean", request.mainQuery.group = request.mainQuery.group || "time", request.mainQuery.gameId = request.mainQuery.gameId || $state.params.gameId, request.mainQuery.metric = angular.isArray(request.mainQuery.metric) ? request.mainQuery.metric : [request.mainQuery.metric], 1 === request.mainQuery.metric.length && "null" === request.mainQuery.metric[0].category && (request.mainQuery.compareInterval = null), angular.forEach(request.mainQuery.metric, function(metric) { | |
var query; | |
"retention" !== metric.event && "retention_full" !== metric.event || "core" !== metric.category ? "returning_users" !== metric.event && "returning_users_full" !== metric.event || "core" !== metric.category ? (query = angular.copy(request.mainQuery), query.metric = metric, request.queries.push(query)) : angular.forEach(["returning_users_1", "returning_users_2", "returning_users_3", "returning_users_4", "returning_users_5", "returning_users_6", "returning_users_7", "returning_users_14", "returning_users_28", , "returning_users_30", "returning_users_90"], function(event) { | |
query = angular.copy(request.mainQuery), query.metric = angular.copy(metric), query.metric.event = event, request.queries.push(query) | |
}) : angular.forEach(["retention_1", "retention_2", "retention_3", "retention_4", "retention_5", "retention_6", "retention_7", "retention_14", "retention_28", "retention_30", "retention_90"], function(event) { | |
query = angular.copy(request.mainQuery), query.metric = angular.copy(metric), query.metric.event = event, request.queries.push(query) | |
}) | |
}), angular.forEach(request.queries, function(q) { | |
if (q.compareInterval) { | |
var compareQuery = angular.copy(q); | |
compareQuery.isCompare = !0, compareQuery.interval = compareQuery.compareInterval, delete compareQuery.compareInterval, request.queries.push(compareQuery), delete q.compareInterval | |
} | |
}), angular.forEach(request.queries, function(q) { | |
if ("time" === q.group && !q.noAggregation) { | |
delete q.includeAggregated; | |
var aggregatedQuery = angular.copy(q); | |
if (aggregatedQuery.group = "dimension", q.showSum && "mean" === aggregatedQuery.aggregation) { | |
var meta = gaApiMeta.getMetric(aggregatedQuery.metric.category, aggregatedQuery.metric.event); | |
meta.forceTotal && (meta.available_aggregations && meta.available_aggregations.indexOf("sum") > -1 ? (aggregatedQuery.aggregation = "sum", request.mainQuery.aggregation_aggregated = "sum") : meta.available_aggregations && meta.available_aggregations.indexOf("event_count") > -1 && (aggregatedQuery.aggregation = "event_count", request.mainQuery.aggregation_aggregated = "event_count")) | |
} | |
request.queries.push(aggregatedQuery) | |
} | |
}), request.urls = request.queries.map(function(q) { | |
return makeRequestURL(q, !1) | |
}), request.hash = btoa(request.urls.join(";")), request | |
}, | |
makeRequestURL = function(query, includeDomain, onlyMetric) { | |
includeDomain = void 0 === includeDomain ? !0 : includeDomain; | |
var gameId = query.gameId || $state.params.gameId, | |
metric = angular.isArray(query.metric) ? query.metric[0] : query.metric, | |
meta = gaApiMeta.getMetric(metric), | |
requestURL = ""; | |
requestURL = onlyMetric ? "/" + metric.category + "/" + $window.encodeURIComponent(meta.alias || metric.event) : includeDomain ? gaConfig.getUrl(!1, !1) + gameId + "/" + metric.category + "/" + $window.encodeURIComponent(meta.alias || metric.event) : gaConfig.data.basePath + gameId + "/" + metric.category + "/" + $window.encodeURIComponent(meta.alias || metric.event); | |
var queryParams = []; | |
return queryParams.push("start=" + query.interval.start / 1e3), queryParams.push("end=" + query.interval.end / 1e3), query.filter && queryParams.push(query.filter.dimension + "=" + query.filter.values.map($window.encodeURIComponent).join(",")), query.metric.currency && queryParams.push("currency=" + $window.encodeURIComponent(query.isVirtualCurrency ? "USD" : query.metric.currency)), query.aggregation && "time" !== query.group && queryParams.push("aggregation=" + $window.encodeURIComponent(query.aggregation)), query.normalized === !0 && "time" === query.group && queryParams.push("normalized=true"), query.aggregation && "time" !== query.group || meta.ignore_rollup || query.rollup && queryParams.push("rollup=" + $window.encodeURIComponent(query.rollup)), requestURL + "?" + queryParams.join("&") | |
}, | |
removeUID = function(UID) { | |
requestPromises[UID] && (requestPromises[UID].resolve(), delete requestPromises[UID]) | |
}, | |
_getVirtualCurrencies = function(originalQuery) { | |
var query = angular.copy(originalQuery); | |
query.isVirtualCurrency = !0, query.group = "dimension"; | |
var url = makeRequestURL(query, !1, !0); | |
return getValue(url).then(function(data) { | |
var currencies = []; | |
return angular.forEach(data.aggregated, function(data) { | |
angular.forEach(data.total, function(value, currency) { | |
"USD" !== currency && currencies.indexOf(currency) < 0 && currencies.push(currency) | |
}) | |
}), $q.when(currencies) | |
}) | |
}, | |
getQuality = function(options, UID) { | |
UID && (removeUID(UID), requestPromises[UID] = $q.defer()), options.gameId = options.gameId || $state.params.gameId; | |
var get_config = { | |
headers: { | |
Authorization: gaValuesUser.gameToken(options.gameId) | |
}, | |
timeout: requestPromises[UID] ? requestPromises[UID].promise : null | |
}, | |
requestURLs = [], | |
category = options.realtime ? "operations" : "error"; | |
angular.forEach(options.levels, function(level) { | |
requestURLs.push("/v1/games/" + options.gameId + "/" + category + "/stacktrace:" + level + "?" + (options.timeseries ? "" : "aggregation=sum&") + (options.filter && options.filter.dimension ? options.filter.dimension + "=" + options.filter.values.map(window.escape).join(",") + "&" : "") + "start=" + options.interval.start / 1e3 + "&end=" + options.interval.end / 1e3) | |
}); | |
var baseUrl = gaConfig.getUrl(!0, options.realtime), | |
time = (new Date).getTime(); | |
return $http.post(baseUrl + (options.gameId || $state.params.gameId), requestURLs, get_config).then(function(response) { | |
return time = (new Date).getTime() - time, gaServicesTracking.addEvent("design", "perf:data-api:batch:" + category + ":stacktrace:load-time-ms", { | |
value: time | |
}), $q.when(response) | |
}).then(function(response) { | |
return $q.when(qualityParse(response.data, options)) | |
}) | |
}, | |
qualityParse = function(data, options) { | |
var parsed = []; | |
return angular.forEach(data, function(response, index) { | |
var level = options.levels[index], | |
dimData = {}; | |
response.body.aggregated && response.body.aggregated["stacktrace:" + level] && (options.filter && options.filter.dimension ? response.body.aggregated["stacktrace:" + level].dimensions && response.body.aggregated["stacktrace:" + level].dimensions[options.filter.dimension] && (dimData = response.body.aggregated["stacktrace:" + level].dimensions[options.filter.dimension]) : dimData[0] = response.body.aggregated["stacktrace:" + level].total, angular.forEach(dimData, function(data, dimension) { | |
angular.forEach(data, function(occurence) { | |
var item = { | |
level: level, | |
key: occurence.key, | |
name: occurence.value, | |
dimension: options.filter && options.filter.dimension || null, | |
dimensionValue: dimension || null, | |
eventCount: occurence.count | |
}; | |
parsed.push(item) | |
}) | |
})) | |
}), options.eventPattern && (parsed = parsed.filter(function(a) { | |
return a.name.match(options.eventPattern) | |
})), parsed | |
}, | |
getValue = function(url, gameId, noCache) { | |
gameId = gameId || $state.params.gameId; | |
var realtime = url.indexOf("operations/") > -1, | |
baseUrl = gaConfig.getUrl(!1, realtime), | |
requestURL = baseUrl + gameId + url, | |
get_config = { | |
headers: { | |
Authorization: gaValuesUser.gameToken(gameId) | |
} | |
}, | |
cache = noCache ? null : gaUtilsCache.get(requestURL); | |
return cache ? $q.when(cache) : $http.get(requestURL, get_config).then(function(response) { | |
return !noCache && gaUtilsCache.put(requestURL, response.data), $q.when(response.data) | |
}) | |
}, | |
getDataDownloadLinks = function(gameId, interval) { | |
var requestURL = gaConfig.getUrl(!1, !1) + gameId + "/export", | |
queryString = "?" + ["start=" + interval.start / 1e3, "end=" + interval.end / 1e3].join("&"); | |
requestURL += queryString; | |
var getConfig = { | |
headers: { | |
Authorization: gaValuesUser.gameToken(gameId) | |
} | |
}; | |
return $http.get(requestURL, getConfig).then(function(response) { | |
return $q.when(response.data) | |
}) | |
}, | |
getFunnels = function(gameId) { | |
var requestURL = gaConfig.getUrl(!1, !1) + gameId + "/funnels", | |
getConfig = { | |
headers: { | |
Authorization: gaValuesUser.gameToken(gameId) | |
} | |
}; | |
return $http.get(requestURL, getConfig).then(function(response) { | |
return $q.when(response.data) | |
}) | |
}; | |
return { | |
getQuality: getQuality, | |
getValue: getValue, | |
get: get, | |
removeUID: removeUID, | |
makeRequestURL: makeRequestURL, | |
getDataDownloadLinks: getDataDownloadLinks, | |
getFunnels: getFunnels | |
} | |
}), angular.module("ga.api.data.funnel", ["ga.config", "ga.values.user", "ga.utils.transform"]).service("gaApiDataFunnel", function($http, $q, $state, gaValuesUser, gaConfig, gaUtilsTransform) { | |
this.getList = function(gameId) { | |
var requestURL = gaConfig.getUrl(!1, !1, !0) + gameId + "/funnels"; | |
return $http.get(requestURL, headerConfig(gameId)).then(function(response) { | |
return $q.when(response.data) | |
}) | |
}, this.getFunnel = function(gameId, funnel, dateRangeId) { | |
if (!funnel.dateRanges || !funnel.dateRanges.length || !dateRangeId) return $q.reject(); | |
var backendId = null; | |
if (funnel.dateRanges.some(function(dr) { | |
return parseInt(dateRangeId) === dr.id ? dr.status && "processed" === dr.status.id && !dr.status.hasData ? (backendId = "__empty__", !0) : (backendId = dr.backendId, !0) : void 0 | |
}), !backendId || backendId && "__failed__" === backendId) return $q.reject(); | |
if ("__empty__" === backendId) return $q.when(gaUtilsTransform.parseEmptyFunnelData(funnel)); | |
var requestURL = gaConfig.getUrl(!1, !1, !0) + gameId + "/funnels/" + backendId; | |
return $http.get(requestURL, headerConfig(gameId)).then(function(response) { | |
return gaUtilsTransform.parseFunnelData(response.data, funnel) | |
}) | |
}, this.processFunnel = function(gameId, email, options) { | |
var payload = { | |
start: options.start / 1e3, | |
end: options.end / 1e3, | |
events: options.events, | |
dimensions: options.dimensions, | |
email: email, | |
funnel_title: options.name | |
}, | |
requestURL = gaConfig.getUrl(!1, !1, !0) + gameId + "/funnels"; | |
return $http.post(requestURL, payload, headerConfig(gameId)).then(function(response) { | |
return $q.when(response.data) | |
}) | |
}; | |
var headerConfig = function(gameId) { | |
return { | |
headers: { | |
Authorization: gaValuesUser.gameToken(gameId) | |
} | |
} | |
} | |
}), angular.module("ga.api.meta", ["ga.filters.numberFormat", "ga.utils.date", "ga.components.moment", "ga.values.user"]).filter("formatUnitType", function($rootScope, $filter, gaApiMeta, gaUtilsDate, moment, gaValuesUser) { | |
var gaNumberFormat = $filter("gaNumberFormat"); | |
return function(input, type, unit, defaultValue, noFix, noShorten) { | |
var isNumber = function(n) { | |
return !isNaN(parseFloat(n)) && isFinite(n) | |
}, | |
currency = gaValuesUser.settings.currencyDefault, | |
ignoreFixUnit = !1; | |
if (angular.isObject(type) && (noShorten = noFix, noFix = defaultValue, defaultValue = unit, unit = type.unit, currency = type.currency || gaValuesUser.settings.currencyDefault, type = type.type), void 0 === input) return ""; | |
defaultValue = defaultValue || "", "money" === unit ? (currency = gaApiMeta.getCurrency(currency), unit = { | |
preUnit: currency.symbol | |
}) : unit = gaApiMeta.getUnit(unit || "_default"), unit.postFix && unit.postUnit && !noFix && (ignoreFixUnit = !0); | |
var filtered = defaultValue, | |
timezone = gaValuesUser.settings.timeZone; | |
if (null !== input && void 0 !== input) switch (type) { | |
case "percent": | |
isNaN(input) || (filtered = gaNumberFormat(100 * input)); | |
break; | |
case "number": | |
filtered = noShorten ? gaNumberFormat(input, !0) : gaNumberFormat(input); | |
break; | |
case "second": | |
filtered = gaNumberFormat(input, !0); | |
break; | |
case "seconds": | |
input = Math.round(input); | |
var secs = 0, | |
mins = 0, | |
hours = 0, | |
days = 0; | |
60 > input ? filtered = input + "s." : 3600 > input ? (secs = input % 60, mins = Math.floor((input - secs) / 60), filtered = mins + "m. " + secs + "s.") : 172800 > input ? (hours = Math.floor(input / 3600), mins = Math.round((input - 60 * hours * 60) / 60), filtered = hours + "h. " + mins + "m.") : (days = Math.floor(input / 86400), hours = Math.round((input - 60 * days * 60 * 24) / 3600), filtered = days + "d. " + hours + "h."); | |
break; | |
case "money": | |
filtered = $filter("gaNumberFormat")(input); | |
break; | |
case "date": | |
filtered = isNumber(input) ? moment.utc(parseInt(input, 10)).format(gaUtilsDate.getCurrentDateFormatString()) : input; | |
break; | |
case "time": | |
filtered = isNumber(input) ? moment.utc(parseInt(input, 10)).tz(timezone).format(gaUtilsDate.getCurrentTimeFormat()) : input; | |
break; | |
case "datetime": | |
filtered = isNumber(input) ? moment.utc(parseInt(input, 10)).tz(timezone).format(gaUtilsDate.getCurrentDateFormatString() + " " + gaUtilsDate.getCurrentTimeFormat()) : input; | |
break; | |
case "timedate": | |
filtered = isNumber(input) ? moment.utc(parseInt(input, 10)).tz(timezone).format(gaUtilsDate.getCurrentTimeFormat() + " (" + gaUtilsDate.getCurrentDateFormatString() + ")") : input; | |
break; | |
case "unixdate": | |
filtered = isNumber(input) ? moment.utc(1e3 * parseInt(input, 10)).format(gaUtilsDate.getCurrentDateFormatString()) : input; | |
break; | |
case "unixdatetime": | |
filtered = isNumber(input) ? moment.utc(1e3 * parseInt(input, 10)).tz(timezone).format(gaUtilsDate.getCurrentDateFormatString() + " " + gaUtilsDate.getCurrentTimeFormat()) : input; | |
break; | |
case "rawdate": | |
filtered = isNumber(input) ? moment.utc(parseInt(input, 10)).format("YYYY-MM-DD") : input; | |
break; | |
case "rawdatetime": | |
filtered = isNumber(input) ? moment.utc(parseInt(input, 10)).format("YYYY-MM-DD HH:mm:ss") : input; | |
break; | |
case "session_length": | |
var tmp = input.split("-"); | |
filtered = 2 === tmp.length ? tmp[1] ? parseInt(tmp[0], 10) / 60 + " - " + parseInt(tmp[1], 10) / 60 + " min" + ("60" === tmp[1] ? "." : "s.") : "> " + parseInt(tmp[0], 10) / 60 + " mins." : input; | |
break; | |
case "session_count": | |
filtered = input + " session" + ("1" === input || 1 === input ? "" : "s"); | |
break; | |
case "dimension": | |
filtered = gaApiMeta.getDimension(input).title; | |
break; | |
case "country": | |
filtered = gaApiMeta.getCountry(input); | |
break; | |
case "cohort_week": | |
input = parseInt(input, 10); | |
var week = Math.floor(input / 7); | |
filtered = "Week " + week + " - day " + (input % 7 + 1); | |
break; | |
case "cohort_week_weekly": | |
input = parseInt(input, 10), filtered = "Week " + input; | |
break; | |
case "cohort_month": | |
input = parseInt(input, 10); | |
var month = Math.floor(input / 28); | |
filtered = "Month " + month + " - day " + (input % 28 + 1); | |
break; | |
case "cohort_month_monthly": | |
input = parseInt(input, 10), filtered = "Month " + input; | |
break; | |
default: | |
filtered = angular.isNumber(input) ? $filter("gaNumberFormat")(input) : input | |
} | |
return filtered === defaultValue ? filtered : (noFix ? "" : unit.preFix || "") + (unit.preUnit || "") + filtered + (ignoreFixUnit ? "" : unit.postUnit || "") + (noFix ? "" : unit.postFix || "") | |
} | |
}).filter("formatMetricNameSingle", function(gaApiMeta) { | |
return gaApiMeta.getMetricDisplay | |
}).factory("gaApiMeta", function() { | |
var dimensions = { | |
area: { | |
title: "Area" | |
}, | |
build: { | |
title: "Build" | |
}, | |
cohort: { | |
title: "Cohort", | |
children: !0 | |
}, | |
cohort_month: { | |
title: "Month", | |
parent: "cohort", | |
type: "unixdate" | |
}, | |
cohort_week: { | |
title: "Week", | |
parent: "cohort", | |
type: "unixdate" | |
}, | |
country: { | |
title: "Country", | |
type: "country" | |
}, | |
install_ad: { | |
title: "Ad", | |
parent: "acquisition" | |
}, | |
install_adgroup: { | |
title: "Ad Group", | |
parent: "acquisition" | |
}, | |
install_campaign: { | |
title: "Campaign", | |
parent: "acquisition" | |
}, | |
install_keyword: { | |
title: "Keyword", | |
parent: "acquisition" | |
}, | |
install_publisher: { | |
title: "Publisher", | |
parent: "acquisition" | |
}, | |
install_site: { | |
title: "Site", | |
parent: "acquisition" | |
}, | |
is_paying: { | |
title: "Paying Users" | |
}, | |
acquisition: { | |
title: "Acquisition", | |
children: !0 | |
}, | |
origin: { | |
title: "Source", | |
parent: "acquisition" | |
}, | |
platform: { | |
title: "Platform" | |
}, | |
device: { | |
title: "Device" | |
}, | |
os_version: { | |
title: "OS Version" | |
}, | |
_default: { | |
type: "dimension", | |
isDefault: !0 | |
}, | |
paying: { | |
title: "Paying" | |
}, | |
not_paying: { | |
title: "Non-Paying" | |
}, | |
organic: { | |
title: "Organic" | |
}, | |
severity: { | |
title: "Severity", | |
hidden: !0, | |
values: { | |
critical: { | |
title: "Critical" | |
}, | |
error: { | |
title: "Error" | |
}, | |
warning: { | |
title: "Warning" | |
} | |
} | |
}, | |
sdk_version: { | |
title: "SDK Version", | |
hidden: !0 | |
}, | |
category: { | |
title: "Category", | |
hidden: !0 | |
} | |
}, | |
getDimension = function(dimension, value) { | |
var meta = angular.copy(dimensions[dimension] || dimensions._default); | |
return meta.type = meta.type || "dimension", meta.name = dimension, meta.unit = dimension, meta.title = meta.title || dimension, meta.hidden = meta.hidden || !1, meta.parent && (meta.parent = getDimension(meta.parent)), value && (meta.title = meta.values[value] && meta.values[value].title || value), meta | |
}, | |
units = { | |
user: { | |
title: "Users", | |
postUnit: "", | |
postFix: " Users" | |
}, | |
session: { | |
title: "Sessions", | |
postUnit: "", | |
postFix: " Sessions" | |
}, | |
install: { | |
title: "Installs", | |
postUnit: "", | |
postFix: " Installs" | |
}, | |
event: { | |
title: "Events", | |
postUnit: "", | |
postFix: " Events" | |
}, | |
money: { | |
title: "Money", | |
preUnit: "$" | |
}, | |
percent: { | |
title: "Percent", | |
postUnit: "%", | |
postFix: "%" | |
}, | |
second: { | |
title: "Seconds", | |
postUnit: "s", | |
postFix: " seconds" | |
}, | |
minute: { | |
title: "Minutes", | |
postUnit: "m", | |
postFix: " minutes" | |
}, | |
hour: { | |
title: "Hours", | |
postUnit: "h", | |
postFix: " hours" | |
}, | |
transaction: { | |
postFix: " Transactions" | |
}, | |
FPS: { | |
title: "FPS", | |
postFix: " FPS" | |
}, | |
_default: { | |
title: "", | |
isDefault: !0 | |
} | |
}, | |
getUnit = function(unit) { | |
return units[unit] || units._default | |
}, | |
meta = { | |
operations: { | |
returning_users: { | |
title: "Returning users", | |
description: "", | |
aggregation: ["mean", "sum"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
installs: { | |
title: "New users", | |
description: "", | |
aggregation: ["mean", "sum"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
revenue: { | |
title: "Revenue", | |
description: "", | |
aggregation: ["mean", "sum"], | |
currency: !0, | |
axisY: { | |
unit: "money", | |
type: "number" | |
} | |
}, | |
converting_users: { | |
title: "Conversion to paying", | |
description: "", | |
aggregation: ["mean", "sum"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
error_count: { | |
title: "Error Events", | |
description: "", | |
aggregation: ["event_count"], | |
axisY: { | |
unit: "event", | |
type: "number" | |
} | |
}, | |
concurrent_users: { | |
title: "Concurrent Users", | |
description: "", | |
aggregation: ["sum"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
event_count: { | |
title: "Incoming Events", | |
description: "", | |
aggregation: ["event_count"], | |
axisY: { | |
unit: "event", | |
type: "number" | |
} | |
}, | |
rejected_events: { | |
title: "Rejected Events", | |
description: "", | |
aggregation: ["event_count"], | |
axisY: { | |
unit: "event", | |
type: "number" | |
} | |
}, | |
session_count: { | |
title: "Active Sessions", | |
description: "", | |
aggregation: ["sum"], | |
axisY: { | |
unit: "session", | |
type: "number" | |
} | |
}, | |
_default: { | |
title: "", | |
description: "", | |
aggregation: ["mean", "sum"], | |
axisY: { | |
unit: "none", | |
type: "number" | |
} | |
} | |
}, | |
core: { | |
ARPDAU: { | |
title: "ARPDAU", | |
description: "Average revenue per daily active user", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
currency: !0, | |
axisY: { | |
type: "number", | |
unit: "money" | |
} | |
}, | |
ARPPU: { | |
title: "ARPPU", | |
description: "Average revenue per paying user", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
currency: !0, | |
axisY: { | |
type: "number", | |
unit: "money" | |
} | |
}, | |
DAU: { | |
title: "DAU", | |
description: "Unique number of users in a day", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
MAU: { | |
title: "MAU", | |
description: "Unique number of monthly users", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
ignore_rollup: !0, | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
WAU: { | |
title: "WAU", | |
description: "Unique number of weekly users", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
ignore_rollup: !0, | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
churn_28: { | |
title: "Churn", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
converting_users: { | |
title: "Conversion to paying", | |
description: "First time purchase", | |
aggregation: ["mean", "sum"], | |
available_aggregations: ["mean", "sum"], | |
axisY: { | |
type: "number", | |
unit: "user" | |
} | |
}, | |
conversion: { | |
title: "Conversion rate", | |
description: "First time purchase", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
type: "percent", | |
unit: "percent" | |
} | |
}, | |
event_count: { | |
title: "Event count", | |
description: "", | |
aggregation: ["event_count"], | |
available_aggregations: ["event_count"], | |
axisY: { | |
unit: "event", | |
type: "number" | |
} | |
}, | |
installs: { | |
title: "New users", | |
description: "", | |
aggregation: ["mean", "sum"], | |
available_aggregations: ["mean", "sum"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
paying_users: { | |
title: "Paying Users", | |
description: "Number of paying users of DAU", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_week: { | |
title: "Returning users (first week)", | |
description: "", | |
aggregation: ["mean", "sum"], | |
available_aggregations: ["mean", "sum"], | |
groupValues: !0, | |
groupValuesUnit: "", | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users: { | |
title: "Returning users", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
groupValues: !0, | |
groupValuesUnit: "", | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_1: { | |
parent: "returning_users", | |
title: "Day 1", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_2: { | |
parent: "returning_users", | |
title: "Day 2", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_3: { | |
parent: "returning_users", | |
title: "Day 3", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_4: { | |
parent: "returning_users", | |
title: "Day 4", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_5: { | |
parent: "returning_users", | |
title: "Day 5", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_6: { | |
parent: "returning_users", | |
title: "Day 6", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_7: { | |
parent: "returning_users", | |
title: "Day 7", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_14: { | |
parent: "returning_users", | |
title: "Day 14", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_28: { | |
parent: "returning_users", | |
title: "Day 28", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_30: { | |
parent: "returning_users", | |
title: "Day 30", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
returning_users_90: { | |
parent: "returning_users", | |
title: "Day 90", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
retention: { | |
title: "Retention", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
groupValues: !0, | |
groupValuesUnit: "", | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_1: { | |
parent: "retention", | |
title: "Day 1", | |
description: "", | |
aggregation: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_2: { | |
parent: "retention", | |
title: "Day 2", | |
description: "", | |
aggregation: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_3: { | |
parent: "retention", | |
title: "Day 3", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_4: { | |
parent: "retention", | |
title: "Day 4", | |
description: "", | |
aggregation: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_5: { | |
parent: "retention", | |
title: "Day 5", | |
description: "", | |
aggregation: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_6: { | |
parent: "retention", | |
title: "Day 6", | |
description: "", | |
aggregation: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_7: { | |
parent: "retention", | |
title: "Day 7", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_10: { | |
parent: "retention", | |
title: "Day 10", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_11: { | |
parent: "retention", | |
title: "Day 11", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_12: { | |
parent: "retention", | |
title: "Day 12", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_13: { | |
parent: "retention", | |
title: "Day 13", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_14: { | |
parent: "retention", | |
title: "Day 14", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_15: { | |
parent: "retention", | |
title: "Day 15", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_16: { | |
parent: "retention", | |
title: "Day 16", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_17: { | |
parent: "retention", | |
title: "Day 17", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_18: { | |
parent: "retention", | |
title: "Day 18", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_19: { | |
parent: "retention", | |
title: "Day 19", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_20: { | |
parent: "retention", | |
title: "Day 20", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_21: { | |
parent: "retention", | |
title: "Day 21", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_22: { | |
parent: "retention", | |
title: "Day 22", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_23: { | |
parent: "retention", | |
title: "Day 23", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_24: { | |
parent: "retention", | |
title: "Day 24", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_25: { | |
parent: "retention", | |
title: "Day 25", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_26: { | |
parent: "retention", | |
title: "Day 26", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_27: { | |
parent: "retention", | |
title: "Day 27", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_28: { | |
parent: "retention", | |
title: "Day 28", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_29: { | |
parent: "retention", | |
title: "Day 29", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_30: { | |
parent: "retention", | |
title: "Day 30", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_90: { | |
parent: "retention", | |
title: "Day 90", | |
description: "", | |
aggregation: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
retention_120: { | |
parent: "retention", | |
title: "Day 120", | |
description: "", | |
aggregation: ["mean"], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
returning: { | |
title: "Returning users", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "user", | |
type: "number" | |
} | |
}, | |
transactions: { | |
title: "Transactions", | |
eventCountTitle: "Transactions", | |
alias: "revenue", | |
description: "", | |
aggregation: ["event_count"], | |
available_aggregations: ["event_count"], | |
currency: !0, | |
axisY: { | |
unit: "transaction", | |
type: "number" | |
}, | |
eventCountUnit: { | |
unit: "transaction", | |
type: "number" | |
} | |
}, | |
revenue: { | |
title: "Revenue per transaction", | |
description: "", | |
aggregation: ["mean", "sum"], | |
available_aggregations: ["mean", "sum"], | |
currency: !0, | |
axisY: { | |
unit: "money", | |
type: "number" | |
} | |
}, | |
stickiness: { | |
title: "DAU/MAU Ratio", | |
available_aggregations: ["mean"], | |
description: "", | |
aggregation: [], | |
axisY: { | |
unit: "percent", | |
type: "percent" | |
} | |
}, | |
session_length: { | |
title: "Session length", | |
description: "", | |
aggregation: ["histogram"], | |
available_aggregations: ["mean", "sum"], | |
groupValues: !0, | |
groupTime: !1, | |
histogram: !0, | |
noSort: !0, | |
keyUnit: "session_length", | |
axisY: { | |
unit: "session", | |
unitTitle: "Sessions", | |
type: "number" | |
} | |
}, | |
session_length_mean: { | |
title: "Avg. session length", | |
description: "", | |
aggregation: ["mean"], | |
available_aggregations: ["mean"], | |
axisY: { | |
unit: "second", | |
unitTitle: "Seconds", | |
type: "second" | |
} | |
}, | |
session_count: { | |
title: "Session count", | |
description: "", | |
aggregation: ["histogram"], | |
available_aggregations: ["mean", "sum"], | |
groupValues: !0, | |
groupTime: !1, | |
histogram: !0, | |
noSort: !0, | |
keyUnit: "session_count", | |
axisY: { | |
unit: "user", | |
unitTitle: "Users", | |
type: "number" | |
} | |
}, | |
session_count_sum: { | |
hidden: !0, | |
title: "Session count SUM", | |
description: "", | |
aggregation: ["sum"], | |
axisY: { | |
unit: "session", | |
type: "number" | |
} | |
}, | |
session_count_mean: { | |
title: "Session count mean", | |
description: "", | |
aggregation: ["mean"], | |
axisY: { | |
unit: "session", | |
type: "number" | |
} | |
}, | |
_default: { | |
title: "", | |
description: "", | |
aggregation: [], | |
axisY: { | |
unit: "event", | |
type: "number" | |
}, | |
isDefault: !0 | |
} | |
}, | |
design: { | |
_default: { | |
axisY: { | |
unit: "none", | |
type: "number" | |
}, | |
aggregation: ["mean", "sum", "event_count"], | |
available_aggregations: ["mean", "sum", "event_count"] | |
}, | |
"GA:AverageFPS": { | |
title: "Average FPS", | |
eventCountTitle: "Average FPS Events", | |
axisY: { | |
unit: "FPS", | |
unitTitle: "FPS", | |
type: "number" | |
}, | |
aggregation: ["mean", "event_count"], | |
available_aggregations: ["mean", "event_count"] | |
}, | |
"GA:CriticalFPS": { | |
title: "Critical FPS Events", | |
axisY: { | |
unit: "none", | |
type: "number" | |
}, | |
aggregation: ["event_count"], | |
available_aggregations: ["event_count"] | |
} | |
}, | |
business: { | |
_default: { | |
axisY: { | |
unit: "money", | |
type: "number" | |
}, | |
aggregation: ["mean", "sum", "event_count"], | |
available_aggregations: ["mean", "sum", "event_count"], | |
currency: !0 | |
} | |
}, | |
quality: { | |
_default: { | |
axisY: { | |
unit: "none", | |
type: "number" | |
}, | |
aggregation: ["mean", "sum", "event_count"] | |
} | |
}, | |
error: { | |
_default: { | |
aggregation: ["mean", "sum", "event_count"], | |
axisY: { | |
unit: "none", | |
type: "number" | |
} | |
}, | |
"users_affected_by:.*": { | |
title: "Users affected by Error events", | |
description: "", | |
aggregation: ["sum"], | |
axisY: { | |
unit: "user", | |
unitTitle: "Users", | |
type: "number" | |
} | |
}, | |
"event_count_by:.*": { | |
title: "Error events", | |
description: "", | |
aggregation: ["event_count"], | |
axisY: { | |
unit: "event", | |
unitTitle: "Events", | |
type: "number" | |
} | |
}, | |
users_affected_by: { | |
title: "Users affected by Error events", | |
description: "", | |
aggregation: ["sum"], | |
axisY: { | |
unit: "user", | |
unitTitle: "Users", | |
type: "number" | |
} | |
}, | |
event_count_by: { | |
title: "Error events", | |
description: "", | |
aggregation: ["event_count"], | |
axisY: { | |
unit: "event", | |
unitTitle: "Events", | |
type: "number" | |
} | |
}, | |
"users_affected_by:critical": { | |
title: "Users affected by critical", | |
description: "", | |
aggregation: ["sum"], | |
axisY: { | |
unit: "user", | |
unitTitle: "Users", | |
type: "number" | |
} | |
}, | |
"users_affected_by:error": { | |
title: "Users affected by error", | |
description: "", | |
aggregation: ["sum"], | |
axisY: { | |
unit: "user", | |
unitTitle: "Users", | |
type: "number" | |
} | |
}, | |
"users_affected_by:warning": { | |
title: "Users affected by warning", | |
description: "", | |
aggregation: ["sum"], | |
axisY: { | |
unit: "user", | |
unitTitle: "Users", | |
type: "number" | |
} | |
}, | |
"event_count_by:critical": { | |
title: "Critical events", | |
description: "", | |
aggregation: ["event_count"], | |
axisY: { | |
unit: "event", | |
unitTitle: "Events", | |
type: "number" | |
} | |
}, | |
"event_count_by:error": { | |
title: "Error events", | |
description: "", | |
aggregation: ["event_count"], | |
axisY: { | |
unit: "event", | |
unitTitle: "Events", | |
type: "number" | |
} | |
}, | |
"event_count_by:warning": { | |
title: "Warning events", | |
description: "", | |
aggregation: ["event_count"], | |
axisY: { | |
unit: "event", | |
unitTitle: "Events", | |
type: "number" | |
} | |
} | |
}, | |
_default: { | |
axisY: { | |
unit: "none", | |
type: "number" | |
} | |
} | |
}, | |
parseMeta = function(fMeta, metric, dimension) { | |
return fMeta = angular.copy(fMeta), fMeta.title || (fMeta.title = metric.split(":").pop()), dimension && (fMeta.title = dimension), fMeta.displayTitle = fMeta.title.split(":").pop(), ".*" === fMeta.displayTitle && (fMeta.displayTitle = metric.split(":").slice(-2)[0] + ":" + fMeta.displayTitle), fMeta | |
}, | |
getMetricArray = function(category, event, getAll) { | |
var selectionArray = [], | |
events = []; | |
if (event) events = event.split(":"); | |
else { | |
var tmp = category.split(":"); | |
category = tmp[0].toLowerCase(), events = tmp.slice(1) | |
}!getAll && events.pop(), selectionArray.push({ | |
value: category.charAt(0).toUpperCase() + category.slice(1), | |
title: category.charAt(0).toUpperCase() + category.slice(1) | |
}); | |
for (var i = 0; i < events.length; i++) selectionArray.push({ | |
value: events[i], | |
title: getMetric(category, events.slice(0, i + 1).join(":")).title | |
}); | |
return selectionArray | |
}, | |
getMetricDisplay = function(category, event, singleEvent) { | |
var events = []; | |
if (category) { | |
if (angular.isObject(category) && (singleEvent = event, event = category.event, category = category.category), event) events = event.split(":"); | |
else { | |
var tmp = category.split(":"); | |
category = tmp[0].toLowerCase(), events = tmp.slice(1) | |
} | |
var eventsDisplay = angular.copy(events); | |
if (singleEvent) { | |
var dis = ""; | |
return dis = ".*" === eventsDisplay[eventsDisplay.length - 1] ? getMetric(category, events.slice(0, events.length - 1).join(":")).title + " > All (.*)" : getMetric(category, events.slice(0, events.length).join(":")).title | |
} | |
for (var i = 0; i < events.length; i++) eventsDisplay[i] = ".*" === events[i] ? "All (.*)" : getMetric(category, events.slice(0, i + 1).join(":")).title; | |
var display = category.charAt(0).toUpperCase() + category.slice(1) + " > " + eventsDisplay.join(" > "); | |
return display | |
} | |
}, | |
getMetric = function(category, metric, subEvent) { | |
var returnMeta; | |
if ("object" == typeof category && (subEvent = metric, metric = category.event, category = category.category), "error" === category && "stacktrace" === metric.substr(0, 10) && (metric = "Occurences"), returnMeta = angular.copy(meta[category] ? meta[category][metric] ? meta[category][metric] : meta[category]._default : meta._default), returnMeta.axisX = returnMeta.axisX || { | |
type: "date", | |
unit: "date", | |
title: "Date" | |
}, subEvent) { | |
var subMeta = getMetric(category, subEvent); | |
subEvent = subMeta.title | |
} | |
var tmp = parseMeta(returnMeta, metric, subEvent); | |
return tmp.category = category, tmp.event = metric, tmp.eventCountTitle = tmp.eventCountTitle || tmp.displayTitle, tmp.starEvent = ".*" === metric.split(":").slice(-1)[0], tmp.starEvent && (tmp.groupValues = !0), tmp | |
}, | |
countries = { | |
AF: "Afghanistan", | |
AX: "Åland Islands", | |
AL: "Albania", | |
DZ: "Algeria", | |
AS: "American Samoa", | |
AD: "Andorra", | |
AO: "Angola", | |
AI: "Anguilla", | |
AQ: "Antarctica", | |
AG: "Antigua and Barbuda", | |
AR: "Argentina", | |
AM: "Armenia", | |
AW: "Aruba", | |
AU: "Australia", | |
AT: "Austria", | |
AZ: "Azerbaijan", | |
BS: "Bahamas", | |
BH: "Bahrain", | |
BD: "Bangladesh", | |
BB: "Barbados", | |
BY: "Belarus", | |
BE: "Belgium", | |
BZ: "Belize", | |
BJ: "Benin", | |
BM: "Bermuda", | |
BT: "Bhutan", | |
BO: "Bolivia, Plurinational State of", | |
BQ: "Bonaire, Sint Eustatius and Saba", | |
BA: "Bosnia and Herzegovina", | |
BW: "Botswana", | |
BV: "Bouvet Island", | |
BR: "Brazil", | |
IO: "British Indian Ocean Territory", | |
BN: "Brunei Darussalam", | |
BG: "Bulgaria", | |
BF: "Burkina Faso", | |
BI: "Burundi", | |
KH: "Cambodia", | |
CM: "Cameroon", | |
CA: "Canada", | |
CV: "Cape Verde", | |
KY: "Cayman Islands", | |
CF: "Central African Republic", | |
TD: "Chad", | |
CL: "Chile", | |
CN: "China", | |
CX: "Christmas Island", | |
CC: "Cocos (Keeling) Islands", | |
CO: "Colombia", | |
KM: "Comoros", | |
CG: "Congo", | |
CD: "Congo, the Democratic Republic of the", | |
CK: "Cook Islands", | |
CR: "Costa Rica", | |
CI: "Côte d´Ivoire", | |
HR: "Croatia", | |
CU: "Cuba", | |
CW: "Curaçao", | |
CY: "Cyprus", | |
CZ: "Czech Republic", | |
DK: "Denmark", | |
DJ: "Djibouti", | |
DM: "Dominica", | |
DO: "Dominican Republic", | |
EC: "Ecuador", | |
EG: "Egypt", | |
SV: "El Salvador", | |
GQ: "Equatorial Guinea", | |
ER: "Eritrea", | |
EE: "Estonia", | |
ET: "Ethiopia", | |
FK: "Falkland Islands (Malvinas)", | |
FO: "Faroe Islands", | |
FJ: "Fiji", | |
FI: "Finland", | |
FR: "France", | |
GF: "French Guiana", | |
PF: "French Polynesia", | |
TF: "French Southern Territories", | |
GA: "Gabon", | |
GM: "Gambia", | |
GE: "Georgia", | |
DE: "Germany", | |
GH: "Ghana", | |
GI: "Gibraltar", | |
GR: "Greece", | |
GL: "Greenland", | |
GD: "Grenada", | |
GP: "Guadeloupe", | |
GU: "Guam", | |
GT: "Guatemala", | |
GG: "Guernsey", | |
GN: "Guinea", | |
GW: "Guinea-Bissau", | |
GY: "Guyana", | |
HT: "Haiti", | |
HM: "Heard Island and McDonald Islands", | |
VA: "Holy See (Vatican City State)", | |
HN: "Honduras", | |
HK: "Hong Kong", | |
HU: "Hungary", | |
IS: "Iceland", | |
IN: "India", | |
ID: "Indonesia", | |
IR: "Iran, Islamic Republic of", | |
IQ: "Iraq", | |
IE: "Ireland", | |
IM: "Isle of Man", | |
IL: "Israel", | |
IT: "Italy", | |
JM: "Jamaica", | |
JP: "Japan", | |
JE: "Jersey", | |
JO: "Jordan", | |
KZ: "Kazakhstan", | |
KE: "Kenya", | |
KI: "Kiribati", | |
KP: "Korea, Democratic People´s Republic of", | |
KR: "Korea, Republic of", | |
KW: "Kuwait", | |
KG: "Kyrgyzstan", | |
LA: "Lao People´s Democratic Republic", | |
LV: "Latvia", | |
LB: "Lebanon", | |
LS: "Lesotho", | |
LR: "Liberia", | |
LY: "Libya", | |
LI: "Liechtenstein", | |
LT: "Lithuania", | |
LU: "Luxembourg", | |
MO: "Macao", | |
MK: "Macedonia, the former Yugoslav Republic of", | |
MG: "Madagascar", | |
MW: "Malawi", | |
MY: "Malaysia", | |
MV: "Maldives", | |
ML: "Mali", | |
MT: "Malta", | |
MH: "Marshall Islands", | |
MQ: "Martinique", | |
MR: "Mauritania", | |
MU: "Mauritius", | |
YT: "Mayotte", | |
MX: "Mexico", | |
FM: "Micronesia, Federated States of", | |
MD: "Moldova, Republic of", | |
MC: "Monaco", | |
MN: "Mongolia", | |
ME: "Montenegro", | |
MS: "Montserrat", | |
MA: "Morocco", | |
MZ: "Mozambique", | |
MM: "Myanmar", | |
NA: "Namibia", | |
NR: "Nauru", | |
NP: "Nepal", | |
NL: "Netherlands", | |
NC: "New Caledonia", | |
NZ: "New Zealand", | |
NI: "Nicaragua", | |
NE: "Niger", | |
NG: "Nigeria", | |
NU: "Niue", | |
NF: "Norfolk Island", | |
MP: "Northern Mariana Islands", | |
NO: "Norway", | |
OM: "Oman", | |
PK: "Pakistan", | |
PW: "Palau", | |
PS: "Palestinian Territory, Occupied", | |
PA: "Panama", | |
PG: "Papua New Guinea", | |
PY: "Paraguay", | |
PE: "Peru", | |
PH: "Philippines", | |
PN: "Pitcairn", | |
PL: "Poland", | |
PT: "Portugal", | |
PR: "Puerto Rico", | |
QA: "Qatar", | |
RE: "Réunion", | |
RO: "Romania", | |
RU: "Russia", | |
RW: "Rwanda", | |
BL: "Saint Barthélemy", | |
SH: "Saint Helena, Ascension and Tristan da Cunha", | |
KN: "Saint Kitts and Nevis", | |
LC: "Saint Lucia", | |
MF: "Saint Martin (French part)", | |
PM: "Saint Pierre and Miquelon", | |
VC: "Saint Vincent and the Grenadines", | |
WS: "Samoa", | |
SM: "San Marino", | |
ST: "Sao Tome and Principe", | |
SA: "Saudi Arabia", | |
SN: "Senegal", | |
RS: "Serbia", | |
SC: "Seychelles", | |
SL: "Sierra Leone", | |
SG: "Singapore", | |
SX: "Sint Maarten (Dutch part)", | |
SK: "Slovakia", | |
SI: "Slovenia", | |
SB: "Solomon Islands", | |
SO: "Somalia", | |
ZA: "South Africa", | |
GS: "South Georgia and the South Sandwich Islands", | |
SS: "South Sudan", | |
ES: "Spain", | |
LK: "Sri Lanka", | |
SD: "Sudan", | |
SR: "Suriname", | |
SJ: "Svalbard and Jan Mayen", | |
SZ: "Swaziland", | |
SE: "Sweden", | |
CH: "Switzerland", | |
SY: "Syrian Arab Republic", | |
TW: "Taiwan, Republic of China", | |
TJ: "Tajikistan", | |
TZ: "Tanzania, United Republic of", | |
TH: "Thailand", | |
TL: "Timor-Leste", | |
TG: "Togo", | |
TK: "Tokelau", | |
TO: "Tonga", | |
TT: "Trinidad and Tobago", | |
TN: "Tunisia", | |
TR: "Turkey", | |
TM: "Turkmenistan", | |
TC: "Turks and Caicos Islands", | |
TV: "Tuvalu", | |
UG: "Uganda", | |
UA: "Ukraine", | |
AE: "United Arab Emirates", | |
GB: "United Kingdom", | |
US: "United States", | |
UM: "United States Minor Outlying Islands", | |
UY: "Uruguay", | |
UZ: "Uzbekistan", | |
VU: "Vanuatu", | |
VE: "Venezuela, Bolivarian Republic of", | |
VN: "Vietnam", | |
VG: "Virgin Islands, British", | |
VI: "Virgin Islands, U.S.", | |
WF: "Wallis and Futuna", | |
EH: "Western Sahara", | |
YE: "Yemen", | |
ZM: "Zambia", | |
ZW: "Zimbabwe" | |
}, | |
getCountry = function(shortCode) { | |
return countries[shortCode] || shortCode | |
}, | |
currenciesList = ["AED", "AFN", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD", "BIF", "BMD", "BND", "BOB", "BRL", "BSD", "BTC", "BTN", "BWP", "BYR", "BZD", "CAD", "CDF", "CHF", "CLF", "CLP", "CNY", "COP", "CRC", "CUP", "CVE", "CZK", "DJF", "DKK", "DOP", "DZD", "EEK", "EGP", "ETB", "EUR", "FJD", "FKP", "GBP", "GEL", "GHS", "GIP", "GMD", "GNF", "GTQ", "GYD", "HKD", "HNL", "HRK", "HTG", "HUF", "IDR", "ILS", "INR", "IQD", "IRR", "ISK", "JEP", "JMD", "JOD", "JPY", "KES", "KGS", "KHR", "KMF", "KPW", "KRW", "KWD", "KYD", "KZT", "LAK", "LBP", "LKR", "LRD", "LSL", "LTL", "LVL", "LYD", "MAD", "MDL", "MGA", "MKD", "MMK", "MNT", "MOP", "MRO", "MTL", "MUR", "MVR", "MWK", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR", "PAB", "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SBD", "SCR", "SDG", "SEK", "SGD", "SHP", "SLL", "SOS", "SRD", "STD", "SVC", "SYP", "SZL", "THB", "TJS", "TMT", "TND", "TOP", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "UZS", "VEF", "VND", "VUV", "WST", "XAF", "XAG", "XAU", "XCD", "XDR", "XOF", "XPF", "YER", "ZAR", "ZMK", "ZMW", "ZWL"], | |
currencies = { | |
USD: { | |
symbol: "$", | |
name: "US Dollar" | |
}, | |
CAD: { | |
symbol: "CA$", | |
name: "Canadian Dollar" | |
}, | |
EUR: { | |
symbol: "€", | |
name: "Euro" | |
}, | |
AED: { | |
symbol: "AED", | |
name: "United Arab Emirates Dirham" | |
}, | |
AFN: { | |
symbol: "Af", | |
name: "Afghan Afghani" | |
}, | |
ALL: { | |
symbol: "ALL", | |
name: "Albanian Lek" | |
}, | |
AMD: { | |
symbol: "AMD", | |
name: "Armenian Dram" | |
}, | |
ARS: { | |
symbol: "AR$", | |
name: "Argentine Peso" | |
}, | |
AUD: { | |
symbol: "AU$", | |
name: "Australian Dollar" | |
}, | |
AZN: { | |
symbol: "man.", | |
name: "Azerbaijani Manat" | |
}, | |
BAM: { | |
symbol: "KM", | |
name: "Bosnia-Herzegovina Convertible Mark" | |
}, | |
BDT: { | |
symbol: "Tk", | |
name: "Bangladeshi Taka" | |
}, | |
BGN: { | |
symbol: "BGN", | |
name: "Bulgarian Lev" | |
}, | |
BHD: { | |
symbol: "BD", | |
name: "Bahraini Dinar" | |
}, | |
BIF: { | |
symbol: "FBu", | |
name: "Burundian Franc" | |
}, | |
BND: { | |
symbol: "BN$", | |
name: "Brunei Dollar" | |
}, | |
BOB: { | |
symbol: "Bs", | |
name: "Bolivian Boliviano" | |
}, | |
BRL: { | |
symbol: "R$", | |
name: "Brazilian Real" | |
}, | |
BWP: { | |
symbol: "BWP", | |
name: "Botswanan Pula" | |
}, | |
BYR: { | |
symbol: "BYR", | |
name: "Belarusian Ruble" | |
}, | |
BZD: { | |
symbol: "BZ$", | |
name: "Belize Dollar" | |
}, | |
CDF: { | |
symbol: "CDF", | |
name: "Congolese Franc" | |
}, | |
CHF: { | |
symbol: "CHF", | |
name: "Swiss Franc" | |
}, | |
CLP: { | |
symbol: "CL$", | |
name: "Chilean Peso" | |
}, | |
CNY: { | |
symbol: "CN¥", | |
name: "Chinese Yuan" | |
}, | |
COP: { | |
symbol: "CO$", | |
name: "Colombian Peso" | |
}, | |
CRC: { | |
symbol: "₡", | |
name: "Costa Rican Colón" | |
}, | |
CVE: { | |
symbol: "CV$", | |
name: "Cape Verdean Escudo" | |
}, | |
CZK: { | |
symbol: "Kč", | |
name: "Czech Republic Koruna" | |
}, | |
DJF: { | |
symbol: "Fdj", | |
name: "Djiboutian Franc" | |
}, | |
DKK: { | |
symbol: "Dkr", | |
name: "Danish Krone" | |
}, | |
DOP: { | |
symbol: "RD$", | |
name: "Dominican Peso" | |
}, | |
DZD: { | |
symbol: "DA", | |
name: "Algerian Dinar" | |
}, | |
EEK: { | |
symbol: "Ekr", | |
name: "Estonian Kroon" | |
}, | |
EGP: { | |
symbol: "EGP", | |
name: "Egyptian Pound" | |
}, | |
ERN: { | |
symbol: "Nfk", | |
name: "Eritrean Nakfa" | |
}, | |
ETB: { | |
symbol: "Br", | |
name: "Ethiopian Birr" | |
}, | |
GBP: { | |
symbol: "£", | |
name: "British Pound Sterling" | |
}, | |
GEL: { | |
symbol: "GEL", | |
name: "Georgian Lari" | |
}, | |
GHS: { | |
symbol: "GH₵", | |
name: "Ghanaian Cedi" | |
}, | |
GNF: { | |
symbol: "FG", | |
name: "Guinean Franc" | |
}, | |
GTQ: { | |
symbol: "GTQ", | |
name: "Guatemalan Quetzal" | |
}, | |
HKD: { | |
symbol: "HK$", | |
name: "Hong Kong Dollar" | |
}, | |
HNL: { | |
symbol: "HNL", | |
name: "Honduran Lempira" | |
}, | |
HRK: { | |
symbol: "kn", | |
name: "Croatian Kuna" | |
}, | |
HUF: { | |
symbol: "Ft", | |
name: "Hungarian Forint" | |
}, | |
IDR: { | |
symbol: "Rp", | |
name: "Indonesian Rupiah" | |
}, | |
ILS: { | |
symbol: "₪", | |
name: "Israeli New Sheqel" | |
}, | |
INR: { | |
symbol: "Rs", | |
name: "Indian Rupee" | |
}, | |
IQD: { | |
symbol: "IQD", | |
name: "Iraqi Dinar" | |
}, | |
IRR: { | |
symbol: "IRR", | |
name: "Iranian Rial" | |
}, | |
ISK: { | |
symbol: "Ikr", | |
name: "Icelandic Króna" | |
}, | |
JMD: { | |
symbol: "J$", | |
name: "Jamaican Dollar" | |
}, | |
JOD: { | |
symbol: "JD", | |
name: "Jordanian Dinar" | |
}, | |
JPY: { | |
symbol: "¥", | |
name: "Japanese Yen" | |
}, | |
KES: { | |
symbol: "Ksh", | |
name: "Kenyan Shilling" | |
}, | |
KHR: { | |
symbol: "KHR", | |
name: "Cambodian Riel" | |
}, | |
KMF: { | |
symbol: "CF", | |
name: "Comorian Franc" | |
}, | |
KRW: { | |
symbol: "₩", | |
name: "South Korean Won" | |
}, | |
KWD: { | |
symbol: "KD", | |
name: "Kuwaiti Dinar" | |
}, | |
KZT: { | |
symbol: "KZT", | |
name: "Kazakhstani Tenge" | |
}, | |
LBP: { | |
symbol: "LB£", | |
name: "Lebanese Pound" | |
}, | |
LKR: { | |
symbol: "SLRs", | |
name: "Sri Lankan Rupee" | |
}, | |
LTL: { | |
symbol: "Lt", | |
name: "Lithuanian Litas" | |
}, | |
LVL: { | |
symbol: "Ls", | |
name: "Latvian Lats" | |
}, | |
LYD: { | |
symbol: "LD", | |
name: "Libyan Dinar" | |
}, | |
MAD: { | |
symbol: "MAD", | |
name: "Moroccan Dirham" | |
}, | |
MDL: { | |
symbol: "MDL", | |
name: "Moldovan Leu" | |
}, | |
MGA: { | |
symbol: "MGA", | |
name: "Malagasy Ariary" | |
}, | |
MKD: { | |
symbol: "MKD", | |
name: "Macedonian Denar" | |
}, | |
MMK: { | |
symbol: "MMK", | |
name: "Myanma Kyat" | |
}, | |
MOP: { | |
symbol: "MOP$", | |
name: "Macanese Pataca" | |
}, | |
MUR: { | |
symbol: "MURs", | |
name: "Mauritian Rupee" | |
}, | |
MXN: { | |
symbol: "MX$", | |
name: "Mexican Peso" | |
}, | |
MYR: { | |
symbol: "RM", | |
name: "Malaysian Ringgit" | |
}, | |
MZN: { | |
symbol: "MTn", | |
name: "Mozambican Metical" | |
}, | |
NAD: { | |
symbol: "N$", | |
name: "Namibian Dollar" | |
}, | |
NGN: { | |
symbol: "₦", | |
name: "Nigerian Naira" | |
}, | |
NIO: { | |
symbol: "C$", | |
name: "Nicaraguan Córdoba" | |
}, | |
NOK: { | |
symbol: "Nkr", | |
name: "Norwegian Krone" | |
}, | |
NPR: { | |
symbol: "NPRs", | |
name: "Nepalese Rupee" | |
}, | |
NZD: { | |
symbol: "NZ$", | |
name: "New Zealand Dollar" | |
}, | |
OMR: { | |
symbol: "OMR", | |
name: "Omani Rial" | |
}, | |
PAB: { | |
symbol: "B/.", | |
name: "Panamanian Balboa" | |
}, | |
PEN: { | |
symbol: "S/.", | |
name: "Peruvian Nuevo Sol" | |
}, | |
PHP: { | |
symbol: "₱", | |
name: "Philippine Peso" | |
}, | |
PKR: { | |
symbol: "PKRs", | |
name: "Pakistani Rupee" | |
}, | |
PLN: { | |
symbol: "zł", | |
name: "Polish Zloty" | |
}, | |
PYG: { | |
symbol: "₲", | |
name: "Paraguayan Guarani" | |
}, | |
QAR: { | |
symbol: "QR", | |
name: "Qatari Rial" | |
}, | |
RON: { | |
symbol: "RON", | |
name: "Romanian Leu" | |
}, | |
RSD: { | |
symbol: "din.", | |
name: "Serbian Dinar" | |
}, | |
RUB: { | |
symbol: "RUB", | |
name: "Russian Ruble" | |
}, | |
RWF: { | |
symbol: "RWF", | |
name: "Rwandan Franc" | |
}, | |
SAR: { | |
symbol: "SR", | |
name: "Saudi Riyal" | |
}, | |
SDG: { | |
symbol: "SDG", | |
name: "Sudanese Pound" | |
}, | |
SEK: { | |
symbol: "Skr", | |
name: "Swedish Krona" | |
}, | |
SGD: { | |
symbol: "S$", | |
name: "Singapore Dollar" | |
}, | |
SOS: { | |
symbol: "Ssh", | |
name: "Somali Shilling" | |
}, | |
SYP: { | |
symbol: "SY£", | |
name: "Syrian Pound" | |
}, | |
THB: { | |
symbol: "฿", | |
name: "Thai Baht" | |
}, | |
TND: { | |
symbol: "DT", | |
name: "Tunisian Dinar" | |
}, | |
TOP: { | |
symbol: "T$", | |
name: "Tongan Paʻanga" | |
}, | |
TRY: { | |
symbol: "TL", | |
name: "Turkish Lira" | |
}, | |
TTD: { | |
symbol: "TT$", | |
name: "Trinidad and Tobago Dollar" | |
}, | |
TWD: { | |
symbol: "NT$", | |
name: "New Taiwan Dollar" | |
}, | |
TZS: { | |
symbol: "TSh", | |
name: "Tanzanian Shilling" | |
}, | |
UAH: { | |
symbol: "₴", | |
name: "Ukrainian Hryvnia" | |
}, | |
UGX: { | |
symbol: "USh", | |
name: "Ugandan Shilling" | |
}, | |
UYU: { | |
symbol: "$U", | |
name: "Uruguayan Peso" | |
}, | |
UZS: { | |
symbol: "UZS", | |
name: "Uzbekistan Som" | |
}, | |
VEF: { | |
symbol: "Bs.F.", | |
name: "Venezuelan Bolívar" | |
}, | |
VND: { | |
symbol: "₫", | |
name: "Vietnamese Dong" | |
}, | |
XAF: { | |
symbol: "FCFA", | |
name: "CFA Franc BEAC" | |
}, | |
XOF: { | |
symbol: "CFA", | |
name: "CFA Franc BCEAO" | |
}, | |
YER: { | |
symbol: "YR", | |
name: "Yemeni Rial" | |
}, | |
ZAR: { | |
symbol: "R", | |
name: "South African Rand" | |
}, | |
ZMK: { | |
symbol: "ZK", | |
name: "Zambian Kwacha" | |
}, | |
ZWL: { | |
symbol: "Z$", | |
name: "Zimbabwean Dollar" | |
} | |
}, | |
getCurrency = function(code) { | |
return currencies[code] || { | |
symbol: "", | |
name: code, | |
code: code | |
} | |
}, | |
getCurrencies = function() { | |
return currenciesList | |
}, | |
aggregationTooltips = { | |
design: { | |
sum: 'The sum of all numbers found in the "value" field of the design event.', | |
mean: 'The arithmetic mean of all numbers found in the "value" field.', | |
count: "The number of design events seen, including those events which did not have a value." | |
}, | |
business: { | |
sum: 'The monetary sum of all business events converted into the currency of your choice. The "amount" field sent in the SDK uses cents, while the sum aggregation divides the sum by 100. Virtual currencies are ignored.', | |
mean: 'The arithmetic mean of all business events, converted into the currency of your choice. The "amount" field sent in the SDK uses cents, while the mean aggregation divides the sum by 100. Virtual currencies are ignored.', | |
count: "The number of business events seen." | |
} | |
}, | |
getAggregationTooltip = function(category) { | |
return aggregationTooltips[category] || null | |
}; | |
return { | |
getMetric: getMetric, | |
getMetricDisplay: getMetricDisplay, | |
getMetricArray: getMetricArray, | |
getDimension: getDimension, | |
getUnit: getUnit, | |
getCurrencies: getCurrencies, | |
getCurrency: getCurrency, | |
getCountry: getCountry, | |
getAggregationTooltip: getAggregationTooltip | |
} | |
}), angular.module("ga.api.metric", ["ui.router", "ga.config", "ga.api.data", "ga.api.meta", "ga.components.rollbar"]).factory("gaApiMetric", function($q, $rootScope, $timeout, $stateParams, gaConfig, gaApiMeta, gaApiData, gaComponentsRollbar) { | |
function zerofy(str) { | |
var match = str.match(/\d+$/); | |
if (match) { | |
for (var z = 10 - match[0].length, zstr = "", i = 1; z >= i; i++) zstr += "0"; | |
return str.replace(/(\d+)$/, zstr + "$1") | |
} | |
return str | |
} | |
var getParsedMetricListPromise, metrics = [], | |
reImport = !1, | |
nbOfResults = 0, | |
nbOfResultsSliced = 0, | |
nbOfSearchResults = 0, | |
parsedMetrics = [], | |
currentSelection = [], | |
options = { | |
noCombine: !1, | |
filter: null, | |
searchQuery: "" | |
}, | |
categories = { | |
core: { | |
label: "Core" | |
}, | |
design: { | |
label: "Design" | |
}, | |
quality: { | |
label: "Quality" | |
}, | |
business: { | |
label: "Business" | |
}, | |
error: { | |
label: "Error" | |
} | |
}, | |
activeCategories = [], | |
showStarEvents = !0, | |
getParsedMetricList = function(sMetric, query) { | |
var selectedMetric = angular.copy(sMetric); | |
if (metrics.length && !reImport) getParsedMetricListPromise = $q.defer(), buildMetricList(selectedMetric, query).then(function(obj) { | |
getParsedMetricListPromise.resolve(obj), getParsedMetricListPromise = null | |
}); | |
else { | |
if (getParsedMetricListPromise) return getParsedMetricListPromise.promise; | |
getParsedMetricListPromise = $q.defer(), _getList().then(function() { | |
buildMetricList(selectedMetric, query).then(function(obj) { | |
getParsedMetricListPromise.resolve(obj), getParsedMetricListPromise = null | |
}) | |
}, function() { | |
getParsedMetricListPromise.reject(), getParsedMetricListPromise = null | |
}), reImport = !1 | |
} | |
return getParsedMetricListPromise.promise | |
}, | |
setOptions = function(opts) { | |
options.noCombine = void 0 !== opts.noCombine ? opts.noCombine : !1, void 0 !== opts.filter ? (options.filter = opts.filter, showStarEvents = void 0 !== options.filter.disableStarEvents ? !options.filter.disableStarEvents : !0, activeCategories = [], options.filter.categories ? activeCategories = options.filter.categories : angular.forEach(categories, function(cat) { | |
activeCategories.push(cat.label.toLowerCase()) | |
})) : (options.filter = null, showStarEvents = !0, activeCategories = [], angular.forEach(categories, function(cat) { | |
activeCategories.push(cat.label.toLowerCase()) | |
})), reImport = !0, currentSelection = [] | |
}, | |
getMetricHierarchy = function(metric) { | |
var deferred = $q.defer(); | |
if (metrics.length) { | |
var metricInfo = _getMetricHierarchy(metric); | |
deferred.resolve(metricInfo) | |
} else getParsedMetricList().then(function() { | |
if (metrics.length) { | |
var metricInfo = _getMetricHierarchy(metric); | |
deferred.resolve(metricInfo) | |
} else deferred.reject() | |
}); | |
return deferred.promise | |
}, | |
getMetricInfo = function(metric) { | |
var deferred = $q.defer(); | |
if (metrics.length) { | |
var childEvents = _hasChildEvents(metric); | |
deferred.resolve({ | |
hasChildEvents: childEvents | |
}) | |
} else getParsedMetricList().then(function() { | |
if (metrics.length) { | |
var childEvents = _hasChildEvents(metric); | |
deferred.resolve({ | |
hasChildEvents: childEvents | |
}) | |
} else deferred.reject() | |
}); | |
return deferred.promise | |
}, | |
_hasChildEvents = function(qMetric) { | |
var queryMetric = angular.copy(qMetric), | |
hasChildEvents = !1; | |
if (queryMetric.event.indexOf(".*") > -1) hasChildEvents = !0; | |
else { | |
var metricStr = queryMetric.category + ":" + queryMetric.event, | |
regExpr = new RegExp("^" + metricStr + ":([^:]*)", "i"); | |
metrics.forEach(function(metric) { | |
var match = (metric.fullEvent.match(regExpr) || [])[1]; | |
match && (hasChildEvents = !0) | |
}) | |
} | |
return hasChildEvents | |
}, | |
_getMetricHierarchy = function(qMetric) { | |
var queryMetric = angular.copy(qMetric), | |
returnArr = [], | |
metricStr = queryMetric.category + ":" + queryMetric.event, | |
arrMetric = metricStr.split(":"), | |
hasChildEvents = _hasChildEvents(qMetric); | |
queryMetric.event.indexOf(".*") > -1 && arrMetric.pop(), returnArr.push({ | |
name: queryMetric.category.charAt(0).toUpperCase() + queryMetric.category.slice(1), | |
title: queryMetric.category.charAt(0).toUpperCase() + queryMetric.category.slice(1), | |
event: null | |
}), arrMetric.shift(); | |
var prevEventStr = ""; | |
return angular.forEach(arrMetric, function(evt, index) { | |
var eventStr = evt; | |
eventStr && (prevEventStr && (eventStr = prevEventStr + ":" + eventStr), prevEventStr = angular.copy(eventStr), index === arrMetric.length - 1 ? -1 === queryMetric.event.indexOf(".*") ? eventStr = null : hasChildEvents && (eventStr += ":.*") : eventStr += ":.*"), returnArr.push({ | |
name: evt, | |
title: gaApiMeta.getMetric(queryMetric.category, prevEventStr).title, | |
event: eventStr | |
}) | |
}), returnArr | |
}, | |
buildMetricList = function(selectedMetric, query) { | |
var deferred = $q.defer(); | |
if (metrics.length) { | |
var cEvent; | |
options.searchQuery = query || !1, angular.isArray(selectedMetric) ? currentSelection = selectedMetric : angular.isObject(selectedMetric) && (cEvent = options.filter && options.filter.customEventList ? selectedMetric.event : selectedMetric.category + ":" + selectedMetric.event, currentSelection = []), _parseMetrics(cEvent).then(function() { | |
deferred.resolve({ | |
nbOfResults: nbOfResults, | |
nbOfResultsSliced: nbOfResultsSliced, | |
metrics: parsedMetrics, | |
selected: currentSelection, | |
nbOfSearchResults: nbOfSearchResults | |
}) | |
}) | |
} else deferred.reject(); | |
return deferred.promise | |
}, | |
_parseCategory = function(rawData, category, each) { | |
var data = rawData[category], | |
metrics = []; | |
return angular.forEach(data, function(event) { | |
var include = !0; | |
if ("function" == typeof each && (include = each(category, event)), include) { | |
var selectable = !0; | |
options && options.filter && options.filter.blacklisted && options.filter.blacklisted.indexOf(category + ":" + event) > -1 && (selectable = !1); | |
var meta = gaApiMeta.getMetric(category, event); | |
metrics.push({ | |
category: category, | |
event: event, | |
selectable: selectable, | |
title: meta.title, | |
fullEvent: categories[category].label + ":" + event | |
}) | |
} | |
}), metrics | |
}, | |
_getList = function() { | |
var deferred = $q.defer(); | |
return metrics = [], options.filter && options.filter.customEventList ? (_parseCustomData(options.filter.customEventList), deferred.resolve()) : gaApiData.getValue("/metrics", $stateParams.gameId).then(function(rawData) { | |
_parseRawData(rawData), deferred.resolve() | |
}, function(response) { | |
response.error && "no_game_api_key" === response.error ? deferred.reject() : deferred.reject("error") | |
}), deferred.promise | |
}, | |
_parseCustomData = function(data) { | |
angular.forEach(data, function(event) { | |
var category = event.split(":")[0], | |
meta = gaApiMeta.getMetric(category, event); | |
metrics.push({ | |
category: category, | |
event: event, | |
selectable: !0, | |
title: meta.title, | |
fullEvent: event | |
}) | |
}) | |
}, | |
_parseRawData = function(rawData) { | |
rawData.core = rawData.core || [], rawData.core.push("transactions"), angular.forEach(rawData.core, function(event) { | |
var meta; | |
if (options.noCombine) { | |
if (meta = gaApiMeta.getMetric("core", event), meta.parent) { | |
var parentMeta = gaApiMeta.getMetric("core", meta.parent); | |
meta.title = parentMeta.title + " - " + meta.title | |
} | |
} else { | |
if ("returning_users_1" === event && (event = "returning_users"), event.indexOf("returning_users_") > -1 && event.indexOf("returning_users_week") < 0) return; | |
if ("retention_3" === event && (event = "retention"), event.indexOf("retention_") > -1) return; | |
meta = gaApiMeta.getMetric("core", event) | |
} if (!meta.hidden) { | |
if (!gaConfig.showNoMetaMetrics && meta.isDefault) return; | |
var selectable = !0; | |
if (options && options.filter && (options.filter.groupTime && meta.groupTime === !1 && (selectable = !1), options.filter.blacklisted && options.filter.blacklisted.indexOf(event) > -1)) return; | |
metrics.push({ | |
category: "core", | |
event: event, | |
title: meta.title, | |
fullEvent: categories.core.label + ":" + event, | |
selectable: selectable | |
}) | |
} | |
}), metrics = metrics.concat(_parseCategory(rawData, "design")), metrics = metrics.concat(_parseCategory(rawData, "quality", function() { | |
return gaConfig.showQualityEvents | |
})), metrics = metrics.concat(_parseCategory(rawData, "business")), metrics = metrics.concat(_parseCategory(rawData, "error", function(category, event) { | |
return "stacktrace" !== event.substr(0, 10) | |
})), metrics.sort(function(a, b) { | |
var x = zerofy(a.title || a.fullEvent), | |
y = zerofy(b.title || b.fullEvent); | |
return y > x ? -1 : x > y ? 1 : 0 | |
}) | |
}, | |
_parseMetrics = function(fullEvent) { | |
var deferred = $q.defer(); | |
fullEvent && (currentSelection = options.filter && options.filter.customEventList ? fullEvent.split(":").slice(0, -1).map(function(val) { | |
return { | |
title: val, | |
value: val | |
} | |
}) : gaApiMeta.getMetricArray(fullEvent)); | |
var rootArray = [], | |
checkList = {}, | |
list = []; | |
if (angular.forEach(currentSelection, function(value) { | |
rootArray.push(value.value) | |
}), !options.searchQuery) return getTree(rootArray.join(":")).then(function(parsed) { | |
if (rootArray.length && "core" !== rootArray[0].toLowerCase() && (angular.forEach(parsed, function(metric) { | |
metric.hasChildEvents && parsed.push({ | |
label: metric.label, | |
hasChildEvents: !1, | |
event: metric.event, | |
selectable: metric.singleEventSelectable, | |
category: metric.category | |
}) | |
}), parsed.sort(function(a, b) { | |
var a1 = a.hasChildEvents ? 0 : 1, | |
b1 = b.hasChildEvents ? 0 : 1, | |
a2 = zerofy(a.event.toLowerCase()), | |
b2 = zerofy(b.event.toLowerCase()); | |
return b1 > a1 ? -1 : a1 > b1 ? 1 : b2 > a2 ? -1 : a2 > b2 ? 1 : 0 | |
}), rootArray.length > 1 && showStarEvents)) { | |
var event = rootArray.slice(1).join(":"); | |
parsed.unshift({ | |
selectAll: !0, | |
label: '.* Select all "' + event + '"', | |
hasChildEvents: !1, | |
selectable: !0, | |
event: event ? event + ":.*" : ".*", | |
category: rootArray[0].toLowerCase() | |
}) | |
} | |
nbOfResults = parsed.length; | |
var tmpMetrics = []; | |
parsed.some(function(evt) { | |
(!evt.category && activeCategories.indexOf(evt.event.toLowerCase()) > -1 || evt.category && activeCategories.indexOf(evt.category.toLowerCase()) > -1) && tmpMetrics.push(evt) | |
}), tmpMetrics && tmpMetrics.length > 2500 && gaComponentsRollbar.putCustom({ | |
level: "critical", | |
msg: "More than 2500 metrics in same level", | |
point: { | |
error: "Too many metrics in same level", | |
data: "" | |
} | |
}); | |
var parsedSliced = tmpMetrics.slice(0, 2500); | |
nbOfResultsSliced = parsedSliced.length, parsedMetrics = parsedSliced, deferred.resolve() | |
}), deferred.promise; | |
var searchQuery = !1; | |
options.searchQuery && (searchQuery = sanitizeRegExp(rootArray.join(":")), searchQuery += "(.*?)", searchQuery += sanitizeRegExp(options.searchQuery).replace(/\s/g, "[\\s|:]"), searchQuery = new RegExp(searchQuery, "i")); | |
var rootResultCount = 0; | |
if (rootArray.length && searchQuery) { | |
var query = new RegExp(sanitizeRegExp(options.searchQuery).replace(/\s/g, "[\\s|:]"), "i"); | |
rootResultCount = metrics.filter(function(item) { | |
return query.test(item.event) | |
}).length | |
} | |
var regExpr = new RegExp(rootArray.length ? "^" + rootArray.join(":") + ":([^:]*)" : "([^:]*)", "i"); | |
metrics.forEach(function(metric) { | |
var match = (metric.fullEvent.match(regExpr) || [])[1], | |
found = match && searchQuery ? searchQuery.test(metric.fullEvent) || searchQuery.test(metric.title) : !0; | |
if (found && match && !checkList[match]) { | |
checkList[match] = searchQuery ? !1 : !0; | |
var hasChildEvents = !1, | |
hasChildEventsPattern = new RegExp((rootArray.length ? sanitizeRegExp(rootArray.join(":")) + ":" : "") + match + ":"); | |
hasChildEvents = searchQuery || ".*" === match ? !1 : metric.fullEvent.match(hasChildEventsPattern); | |
var label = searchQuery ? gaApiMeta.getMetricDisplay(metric.fullEvent) : match; | |
if (list.push({ | |
event: hasChildEvents ? !1 : metric.event, | |
label: label, | |
labelNoHtml: label, | |
hasChildEvents: hasChildEvents, | |
selectable: metric.selectable, | |
category: metric.category | |
}), hasChildEvents && metric.event) { | |
var tmpEvent = metric.fullEvent.split(":"); | |
tmpEvent.length > 1 | |
} | |
} | |
}), rootResultCount -= list.length, rootResultCount = 0 > rootResultCount ? 0 : rootResultCount, nbOfSearchResults = rootResultCount; | |
var slicedList = list.slice(0, 2500); | |
return parsedMetrics = slicedList, deferred.resolve(), deferred.promise | |
}, | |
getTree = function(match) { | |
var deferred = $q.defer(), | |
level = (match ? match.split(":").length : 0) + 1, | |
tmpMetrics = []; | |
if (match) { | |
var pattern = new RegExp("^" + sanitizeRegExp(match) + "[$|:.*]"); | |
tmpMetrics = metrics.filter(function(metric) { | |
var include = metric.fullEvent.match(pattern) && metric.fullEvent.split(":").length === level; | |
return include | |
}), $timeout(function() { | |
tmpMetrics = tmpMetrics.map(function(metric) { | |
if (void 0 === metric.hasChildEvents) { | |
var hasChildEventsPattern = new RegExp("^" + sanitizeRegExp(metric.fullEvent) + "\\:"), | |
hasChildEvents = metrics.some(function(metric) { | |
return metric.fullEvent.match(hasChildEventsPattern) | |
}); | |
metric.hasChildEvents = hasChildEvents | |
} | |
return { | |
label: metric.title || metric.event.split(":").pop(), | |
category: metric.category, | |
event: metric.event, | |
selectable: metric.hasChildEvents ? !0 : metric.selectable, | |
singleEventSelectable: metric.selectable, | |
hasChildEvents: metric.hasChildEvents | |
} | |
}), deferred.resolve(tmpMetrics) | |
}, tmpMetrics.length > 1e3 ? 100 : 0) | |
} else metrics.some(function(metric) { | |
return "core" === metric.category | |
}) && tmpMetrics.push({ | |
event: "Core", | |
label: "Core", | |
hasChildEvents: !0, | |
selectable: !0 | |
}), metrics.some(function(metric) { | |
return "design" === metric.category | |
}) && tmpMetrics.push({ | |
event: "Design", | |
label: "Design", | |
hasChildEvents: !0, | |
selectable: !0 | |
}), metrics.some(function(metric) { | |
return "quality" === metric.category | |
}) && tmpMetrics.push({ | |
event: "Quality", | |
label: "Quality", | |
hasChildEvents: !0, | |
selectable: !0 | |
}), metrics.some(function(metric) { | |
return "business" === metric.category | |
}) && tmpMetrics.push({ | |
event: "Business", | |
label: "Business", | |
hasChildEvents: !0, | |
selectable: !0 | |
}), metrics.some(function(metric) { | |
return "error" === metric.category | |
}) && tmpMetrics.push({ | |
event: "Error", | |
label: "Error", | |
hasChildEvents: !0, | |
selectable: !0 | |
}), options.filter && options.filter.customEventList && angular.forEach(metrics, function(metric) { | |
if (void 0 === metric.hasChildEvents) { | |
var hasChildEventsPattern = new RegExp("^" + sanitizeRegExp(metric.fullEvent) + "\\:"), | |
hasChildEvents = metrics.some(function(metric) { | |
return metric.fullEvent.match(hasChildEventsPattern) | |
}); | |
metric.hasChildEvents = hasChildEvents | |
}(metric.hasChildEvents && 1 === metric.event.split(":").length || metric.category === metric.event) && tmpMetrics.push({ | |
label: metric.title || metric.event.split(":").pop(), | |
category: metric.category, | |
event: metric.event, | |
selectable: metric.hasChildEvents ? !0 : metric.selectable, | |
singleEventSelectable: metric.selectable, | |
hasChildEvents: metric.hasChildEvents | |
}) | |
}), deferred.resolve(tmpMetrics); | |
return deferred.promise | |
}, | |
sanitizeRegExp = function(string) { | |
return string.replace(/[\?\(\)\[\]\$\^\:\.]/g, "\\$&") | |
}, | |
getMetric = function(metricPath) { | |
var deferred = $q.defer(); | |
if (metrics.length) { | |
var metric = _getMetric(metricPath); | |
deferred.resolve(metric ? metric : null) | |
} else getParsedMetricList().then(function() { | |
if (metrics.length) { | |
var metric = _getMetric(metricPath); | |
deferred.resolve(metric ? metric : null) | |
} else deferred.resolve(null) | |
}); | |
return deferred.promise | |
}, | |
_getMetric = function(metricPath) { | |
var found = null; | |
return metrics.some(function(metric) { | |
return metricPath === metric.event ? (found = metric, !0) : void 0 | |
}), found | |
}; | |
return { | |
getParsedMetricList: getParsedMetricList, | |
setOptions: setOptions, | |
getMetricHierarchy: getMetricHierarchy, | |
getMetricInfo: getMetricInfo, | |
getMetric: getMetric | |
} | |
}), angular.module("ga.api.userDb", ["ga.config", "ga.values.user", "ga.api.userDb.mock"]).factory("gaApiUserDb", function($http, $q, $timeout, gaConfig, gaValuesUser, gaApiUserDbMock) { | |
var getConfig = function() { | |
var config = { | |
headers: {} | |
}; | |
return gaValuesUser.token && (config.headers["X-Authorization"] = gaValuesUser.token), config | |
}, | |
_validateData = function(data, single) { | |
return "object" == typeof data && angular.isArray(data.errors) && angular.isArray(data.results) || (data = { | |
errors: [{ | |
id: "invalidResponse", | |
msg: "Response is not valid", | |
data: data | |
}], | |
results: [] | |
}), data.errors.length ? $q.reject(data.errors) : $q.when(single ? data.results[0] : data.results) | |
}, | |
_request = function(type, url, data, config, raw) { | |
return config = config || getConfig(), gaApiUserDbMock.request.apply(gaApiUserDbMock, Array.prototype.slice.call(arguments)).then(function(response) { | |
return raw ? $q.when(response) : _validateData(response) | |
}).catch(function() { | |
url = gaConfig.userApi.baseUrl + url, data = data || null; | |
var args = ["get", "delete", "head"].indexOf(type) > -1 ? [url, config] : [url, data, config]; | |
return $http[type].apply($http, args).catch(function(response) { | |
return raw ? $q.reject(response.data) : _validateData(response.data) | |
}).then(function(response) { | |
return raw ? $q.when(response.data) : _validateData(response.data) | |
}) | |
}) | |
}, | |
upload = function(url, file, progressCallback) { | |
var config = getConfig(), | |
deferred = $q.defer(), | |
fd = new FormData; | |
fd.append("image", file), config && config.headers && config.headers["X-Authorization"] && fd.append("X-Authorization", config.headers["X-Authorization"]); | |
var xhr = new XMLHttpRequest; | |
return "function" == typeof progressCallback && xhr.upload.addEventListener("progress", function(e) { | |
if (e.lengthComputable) { | |
var percent = e.loaded / e.total || 0; | |
progressCallback(percent) | |
} | |
}, !1), xhr.addEventListener("load", function(e) { | |
var response = {}; | |
try { | |
response = JSON.parse(e.target.responseText) | |
} catch (e) {} | |
deferred.resolve(_validateData(response, !0)) | |
}, !1), xhr.addEventListener("error", function() { | |
deferred.reject("An error occured") | |
}, !1), xhr.addEventListener("abort", function() { | |
deferred.reject("Upload was cancelled") | |
}, !1), xhr.open("POST", url), xhr.setRequestHeader("Authorization", gaValuesUser.token), xhr.send(fd), deferred.promise | |
}, | |
copyFile = function(fileUrl) { | |
var payload = { | |
fileUrl: fileUrl | |
}; | |
return put("upload/image", payload) | |
}, | |
get = _request.bind(this, "get"), | |
post = _request.bind(this, "post"), | |
put = _request.bind(this, "put"), | |
update = _request.bind(this, "put"), | |
remove = _request.bind(this, "delete"); | |
return { | |
upload: upload, | |
copyFile: copyFile, | |
post: post, | |
get: get, | |
put: put, | |
update: update, | |
remove: remove, | |
getConfig: getConfig, | |
_validateData: _validateData | |
} | |
}), angular.module("ga.api.userDb.mock", ["ga.config", "ga.values.user", "ga.api.userDb.public.user"]).service("gaApiUserDbMock", function($q, $injector, gaConfig, gaValuesUser) { | |
var replyJson = function(results, errors) { | |
return { | |
results: results ? angular.isArray(results) ? results : [results] : [], | |
errors: errors ? angular.isArray(errors) ? errors : [errors] : [] | |
} | |
}, | |
getData = function(url, fallback) { | |
var store = {}; | |
try { | |
store = JSON.parse(localStorage.getItem("gaUserLocalStore")) || {} | |
} catch (e) {} | |
return store[url] || fallback || null | |
}, | |
putData = function(url, data) { | |
var store = {}; | |
try { | |
store = JSON.parse(localStorage.getItem("gaUserLocalStore")) || {} | |
} catch (e) {} | |
store[url] = data, localStorage.setItem("gaUserLocalStore", JSON.stringify(store)) | |
}; | |
this.replyJson = replyJson, this.getData = getData, this.putData = putData, this.request = function(type, url, data) { | |
if (url.match(/^public/)) return $q.reject(); | |
if ("user/data" === url && gaValuesUser.activated === !1) return $injector.get("gaApiUserDbPublicUser").getData(gaValuesUser.token).then(function(result) { | |
return result.onboarding = getData("user/onboarding", result.onboarding), result.settings = getData("user/settings", result.settings), $q.when(replyJson(result)) | |
}); | |
var gameId, dashboardId, useMock = !gaValuesUser.activated; | |
if ((gameId = url.match(/games\/([0-9]+)/)) ? (gameId = parseInt(gameId[1] || null), useMock = (gaValuesUser.game(gameId) || {}).demo) : (dashboardId = url.match(/([0-9]+-demo)/)) && (useMock = !0, dashboardId = dashboardId[1]), !useMock) return $q.reject(); | |
if (mocks[type] && useMock) { | |
var route = null, | |
match = null; | |
if (mocks[type].some(function(r) { | |
return match = url.match(new RegExp(r.path)), match ? (route = r, !0) : void 0 | |
}), route && match) { | |
var results = "function" == typeof route.results ? route.results.apply(this, [data].concat(match.slice(1))) : route.results; | |
return $q.when(route.raw ? results : replyJson(results)) | |
} | |
} | |
return $q.reject() | |
}; | |
var mocks = { | |
get: [{ | |
path: "data_api/status/processing", | |
results: replyJson([]) | |
}, { | |
path: "games/([0-9]+)/dashboards/sortorder", | |
results: function() { | |
var data = getData("user/dashboards/sortorder", []); | |
return { | |
results: data, | |
errors: [] | |
} | |
}, | |
raw: !0 | |
}, { | |
path: "games/([0-9]+)/dashboards", | |
results: function() { | |
return getData("user/dashboards/dashboards", []) | |
} | |
}, { | |
path: "api/games/([0-9]+)/has/heatmap", | |
results: { | |
errors: [], | |
results: [], | |
heatmaps: !0 | |
}, | |
raw: !0 | |
}, { | |
path: "games/([0-9]+)/heatmap/settings", | |
results: { | |
errors: [], | |
results: [{ | |
gameId: 7165, | |
heatmap_skey: "3fc6d0597a73fe28c80962b3bfcfedeb93adddef", | |
heatmap_dkey: "afc969bda35dfa5bbba69922bcf73309324e89b6", | |
heatmap_key: "183609b5aeb121013eb395f559fd9199", | |
settings: { | |
selectedSet: 0, | |
sets: [{ | |
selectedHeatmap: 0, | |
name: "Heatmap 1", | |
area: "Level 1", | |
heatmaps: [{ | |
settingsExpanded: !0, | |
uid: "1395236473-10038", | |
selectedColor: "1", | |
dateRange: { | |
main: { | |
start: null, | |
end: null | |
} | |
}, | |
selectedEvents: [{ | |
category: "Level 1", | |
type: "add", | |
name: "Level 1:Kill" | |
}], | |
name: "Heatmap", | |
selectedBuild: null, | |
visible: 1, | |
range: { | |
max: 100, | |
min: 0 | |
}, | |
radius: 10, | |
selectedRender: "0" | |
}], | |
mesh: null, | |
id: 0 | |
}] | |
}, | |
shared: !1, | |
initial_load: !1, | |
createdDate: "2014-03-19T13:41:05", | |
userId: null, | |
id: 1, | |
editedDate: "2014-03-26T08:40:44" | |
}] | |
}, | |
raw: !0 | |
}, { | |
path: "games/([0-9]+)/dashboards", | |
results: function() { | |
return getData("user/dashboards/dashboards", []) | |
} | |
}, { | |
path: "dashboards/([0-9]+)-demo", | |
results: function(o, id) { | |
var dashboards = getData("user/dashboards/dashboards", []), | |
found = null; | |
return dashboards && dashboards.length && dashboards.some(function(d) { | |
d.id === id + "-demo" && (found = d) | |
}), found.locked = !1, found | |
} | |
}, { | |
path: "games/([0-9]+)/queries", | |
results: function() { | |
return [getData("user/explore/queries", [])] | |
} | |
}], | |
put: [{ | |
path: "user/onboarding", | |
results: function(data) { | |
return putData("user/onboarding", data), [] | |
} | |
}, { | |
path: "user/settings", | |
results: function(data) { | |
return putData("user/settings", data), [] | |
} | |
}, { | |
path: "games/([0-9]+)/dashboards/sortorder", | |
results: function(data) { | |
return putData("user/dashboards/sortorder", data.sortorder), [] | |
} | |
}, { | |
path: "games/([0-9]+)/dashboards", | |
results: function(data) { | |
if (0 === data.id) { | |
data.id = Math.floor(1e4 * Math.random()) + "-demo"; | |
var cdashboards = getData("user/dashboards/dashboards", []); | |
if (data.widgets && data.widgets.length) | |
for (var i = 0, max = data.widgets.length; max > i; i++) data.widgets[i].id = i; | |
cdashboards.push(data), putData("user/dashboards/dashboards", cdashboards) | |
} else { | |
var dashboards = getData("user/dashboards/dashboards", []), | |
found = null; | |
dashboards && dashboards.length && (dashboards.some(function(d) { | |
return d.id === data.id ? (found = d, !0) : void 0 | |
}), found && (found = data)), putData("user/dashboards/dashboards", dashboards) | |
} | |
return data.locked = !1, data | |
} | |
}, { | |
path: "games/([0-9]+)/heatmap/settings", | |
results: replyJson([]) | |
}, { | |
path: "dashboards/([0-9]+)-demo/lock", | |
results: function(o, id) { | |
var dashboards = getData("user/dashboards/dashboards", []), | |
found = null; | |
return dashboards && dashboards.length && dashboards.some(function(d) { | |
return d.id === id + "-demo" ? (found = d, !0) : void 0 | |
}), found.locked = !0, found | |
} | |
}, { | |
path: "dashboards/([0-9]+)-demo/unlock", | |
results: function(o, id) { | |
var dashboards = getData("user/dashboards/dashboards", []), | |
found = null; | |
return dashboards && dashboards.length && dashboards.some(function(d) { | |
return d.id === id + "-demo" ? (found = d, !0) : void 0 | |
}), found.locked = !1, found | |
} | |
}, { | |
path: "dashboards/([0-9]+)-demo", | |
results: function(data) { | |
var dashboards = getData("user/dashboards/dashboards", []); | |
if (dashboards && dashboards.length) { | |
var cleanedDashboards = []; | |
dashboards.some(function(d) { | |
if (d.id === data.id) { | |
if (data.widgets && data.widgets.length) | |
for (var i = 0, max = data.widgets.length; max > i; i++) data.widgets[i].id = i; | |
d = data | |
} | |
cleanedDashboards.push(d) | |
}), putData("user/dashboards/dashboards", cleanedDashboards) | |
} | |
return data.locked = !1, data | |
} | |
}, { | |
path: "games/([0-9]+)/queries", | |
results: function(data) { | |
var queries = getData("user/explore/queries", []), | |
saveObj = { | |
id: Math.floor(1e4 * Math.random()) + "-demo", | |
name: data.name, | |
saveInterval: data.saveInterval, | |
query_data: { | |
global: data.global, | |
yAxis: data.yAxis | |
} | |
}; | |
return queries.push(saveObj), putData("user/explore/queries", queries), saveObj | |
} | |
}], | |
post: [{ | |
path: "", | |
results: [] | |
}], | |
"delete": [{ | |
path: "dashboards/([0-9]+)-demo", | |
results: function(o, id) { | |
var dashboards = getData("user/dashboards/dashboards", []); | |
if (dashboards && dashboards.length) { | |
var cleanedDashboards = []; | |
dashboards.some(function(d) { | |
d.id !== id + "-demo" && cleanedDashboards.push(d) | |
}), putData("user/dashboards/dashboards", cleanedDashboards) | |
} | |
return [] | |
} | |
}, { | |
path: "queries/([0-9]+)-demo", | |
results: function(o, id) { | |
var queries = getData("user/explore/queries", []); | |
if (queries && queries.length) { | |
var cleanedQueries = []; | |
queries.some(function(d) { | |
d.id !== id + "-demo" && cleanedQueries.push(d) | |
}), putData("user/explore/queries", cleanedQueries) | |
} | |
return [] | |
} | |
}], | |
head: [{ | |
path: "", | |
results: [] | |
}] | |
} | |
}), angular.module("ga.api.userDb.authenticated.dashboard", ["ui.router", "ga.api.userDb", "ga.utils.helpers", "ga.services.user", "ga.services.announcement", "ga.ui.notify"]).service("gaApiUserDbAuthenticatedDashboards", function($q, $http, $stateParams, gaApiUserDb, gaHelpers, gaServicesUser) { | |
var sortDashboards = function(customSortList, a, b) { | |
var sortOrderA = customSortList.indexOf(a.id), | |
sortOrderB = customSortList.indexOf(b.id); | |
return a.sortOrder = sortOrderA > -1 ? sortOrderA : a.sortOrder, b.sortOrder = sortOrderB > -1 ? sortOrderB : b.sortOrder, a.sortOrder === b.sortOrder ? 0 : a.sortOrder > b.sortOrder ? 1 : -1 | |
}; | |
this.sortDashboards = sortDashboards; | |
var staticDashboards = null; | |
this.dashboards = {}, this.getStaticDashboards = function() { | |
if (staticDashboards) return $q.when(staticDashboards); | |
var url = "/static/ga-app/modules/api/user-db/authenticated/dashboard.json"; | |
return $http.get(url).then(function(response) { | |
return staticDashboards = gaHelpers.copy(response.data), $q.when(staticDashboards) | |
}) | |
}, this.getGameDashboards = function(gameId) { | |
gameId = gameId || $stateParams.gameId; | |
var url = "games/" + gameId + "/dashboards"; | |
return gaApiUserDb.get(url) | |
}, this.getGameDashboardsSortOrder = function(gameId) { | |
gameId = gameId || $stateParams.gameId; | |
var url = "games/" + gameId + "/dashboards/sortorder"; | |
return gaApiUserDb.get(url) | |
}, this.getDashboards = function(gameId) { | |
return gameId = gameId || $stateParams.gameId, this.dashboards[gameId] ? $q.when(this.dashboards[gameId]) : $q.all({ | |
"static": this.getStaticDashboards(), | |
game: this.getGameDashboards(gameId), | |
sort: this.getGameDashboardsSortOrder(gameId) | |
}).then(function(results) { | |
return this.dashboards[gameId] = results.static.concat(results.game).sort(sortDashboards.bind(this, results.sort)), $q.when(this.dashboards[gameId]) | |
}.bind(this)) | |
}, this.sortOrder = function(gameId) { | |
return gameId = gameId || $stateParams.gameId, (this.dashboards[gameId] || []).map(function(dashboard) { | |
return dashboard.id | |
}) | |
}, this.lock = function(dashboardId, unlock) { | |
var url = "dashboards/" + dashboardId + "/" + (unlock ? "unlock" : "lock"); | |
return gaApiUserDb.put(url).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this._getDashboard = function(dashboardId) { | |
if (isNaN(parseInt(dashboardId, 10))) { | |
var found; | |
return staticDashboards.some(function(dashboard) { | |
return dashboard.id === dashboardId ? (found = dashboard, !0) : void 0 | |
}), found ? $q.when(found) : $q.reject([{ | |
msg: "Dashboard not found" | |
}]) | |
} | |
var url = "dashboards/" + dashboardId; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.getDashboard = function(dashboardId) { | |
return this._getDashboard(dashboardId).then(function(dashboard) { | |
return dashboard.widgets.forEach(function(widget) { | |
widget.statusObject = { | |
state: "init" | |
}, widget.trackerId = dashboardId + "-" + widget.id | |
}), $q.when(dashboard) | |
}) | |
}, this.saveDashboardsOrder = function(sortOrderList, gameId) { | |
var url = "games/" + gameId + "/dashboards/sortorder", | |
payload = { | |
sortorder: sortOrderList | |
}; | |
return gaApiUserDb.put(url, payload).then(function(results) { | |
return this.dashboards[gameId] = null, $q.when(results[0] || null) | |
}.bind(this)) | |
}, this.saveDashboard = function(dashboard, gameId) { | |
var url; | |
return url = dashboard.id ? "dashboards/" + dashboard.id : "games/" + gameId + "/dashboards", gaApiUserDb.put(url, dashboard).then(function(results) { | |
return this.dashboards[gameId] = null, $q.when(results[0] || null) | |
}.bind(this)) | |
}, this.deleteDashboard = function(dashboardId, gameId) { | |
var url = "dashboards/" + dashboardId; | |
return gaApiUserDb.remove(url).then(function(results) { | |
return this.dashboards[gameId] = null, $q.when(results[0] || null) | |
}.bind(this)) | |
}, this.resolve = function(stateParams) { | |
var params = gaHelpers.copy(stateParams), | |
isStatic = !1; | |
params.dashboardId = parseInt(stateParams.dashboardId, 10), params.dashboardId !== params.dashboardId && (isStatic = !0, params.dashboardId = stateParams.dashboardId), (stateParams.dashboardId || "").toString().match(/-demo$/) && (params.dashboardId = stateParams.dashboardId); | |
var dashboard; | |
return this.dashboards[params.gameId].some(function(d) { | |
return params.dashboardId === d.id ? (dashboard = d, !0) : void 0 | |
}), "edit" === params.action && 0 === params.dashboardId ? (dashboard = !0, $q.when()) : dashboard ? isStatic && "edit" === params.action ? (params.action = "show", $q.reject(params)) : isStatic || "intro" !== params.action ? isStatic && "show" === params.action && !gaServicesUser.onboarding.dashboard[params.dashboardId] ? (params.action = "intro", $q.reject(params)) : "edit" === params.action && params.dashboardId ? this.lock(params.dashboardId).catch(function() { | |
return params.action = "show", $q.reject(params) | |
}) : $q.when(dashboard) : (params.action = "show", $q.reject(params)) : (params.action = "show", params.dashboardId = "engagement", $q.reject(params)) | |
}.bind(this) | |
}), angular.module("ga.api.userDb.authenticated.query", ["ga.api.userDb", "ui.router"]).factory("gaApiUserDbAuthenticatedQuery", function($q, $http, $state, gaApiUserDb) { | |
var getQueryList = function() { | |
var gameId = $state.params.gameId, | |
url = "games/" + gameId + "/queries"; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, | |
saveQuery = function(queryObj) { | |
var gameId = $state.params.gameId, | |
url = "games/" + gameId + "/queries"; | |
return gaApiUserDb.put(url, queryObj).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, | |
deleteQuery = function(queryId) { | |
var url = "queries/" + queryId; | |
return gaApiUserDb.remove(url).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, | |
getQuery = function(queryId) { | |
var url = "queries/" + queryId; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}; | |
return { | |
getQueryList: getQueryList, | |
saveQuery: saveQuery, | |
deleteQuery: deleteQuery, | |
getQuery: getQuery | |
} | |
}), angular.module("ga.api.userDb.authenticated.heatmap", ["ui.router", "ga.api.userDb"]).factory("gaApiUserDbAuthenticatedHeatmap", function($q, $state, $http, gaApiUserDb) { | |
var getSettings = function(gameId) { | |
var url = "games/" + gameId + "/heatmap/settings"; | |
return gaApiUserDb.get(url).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, | |
putSettings = function(gameId, settings) { | |
var url = "games/" + gameId + "/heatmap/settings"; | |
return gaApiUserDb.put(url, settings).then(function(results) { | |
return $q.when(results) | |
}) | |
}, | |
authHeatmap = function(gameId, firsttime) { | |
var deferred = $q.defer(), | |
rejectFunc = function(nodata) { | |
deferred.reject(nodata), nodata ? $state.go("game.heatmap-nodata", { | |
gameId: gameId | |
}) : $state.go("game.heatmap-firsttime", { | |
gameId: gameId | |
}) | |
}; | |
return gaApiUserDb.get("data_api/games/" + gameId + "/has/heatmap", null, null, !0).then(function(response) { | |
response.errors.length > 0 || !response.heatmaps ? rejectFunc(!0) : firsttime ? deferred.resolve() : gaApiUserDb.get("games/" + gameId + "/heatmap/settings").then(function(data) { | |
if (void 0 !== data[0] && data[0].initial_load) rejectFunc(!1); | |
else { | |
var settings = data[0].settings; | |
void 0 !== settings && void 0 !== settings.sets ? (settings.keys = { | |
gamekey: data[0].heatmap_key, | |
secretkey: data[0].heatmap_skey, | |
apikey: data[0].heatmap_dkey | |
}, settings.gameId = data[0].gameId, deferred.resolve(settings)) : rejectFunc(!1) | |
} | |
}, function() { | |
rejectFunc(!1) | |
}) | |
}, rejectFunc), deferred.promise | |
}; | |
return { | |
authHeatmap: authHeatmap, | |
getSettings: getSettings, | |
putSettings: putSettings | |
} | |
}), angular.module("ga.api.userDb.authenticated.invite", ["ga.api.userDb"]).service("gaApiUserDbAuthenticatedInvite", function($q, $timeout, gaApiUserDb) { | |
this.accept = function(invite) { | |
var service = invite.type + "_access/" + invite.id + "/accept_decline", | |
payload = { | |
action: "accept" | |
}; | |
return gaApiUserDb.put(service, payload) | |
}, this.decline = function(invite) { | |
var service = invite.type + "_access/" + invite.id + "/accept_decline", | |
payload = { | |
action: "decline" | |
}; | |
return gaApiUserDb.put(service, payload) | |
}, this.delete = function(invite) { | |
var service = invite.type + "_access/" + invite.id; | |
return gaApiUserDb.remove(service) | |
}, this.change = function(invite) { | |
var payload = { | |
role_id: invite.role | |
}, | |
service = invite.type + "_access/" + invite.id; | |
return gaApiUserDb.put(service, payload) | |
} | |
}), angular.module("ga.api.userDb.authenticated.user", ["ga.api.userDb"]).service("gaApiUserDbAuthenticatedUser", function($q, gaApiUserDb) { | |
this.supportToken = function() { | |
return gaApiUserDb.get("user/support/token").then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.getData = function() { | |
return gaApiUserDb.get("user/data").then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.saveOnboarding = function(data) { | |
return data ? gaApiUserDb.put("user/onboarding", data).then(function(results) { | |
return $q.when(results[0] || null) | |
}) : void 0 | |
}, this.save = function(data) { | |
return gaApiUserDb.put("user", data).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.unlink = function() { | |
return gaApiUserDb.put("user/unlink", {}) | |
}, this.link = function(data) { | |
return gaApiUserDb.put("user/link", data) | |
}, this.passwordChange = function(data) { | |
return gaApiUserDb.put("user/password", data) | |
}, this.subscriptions = function() { | |
return gaApiUserDb.get("user/subscriptions") | |
}, this.unsubscribe = function(data) { | |
return gaApiUserDb.put("user/subscriptions", data) | |
}, this.createStudio = function(data) { | |
return gaApiUserDb.put("user/studios", data) | |
}, this.logout = function() { | |
return gaApiUserDb.get("user/logout") | |
} | |
}), angular.module("ga.api.userDb.authenticated.report", ["ga.api.userDb", "ui.router"]).service("gaApiUserDbAuthenticatedReport", function($q, $state, gaApiUserDb) { | |
this.getGameReports = function() { | |
var gameId = $state.params.gameId, | |
url = "games/" + gameId + "/reports"; | |
return gaApiUserDb.get(url) | |
}, this.getReportSubscribers = function(reportId) { | |
var url = "reports/" + reportId + "/report_subscribers"; | |
return gaApiUserDb.get(url) | |
}, this.updateReportSubscriber = function(subscriberId, subscriberData) { | |
var url = "report_subscribers/" + subscriberId; | |
return gaApiUserDb.put(url, subscriberData).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.createReportSubscriber = function(reportId, subscriberData) { | |
var url = "reports/" + reportId + "/report_subscribers"; | |
return gaApiUserDb.put(url, subscriberData).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.deleteReportSubscriber = function(subscriberId) { | |
var url = "report_subscribers/" + subscriberId; | |
return gaApiUserDb.remove(url) | |
} | |
}), angular.module("ga.api.userDb.authenticated.status", ["ga.api.userDb"]).service("gaApiUserDbAuthenticatedStatus", function($q, $timeout, gaApiUserDb) { | |
this.getProcessing = function() { | |
var url = "data_api/status/processing"; | |
return gaApiUserDb.get(url) | |
} | |
}), angular.module("ga.api.userDb.authenticated.game", ["ga.api.userDb", "ui.router"]).service("gaApiUserDbAuthenticatedGame", function($q, $state, gaApiUserDb) { | |
this.getGameData = function(gameId) { | |
return gaApiUserDb.get("games/" + gameId).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.getGameUsers = function() { | |
return gaApiUserDb.get("games/" + $state.params.gameId + "/users") | |
}, this.getAccesses = function() { | |
return gaApiUserDb.get("games/" + $state.params.gameId + "/accesses") | |
}, this.getStoreApps = function() { | |
return gaApiUserDb.get("games/" + $state.params.gameId + "/store_apps") | |
}, this.createStoreApps = function(payload) { | |
return gaApiUserDb.put("games/" + $state.params.gameId + "/store_apps", payload) | |
}, this.addUser = function(gameId, email, role, email_reports) { | |
var payload = { | |
role_id: role, | |
email: email, | |
add_email_reports: email_reports | |
}, | |
service = "games/" + gameId + "/accesses"; | |
return gaApiUserDb.put(service, payload) | |
}, this.saveGame = function(gameId, data) { | |
return gaApiUserDb.put("games/" + gameId, data).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.archiveGame = function(gameId, archiveStatus) { | |
var payload = { | |
archive: archiveStatus | |
}, | |
service = "games/" + gameId + "/archive"; | |
return gaApiUserDb.put(service, payload) | |
}, this.saveGameLinkNotification = function(gameId, hideNotification) { | |
var payload = { | |
hideNotification: hideNotification | |
}, | |
service = "games/" + gameId + "/link_game_notification"; | |
return gaApiUserDb.put(service, payload) | |
}, this.saveOldFunnelsImported = function(gameId) { | |
var payload = { | |
oldFunnelsImported: !0 | |
}, | |
service = "games/" + gameId + "/old_funnels_imported"; | |
return gaApiUserDb.put(service, payload) | |
}, this.getFunnels = function(gameId) { | |
return gaApiUserDb.get("games/" + gameId + "/funnels") | |
}, this.getOldFunnels = function(gameId) { | |
return gaApiUserDb.get("games/" + gameId + "/funnels_old") | |
}, this.createFunnel = function(gameId, funnelName, settings, dateRanges) { | |
var tmpDateRanges = null; | |
dateRanges && (tmpDateRanges = dateRanges.map(function(dr) { | |
return { | |
id: dr.id, | |
start: dr.start / 1e3, | |
end: dr.end / 1e3 | |
} | |
})); | |
var payload = { | |
funnel_name: funnelName, | |
settings: settings, | |
date_ranges: tmpDateRanges | |
}, | |
service = "games/" + gameId + "/funnels"; | |
return gaApiUserDb.put(service, payload).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
} | |
}), angular.module("ga.api.userDb.authenticated.studio", ["ga.api.userDb"]).service("gaApiUserDbAuthenticatedStudio", function($q, gaApiUserDb) { | |
this.createGame = function(studioId, data) { | |
return gaApiUserDb.put("studios/" + studioId + "/games", data) | |
}, this.saveStudio = function(studioId, data) { | |
return gaApiUserDb.put("studios/" + studioId, data).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.getStudioUsers = function(studioId) { | |
return gaApiUserDb.get("studios/" + studioId + "/accesses").then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.addUser = function(studioId, email, role, email_reports) { | |
var payload = { | |
role_id: role, | |
email: email, | |
add_email_reports: email_reports | |
}, | |
service = "studios/" + studioId + "/accesses"; | |
return gaApiUserDb.put(service, payload) | |
}, this.archiveStudio = function(studioId, archiveStatus) { | |
var payload = { | |
archive: archiveStatus | |
}, | |
service = "studios/" + studioId + "/archive"; | |
return gaApiUserDb.put(service, payload) | |
} | |
}), angular.module("ga.api.userDb.authenticated.genre", ["ga.api.userDb"]).service("gaApiUserDbAuthenticatedGenre", function(gaApiUserDb) { | |
this.getGenres = function() { | |
return gaApiUserDb.get("game_genres") | |
} | |
}), angular.module("ga.api.userDb.authenticated.appfigures", ["ga.api.userDb"]).service("gaApiUserDbAuthenticatedAppfigures", function($q, $timeout, $window, gaApiUserDb) { | |
this.getAppMeta = function(productid) { | |
return gaApiUserDb.get("data_api/appfigures/meta?productid=" + productid).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.search = function(query) { | |
var q = encodeURIComponent(query.replace(/ \\/g, "+")); | |
return gaApiUserDb.get("data_api/appfigures/search?query=" + q).then(function(results) { | |
return $q.when(results[0] || null) | |
}).catch(function() {}) | |
} | |
}), angular.module("ga.api.userDb.authenticated.store_app", ["ga.api.userDb"]).service("gaApiUserDbAuthenticatedStoreApp", function($q, $timeout, gaApiUserDb) { | |
this.update = function(store_app_id, payload) { | |
var url = "store_apps/" + store_app_id; | |
return gaApiUserDb.put(url, payload) | |
}, this.delete = function(store_app_id) { | |
var url = "store_apps/" + store_app_id; | |
return gaApiUserDb.remove(url) | |
} | |
}), angular.module("ga.api.userDb.authenticated.funnel", ["ga.api.userDb", "ui.router"]).service("gaApiUserDbAuthenticatedFunnel", function($q, $state, gaApiUserDb) { | |
this.updateFunnel = function(funnelId, funnelName, settings, dateRanges) { | |
var tmpDateRanges = null; | |
dateRanges && (tmpDateRanges = dateRanges.map(function(dr) { | |
return { | |
id: dr.id, | |
start: dr.start / 1e3, | |
end: dr.end / 1e3, | |
backendId: dr.backendId, | |
"delete": dr.delete || !1 | |
} | |
})); | |
var payload = { | |
funnel_name: funnelName, | |
settings: settings, | |
date_ranges: tmpDateRanges | |
}, | |
service = "funnels/" + funnelId; | |
return gaApiUserDb.put(service, payload) | |
}, this.deleteFunnel = function(funnelId) { | |
var service = "funnels/" + funnelId; | |
return gaApiUserDb.remove(service) | |
} | |
}), angular.module("ga.api.userDb.authenticated.haystack", ["ga.api.userDb"]).service("gaApiUserDbAuthenticatedHaystack", function($q, gaApiUserDb) { | |
this.haystackJson = function() { | |
return gaApiUserDb.get("admin/haystack.json", null, null, !0).then(function(response) { | |
return $q.when(response) | |
}) | |
} | |
}), angular.module("ga.api.userDb.public.user", ["ga.api.userDb"]).service("gaApiUserDbPublicUser", function($q, gaApiUserDb) { | |
this.getData = function(token) { | |
return gaApiUserDb.get("public/user/" + token).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.saveOnboarding = function() { | |
return $q.when() | |
}, this.save = function() { | |
return $q.when() | |
}, this.subscriptions = function() { | |
return $q.when([]) | |
}, this.unsubscribe = function() { | |
return $q.when() | |
}, this.createStudio = function() { | |
return $q.when() | |
} | |
}), angular.module("ga.api.userDb.public.activate", ["ga.api.userDb"]).service("gaApiUserDbPublicActivate", function(gaApiUserDb) { | |
this.sendActivationEmail = function(email) { | |
return gaApiUserDb.put("public/activate_account/" + email) | |
}, this.checkActivation = function(email) { | |
return gaApiUserDb.get("public/activate_account_check/" + email) | |
} | |
}), angular.module("ga.api.userDb.public.invite", ["ga.api.userDb", "ga.utils.cache"]).service("gaApiUserDbPublicInvite", function($state, $q, gaApiUserDb, gaUtilsCache) { | |
this.getInviteInfo = function(email, resource, token) { | |
var dataPayload = { | |
email: email, | |
resource: resource, | |
token: token | |
}, | |
tryCache = gaUtilsCache.get(dataPayload.resource + dataPayload.token); | |
return tryCache && $q.when(tryCache) || gaApiUserDb.post("public/invite", dataPayload).then(function(results) { | |
return results[0] && gaUtilsCache.put(dataPayload.resource + dataPayload.token, results[0], null, 1e4), $q.when(results[0] || null) | |
}) | |
} | |
}), angular.module("ga.api.userDb.public.signup", ["ga.api.userDb"]).service("gaApiUserDbPublicSignup", function($q, $http, $state, gaApiUserDb) { | |
this.signupUser = function(params) { | |
var url = "public/signup/basic"; | |
return gaApiUserDb.put(url, params).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.activateAccount = function(params) { | |
var url = "public/activate_account"; | |
return gaApiUserDb.put(url, params).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.createAccount = function(params) { | |
var url = "public/create_account"; | |
return gaApiUserDb.put(url, params).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
} | |
}), angular.module("ga.api.userDb.public.unsubscribe", ["ga.api.userDb"]).service("gaApiUserDbPublicUnsubscribe", function(gaApiUserDb) { | |
this.getSubscriptions = function(email, token) { | |
var url = "public/reports/subscriptions/" + email + "/" + token; | |
return gaApiUserDb.get(url) | |
}, this.unsubscribe = function(email, token, data) { | |
var url = "public/reports/subscriptions/" + email + "/" + token; | |
return gaApiUserDb.put(url, data) | |
} | |
}), angular.module("ga.api.userDb.public.login", ["ga.api.userDb"]).service("gaApiUserDbPublicLogin", function($q, gaApiUserDb) { | |
this.loginBasic = function(email, password, remember) { | |
var dataPayload = { | |
email: email, | |
password: password, | |
remember: !!remember | |
}; | |
return gaApiUserDb.post("public/login/basic", dataPayload).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
} | |
}), angular.module("ga.api.userDb.public.linkAccount", ["ga.api.userDb"]).service("gaApiUserDbPublicLinkAccount", function($q, gaApiUserDb) { | |
this.link = function(dataPayload) { | |
return gaApiUserDb.put("public/link_account", dataPayload).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
} | |
}), angular.module("ga.api.userDb.public.passwordReset", ["ga.api.userDb"]).service("gaApiUserDbPublicPasswordReset", function($q, gaApiUserDb) { | |
this.info = function(token) { | |
return gaApiUserDb.get("public/password_reset/" + token).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.reset = function(data, token) { | |
return gaApiUserDb.put("public/password_reset/" + token, data).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
}, this.request = function(data) { | |
return gaApiUserDb.put("public/password_reset", data).then(function(results) { | |
return $q.when(results[0] || null) | |
}) | |
} | |
}), angular.module("ga.api.statuspage", ["ui.router", "ga.utils.cookie", "ga.values.user", "ga.services.announcement"]).factory("gaApiStatuspage", function($rootScope, $http, $timeout, $state, gaValuesUser, gaServicesAnnouncement) { | |
var $scope = $rootScope.$new(), | |
statusPageUrl = "https://gameanalytics.statuspage.io/index.json"; | |
$scope.data = null; | |
var updateStatusTimer, updateStatus = function() { | |
$timeout.cancel(updateStatusTimer), $state.includes("game") || $state.includes("user.home") ? $http.get(statusPageUrl).then(function(response) { | |
$scope.data = response.data, updateStatusTimer = $timeout(updateStatus, 6e5) | |
}).catch(function() { | |
updateStatusTimer = $timeout(updateStatus, 6e5) | |
}) : updateStatusTimer = $timeout(updateStatus, 6e4) | |
}; | |
return $scope.$watch("data.status", function(newVal, oldVal) { | |
if (newVal && !angular.equals(newVal, oldVal)) | |
if ($rootScope.$broadcast("GaStatusChange", newVal), "none" !== newVal.indicator) { | |
var components = []; | |
if (angular.forEach($scope.data.components, function(component) { | |
"operational" !== component.status && components.push("<strong>" + component.name + "</strong>") | |
}), components.length > 1) { | |
var last = components.pop(); | |
components[components.length - 1] = components[components.length - 1] + " and " + last | |
} | |
var content = "We are currently experiencing some issues with our " + components.join(", "); | |
content += ' - keep updated on our <a href="http://gameanalytics.statuspage.io/" target="_blank">status page</a>', gaServicesAnnouncement.add({ | |
id: "status-page-io", | |
icon: "ga-icon-severity-warning", | |
style: "yellow", | |
content: content, | |
replace: !0 | |
}) | |
} else gaServicesAnnouncement.hide("status-page-io") | |
}), { | |
data: $scope.data, | |
updateStatus: updateStatus | |
} | |
}), angular.module("ga.api.s3", ["ga.utils.cache"]).factory("gaApiS3", function($http, $q, gaUtilsCache) { | |
var s3Url = "https://s3.amazonaws.com/", | |
downloadBucket = "public.gameanalytics.com/", | |
getSdkChangelogs = function(force) { | |
var sdkChangesFile = "sdk_status/change_logs.json", | |
requestURL = s3Url + downloadBucket + sdkChangesFile, | |
deferred = $q.defer(), | |
changelogs = force ? null : gaUtilsCache.get("S3SdkChangeLogs", "localStorage"); | |
if (changelogs) deferred.resolve(changelogs); | |
else { | |
var Success = function(response) { | |
deferred.resolve(response.data); | |
var cacheTime = 18e5; | |
gaUtilsCache.put("S3SdkChangeLogs", response.data, "localStorage", cacheTime) | |
}, | |
Error = function() { | |
deferred.reject() | |
}; | |
$http.get(requestURL).then(Success, Error) | |
} | |
return deferred.promise | |
}, | |
getSdkLatestVersions = function() { | |
var sdkVersionsFile = "sdk_status/current.json", | |
requestURL = s3Url + downloadBucket + sdkVersionsFile, | |
deferred = $q.defer(); | |
return $http.get(requestURL).then(function(response) { | |
deferred.resolve(response.data) | |
}, function(response) { | |
deferred.reject(response) | |
}), deferred.promise | |
}, | |
getSdkMeta = function() { | |
var sdkInfo = { | |
android: { | |
icon: "", | |
name: "Android", | |
repoUrl: "https://github.com/GameAnalytics/GA-Android-SDK" | |
}, | |
ios: { | |
icon: "", | |
name: "iOS", | |
repoUrl: "https://github.com/GameAnalytics/GA-iOS-SDK" | |
}, | |
corona: { | |
icon: "", | |
name: "Corona", | |
repoUrl: "https://github.com/GameAnalytics/GA-Corona-SDK" | |
}, | |
unity: { | |
icon: "", | |
name: "Unity", | |
repoUrl: "https://github.com/GameAnalytics/GA-Unity-SDK" | |
}, | |
flash: { | |
icon: "", | |
name: "Flash", | |
repoUrl: "https://github.com/GameAnalytics/GA-Flash-SDK" | |
} | |
}; | |
return sdkInfo | |
}; | |
return { | |
getSdkLatestVersions: getSdkLatestVersions, | |
getSdkChangelogs: getSdkChangelogs, | |
getSdkMeta: getSdkMeta | |
} | |
}), angular.module("ga.values.user", []).value("gaValuesUser", { | |
settings: {}, | |
details: {}, | |
token: null, | |
readonly: null, | |
activated: null, | |
gameToken: function() { | |
return null | |
}, | |
game: function() { | |
return null | |
}, | |
id: 0 | |
}), angular.module("ga.services.user", ["ui.router", "ga.values.user", "ga.config", "ga.api.userDb.public.login", "ga.api.userDb.authenticated.user", "ga.api.userDb.authenticated.invite", "ga.utils.cookie", "ga.utils.helpers", "ga.services.game", "ga.ui.modal", "ga.pages.user.invites", "ga.pages.user.passwordChange", "ga.pages.public.passwordReset", "ga.services.pardot"]).service("gaServicesUser", function($window, $state, $rootScope, $q, $timeout, gaConfig, gaValuesUser, gaApiUserDbPublicLogin, gaApiUserDbAuthenticatedInvite, gaApiUserDbAuthenticatedUser, gaUtilsCookie, gaHelpers, gaServicesGame, gaUiModal, gaServicesPardot) { | |
var detectSleepTimer, detectSleepLast, detectSleep = function() { | |
var currentTime = (new Date).getTime(); | |
currentTime > detectSleepLast + 1e4 + 2e3 && this.token && this.getUserData(), detectSleepLast = (new Date).getTime() | |
}; | |
detectSleepTimer = setInterval(detectSleep.bind(this), 1e4); | |
var _userToken = { | |
token: null, | |
exp: 0 | |
}, | |
_userData = null, | |
_userFlags = {}, | |
getUserDataInterval = 6e5, | |
getUserDataTimer = null, | |
getUserDataInProgress = !1, | |
populateValues = function() { | |
Object.defineProperties(gaValuesUser, { | |
token: { | |
enumerable: !0, | |
get: function() { | |
return this.token | |
}.bind(this) | |
}, | |
gameToken: { | |
enumerable: !1, | |
value: this.gameToken.bind(this) | |
}, | |
settings: { | |
enumerable: !0, | |
get: this.settings.serialize.bind(this) | |
}, | |
details: { | |
enumerable: !0, | |
get: this.details.serialize.bind(this) | |
}, | |
activated: { | |
enumerable: !0, | |
get: function() { | |
return this.activated | |
}.bind(this) | |
}, | |
game: { | |
enumerable: !1, | |
value: function(gameId) { | |
return this.game(gameId) | |
}.bind(this) | |
}, | |
id: { | |
enumerable: !0, | |
get: function() { | |
return this.id | |
}.bind(this) | |
} | |
}) | |
}.bind(this), | |
updateUserData = function(newData, noBroadcast) { | |
var oldData = this.data; | |
gaHelpers.equals(newData.invites, oldData.invites) || (_userData.invites = newData.invites, !noBroadcast && $rootScope.$broadcast("userInvitesChange")), gaHelpers.equals(newData.studiosGames, oldData.studiosGames, ["dataApiToken"]) ? _userData.studiosGames.forEach(function(studio, studioIndex) { | |
studio.games.forEach(function(game, gameIndex) { | |
game.dataApiToken = newData.studiosGames[studioIndex].games[gameIndex].dataApiToken | |
}) | |
}) : (_userData.studiosGames = newData.studiosGames, !noBroadcast && $rootScope.$broadcast("userStudiosChange")) | |
}.bind(this), | |
parseStudio = function(studio) { | |
var parsed = gaHelpers.copy(studio); | |
return parsed.games = (parsed.games || []).map(parseGame.bind(this, parsed)), parsed.imagePath = studio.demo ? "/static/ga-app/images/demo-studio-icon.png" : parsed.imageFile ? gaConfig.images.baseUrl + parsed.imageFile : "/static/ga-app/images/default-studio-icon.png", parsed.owner = "owner" === parsed.access.role, parsed.admin = parsed.owner || "admin" === parsed.access.role, parsed.viewer = parsed.admin || "viewer" === parsed.access.role || this.demo, parsed | |
}.bind(this), | |
parseGame = function(studio, game) { | |
var parsed = gaHelpers.copy(game); | |
return parsed.studioId = studio.id, parsed.owner = "owner" === parsed.access.role, parsed.admin = studio.admin || parsed.owner || "admin" === parsed.access.role, parsed.viewer = studio.viewer || parsed.admin || "viewer" === parsed.access.role, parsed.imagePath = studio.demo ? "/static/ga-app/images/demo-game-icon.png" : parsed.imageFile ? gaConfig.images.baseUrl + parsed.imageFile : "/static/ga-app/images/default-game-icon.png", Object.defineProperties(parsed, { | |
status: { | |
enumerable: !1, | |
value: gaServicesGame.getStatus.bind(gaServicesGame, game.id) | |
}, | |
numbers: { | |
enumerable: !1, | |
value: gaServicesGame.getNumbers.bind(gaServicesGame, game.id) | |
}, | |
token: { | |
enumerable: !1, | |
get: function() { | |
return game.dataApiToken.token | |
} | |
} | |
}), parsed | |
}.bind(this), | |
parseInvite = function(invite) { | |
return invite.type = invite.title ? "game" : "studio", invite.name = invite.name || invite.title, Object.defineProperties(invite, { | |
accept: { | |
enumerable: !1, | |
value: function() { | |
return gaApiUserDbAuthenticatedInvite.accept(invite).then(function() { | |
return this.getUserData() | |
}.bind(this)) | |
}.bind(this) | |
}, | |
decline: { | |
enumerable: !1, | |
value: function() { | |
return gaApiUserDbAuthenticatedInvite.decline(invite).then(function() { | |
return invite.remove(), $q.when() | |
}) | |
}.bind(this) | |
}, | |
remove: { | |
enumerable: !1, | |
value: function() { | |
if (_userData) { | |
var found = _userData.invites[invite.type].some(function(item, index) { | |
return item.id === invite.id ? (_userData.invites[invite.type].splice(index, 1), !0) : void 0 | |
}); | |
return found && $rootScope.$broadcast("userInvitesChange"), found | |
} | |
}.bind(this) | |
} | |
}), invite | |
}.bind(this); | |
this.settings = {}, this.invites = {}, this.details = {}, this.logout = function() { | |
gaApiUserDbAuthenticatedUser.logout(), this.token = null | |
}, this.init = function() { | |
this.token = gaHelpers.parse(gaUtilsCookie.get("gaUserToken"), { | |
token: null, | |
exp: 0 | |
}), populateValues.bind(this)() | |
}, this.dialogInvites = function() { | |
return gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/user/invites/invites.html", | |
controller: "gaPagesUserInvitesController", | |
parameters: {}, | |
escape: !0, | |
width: 800 | |
}) | |
}, this.dialogPasswordChange = function() { | |
return gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/user/password-change/password-change.html", | |
controller: "gaPagesUserPasswordChangeController", | |
parameters: {}, | |
escape: !0, | |
width: 600 | |
}) | |
}, this.dialogPasswordForgot = function(email) { | |
return gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/public/password-forgot/password-forgot.html", | |
controller: "gaPagesPublicPasswordForgotController", | |
parameters: { | |
data: { | |
email: email || this.details.email | |
} | |
}, | |
escape: !0, | |
width: 600 | |
}) | |
}, this.login = function(email, password, remember) { | |
return gaApiUserDbPublicLogin.loginBasic(email, password, remember).then(function(result) { | |
return this.token = result, this.resolveUser() | |
}.bind(this)) | |
}, this.getUserData = function(noBroadcast, forceRefresh) { | |
clearTimeout(getUserDataTimer); | |
var init = !_userData; | |
return this.token ? (getUserDataInProgress = !0, gaApiUserDbAuthenticatedUser.getData().then(function(result) { | |
return getUserDataInProgress = !1, this.token = result.userApiToken, result.pardotToken && gaServicesPardot.addProspect(result.details.email, result.pardotToken.token), delete result.pardotToken, init ? _userData = result : forceRefresh ? (_userData = result, !noBroadcast && $rootScope.$broadcast("forcedUserDataChange")) : updateUserData(result, noBroadcast), getUserDataTimer = setTimeout(this.getUserData.bind(this), getUserDataInterval), $q.when(result) | |
}.bind(this)).catch(function(errors) { | |
return getUserDataInProgress = !1, this.token = null, $q.reject(errors) | |
}.bind(this))) : $q.reject([{ | |
msg: "No token" | |
}]) | |
}, this.resolveUser = function(retryNr) { | |
return retryNr = retryNr || 0, this.token ? _userData ? $q.when(_userData) : this.getUserData() : $q.reject("No token present") | |
}, Object.defineProperties(this, { | |
supportToken: { | |
enumerable: !1, | |
value: function() { | |
return this.token ? gaApiUserDbAuthenticatedUser.supportToken() : $q.when(null) | |
}.bind(this) | |
}, | |
instance: { | |
enumerable: !1, | |
get: function() { | |
var userInstance = angular.element.extend({ | |
name: this.details.name, | |
id: this.id, | |
linked: this.linked | |
}, this.details.serialize(), this.settings.serialize()); | |
return userInstance | |
} | |
}, | |
activated: { | |
enumerable: !0, | |
get: function() { | |
return _userFlags && _userFlags.nonActivated ? !1 : !0 | |
} | |
}, | |
demoGameEnabled: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.demoGameEnabled || !1 | |
} | |
}, | |
admin: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.admin || !1 | |
} | |
}, | |
adminLoggedIn: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.adminLoggedIn || !1 | |
} | |
}, | |
impersonated: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.impersonated || !1 | |
} | |
}, | |
id: { | |
enumerable: !0, | |
get: function() { | |
return _userData ? _userData.id : 0 | |
} | |
}, | |
linked: { | |
enumerable: !0, | |
get: function() { | |
return _userData ? _userData.linked : null | |
}, | |
set: function(newLinked) { | |
_userData && (_userData.linked = newLinked) | |
} | |
}, | |
demo: { | |
enumerable: !0, | |
get: function() { | |
return _userData ? !!_userData.demo : !1 | |
} | |
}, | |
demoStudio: { | |
enumerable: !0, | |
get: function() { | |
return _userData ? !!_userData.demoStudio : !1 | |
} | |
}, | |
flags: { | |
enumerable: !1, | |
get: function() { | |
return _userFlags || {} | |
} | |
}, | |
token: { | |
enumerable: !1, | |
get: function() { | |
return !_userToken || this.expires <= 0 ? null : _userToken.token | |
}.bind(this), | |
set: function(token) { | |
if (void 0 === token) return !1; | |
if (null === token || token === !1) _userToken = { | |
token: null, | |
exp: 0 | |
}, gaUtilsCookie.remove("gaUserToken"), localStorage.clear(), _userData = null, _userFlags = {}; | |
else if (token && void 0 !== token.token && void 0 !== token.exp) { | |
_userToken = { | |
token: token.token, | |
exp: token.exp | |
}, _userToken.exp = 1e3 * parseInt(_userToken.exp, 10), gaUtilsCookie.set("gaUserToken", JSON.stringify(token), 14); | |
for (var flag in token.flags) _userFlags[flag] = token.flags[flag] | |
} else gaUtilsCookie.remove("gaUserToken"), localStorage.clear() | |
} | |
}, | |
expires: { | |
enumerable: !1, | |
get: function() { | |
return _userToken && _userToken.token ? 1 : 0 | |
} | |
}, | |
data: { | |
enumerable: !1, | |
get: function() { | |
return _userData ? gaHelpers.copy(_userData) : null | |
} | |
}, | |
studios: { | |
enumerable: !0, | |
get: function() { | |
return (_userData && _userData.studiosGames ? _userData.studiosGames : []).map(parseStudio) | |
} | |
}, | |
studio: { | |
enumerable: !1, | |
value: function(studioId) { | |
var found = null; | |
return (_userData && _userData.studiosGames ? _userData.studiosGames : []).some(function(studio) { | |
return studio.id === studioId ? (found = parseStudio(studio), !0) : void 0 | |
}), found | |
} | |
}, | |
game: { | |
enumerable: !1, | |
value: function(gameId) { | |
var found = null; | |
return (_userData ? _userData.studiosGames : []).some(function(studio) { | |
return studio.games.some(function(game) { | |
return game.id === gameId ? (found = parseGame(studio, game), !0) : void 0 | |
}) | |
}), found | |
} | |
}, | |
gameToken: { | |
enumerable: !1, | |
value: function(gameId) { | |
var game = this.game(parseInt(gameId, 10)); | |
return game ? game.token : null | |
} | |
}, | |
onboarding: { | |
enumerable: !1, | |
get: function() { | |
var onboarding = gaHelpers.serializeObject(_userData && _userData.onboarding || {}); | |
return onboarding.dashboard = onboarding.dashboard || {}, onboarding.dashboard.realtime = !0, Object.defineProperties(onboarding, { | |
set: { | |
enumerable: !1, | |
value: function(section, key, boolValue) { | |
_userData && (_userData.onboarding = _userData.onboarding || {}, _userData.onboarding[section] = _userData.onboarding[section] || {}, _userData.onboarding[section][key] = !!boolValue) | |
} | |
}, | |
save: { | |
enumerable: !1, | |
value: gaApiUserDbAuthenticatedUser.saveOnboarding.bind(gaApiUserDbAuthenticatedUser, (_userData || {}).onboarding) | |
} | |
}), onboarding | |
} | |
}, | |
invites: { | |
enumerable: !1, | |
get: function() { | |
if (!_userData || !_userData.invites) return []; | |
var allInvites = gaHelpers.copy(_userData.invites.studio.concat(_userData.invites.game)).map(parseInvite).sort(function(a, b) { | |
return a.invitedTs === b.invitedTs ? 0 : a.invitedTs < b.invitedTs ? 1 : -1 | |
}); | |
return allInvites | |
} | |
}, | |
invite: { | |
enumerable: !1, | |
value: function(id, type) { | |
if ("studio" !== type && "game" !== type) return null; | |
var found = null; | |
return (_userData ? _userData.invites[type] : []).some(function(invite) { | |
invite.id === id && (found = parseInvite(gaHelpers.copy(invite))) | |
}), found | |
} | |
} | |
}), Object.defineProperties(this.settings, { | |
timeZone: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.settings.timeZone || "Europe/London" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.settings.timeZone = value | |
} | |
}, | |
numberFormat: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.settings.numberFormat || "1" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.settings.numberFormat = value | |
} | |
}, | |
startOfWeek: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.settings.startOfWeek || "Monday" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.settings.startOfWeek = value | |
} | |
}, | |
dateFormat: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.settings.dateFormat || "MDY" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.settings.dateFormat = value | |
} | |
}, | |
timeFormat: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.settings.timeFormat || "24hour" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.settings.timeFormat = value | |
} | |
}, | |
currencyDefault: { | |
enumerable: !0, | |
get: function() { | |
return _userData && _userData.settings.currencyDefault || "USD" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.settings.currencyDefault = value | |
} | |
}, | |
serialize: { | |
enumerable: !1, | |
value: gaHelpers.serializeObject.bind(this, this.settings) | |
}, | |
save: { | |
enumerable: !1, | |
value: function(newValues) { | |
return gaApiUserDbAuthenticatedUser.save(newValues).then(function() { | |
var old = this.settings.serialize(); | |
_userData.settings = angular.element.extend(_userData.settings, newValues), $rootScope.$broadcast("userSettingsChange", this.settings.serialize(), old) | |
}.bind(this)) | |
}.bind(this) | |
} | |
}), Object.defineProperties(this.details, { | |
firstName: { | |
enumerable: !0, | |
get: function() { | |
return _userData ? _userData.details.firstName : "" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.details.firstName = value | |
} | |
}, | |
lastName: { | |
enumerable: !0, | |
get: function() { | |
return _userData ? _userData.details.lastName : "" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.details.lastName = value | |
} | |
}, | |
city: { | |
enumerable: !0, | |
get: function() { | |
return _userData ? _userData.details.city : "" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.details.city = value | |
} | |
}, | |
country: { | |
enumerable: !0, | |
get: function() { | |
return _userData ? _userData.details.country : "" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.details.country = value | |
} | |
}, | |
name: { | |
enumerable: !1, | |
get: function() { | |
return this.activated ? (this.details.firstName + " " + this.details.lastName).trim() : this.details.email | |
}.bind(this) | |
}, | |
email: { | |
enumerable: !0, | |
get: function() { | |
return _userData ? _userData.details.email : "" | |
}, | |
set: function(value) { | |
if (!_userData) throw new Error("No user is logged in"); | |
_userData.details.email = value | |
} | |
}, | |
serialize: { | |
enumerable: !1, | |
value: gaHelpers.serializeObject.bind(this, this.details) | |
}, | |
save: { | |
enumerable: !1, | |
value: function(newValues) { | |
var details = gaHelpers.copy(newValues); | |
return delete details.email, gaApiUserDbAuthenticatedUser.save(details).then(function() { | |
return _userData.demoGameEnabled !== newValues.demoGameEnabled ? (_userData.demoGameEnabled = newValues.demoGameEnabled, this.getUserData().then(function() { | |
return $rootScope.$broadcast("userDemoGameChange"), $rootScope.$broadcast("userDetailsChange"), $q.when() | |
})) : (_userData.details = angular.element.extend(_userData.details, newValues), $rootScope.$broadcast("userDetailsChange"), $q.when()) | |
}.bind(this)) | |
}.bind(this) | |
} | |
}); | |
var storageEventHandler = function(e) { | |
if ("gaUserToken" === e.key) { | |
var newValue = gaHelpers.parse(e.newValue), | |
oldValue = gaHelpers.parse(e.oldValue); | |
oldValue && oldValue.token ? oldValue && oldValue.token && (newValue && newValue.token || (this.token = null, $state.reload())) : newValue && newValue.token && (this.token = newValue, this.resolveUser().then(function() { | |
$state.reload() | |
})) | |
} | |
}; | |
$window.addEventListener("storage", storageEventHandler.bind(this), !1), this.__mockUser = function(mockData) { | |
_userData = mockData | |
}, this.init() | |
}), angular.module("ga.services.user.mock", ["ga.services.user", "ga.values.user"]).service("gaServicesUserMock", function(gaServicesUser) { | |
this.mockUser = function() { | |
var expires = Math.round(((new Date).getTime() + 12e5) / 1e3), | |
game = { | |
access: { | |
flags: { | |
business: !0 | |
}, | |
role: "owner", | |
level: 99 | |
}, | |
imageName: "test.jpeg", | |
dataApiToken: { | |
token: '><(((">oOo<")><', | |
exp: expires | |
}, | |
id: 1, | |
title: "Test Game" | |
}, | |
mockData = { | |
onboarding: { | |
cohort: { | |
tour: !0 | |
}, | |
explore: { | |
tour: !0 | |
}, | |
dashboard: { | |
engagement: !0, | |
tour: !0, | |
realtimeTour: !0, | |
acquisition_notice: !0, | |
quality: !0, | |
acquisition: !0, | |
monetization: !0 | |
} | |
}, | |
studiosGames: [{ | |
access: { | |
flags: { | |
business: !0 | |
}, | |
role: "owner", | |
level: 99 | |
}, | |
imageName: null, | |
games: [game], | |
id: 1, | |
name: "Test Studio" | |
}], | |
details: { | |
city: null, | |
firstName: "John", | |
country: null, | |
lastName: "Doe", | |
createdDate: "2013-11-19T11:37:14", | |
id: 3, | |
phone: null, | |
email: "john.doe@gameanalytics.com" | |
}, | |
userApiToken: { | |
token: '><((">oOo<"))><', | |
id: 1, | |
exp: expires | |
}, | |
settings: { | |
numberFormat: "1", | |
dateFormat: "YMD", | |
timeFormat: "24hour", | |
timeZone: "Europe/London", | |
currencyDefault: "USD", | |
startOfWeek: "Monday" | |
} | |
}; | |
gaServicesUser.token = { | |
token: '><(("> <"))><', | |
exp: expires | |
}, gaServicesUser.__mockUser(mockData) | |
}, this.unmockUser = function() { | |
gaServicesUser.token = null | |
} | |
}).run(function(gaServicesUserMock) { | |
gaServicesUserMock.mockUser() | |
}), angular.module("ga.services.game", ["ga.config", "ga.values.user", "ga.api.data", "ga.utils.query", "ga.utils.cache", "ga.utils.date", "ga.api.userDb.authenticated.game"]).service("gaServicesGame", function($window, $q, $http, gaConfig, gaValuesUser, gaApiData, gaUtilsQuery, gaUtilsCache, gaUtilsDate, gaApiUserDbAuthenticatedGame) { | |
var statusCacheInterval = 15e3, | |
gameNumbersCacheInterval = 36e5, | |
validateBatchResponse = function(responses) { | |
var numbers = {}, | |
error = responses.data.some(function(response) { | |
if (!response || 200 !== response.code || !response.body || !response.body.aggregated) return !0; | |
for (var event in response.body.aggregated) { | |
response.body.aggregated[event].total = response.body.aggregated[event].total || 0; | |
var dimensions = null; | |
if (response.body.aggregated[event].dimensions) { | |
dimensions = []; | |
for (var dimension in response.body.aggregated[event].dimensions) | |
for (var key in response.body.aggregated[event].dimensions[dimension]) dimensions.push({ | |
key: key, | |
total: response.body.aggregated[event].dimensions[dimension][key] || 0 | |
}) | |
} | |
response.body.aggregated[event].dimensions = dimensions && dimensions.sort(function(a, b) { | |
return a.total === b.total ? 0 : a.total > b.total ? 1 : -1 | |
}) || null, numbers[event] = response.body.aggregated[event] | |
} | |
}); | |
return error ? $q.reject({ | |
data: { | |
error: "invalid_response" | |
} | |
}) : $q.when(numbers) | |
}, | |
getConfig = function(gameId) { | |
return { | |
headers: { | |
Authorization: gaValuesUser.gameToken(gameId) | |
} | |
} | |
}; | |
this.getMetrics = function(gameId, metrics, interval) { | |
var realtime = metrics.some(function(metric) { | |
return "operations" === metric.category | |
}); | |
realtime && (interval = "last24hours"), interval = "string" == typeof interval ? gaUtilsDate.getPeriodRange(interval) : interval; | |
var batchCalls = metrics.map(function(metric) { | |
return "/v1/games/" + gameId + "/" + metric.category + "/" + metric.event + "?start=" + interval.start / 1e3 + "&end=" + interval.end / 1e3 + "&aggregation=" + (metric.aggregation || "mean") + (metric.filter ? "&" + metric.filter.dimension + "=" + $window.escape(metric.filter.values.join(",")) : "") | |
}), | |
config = getConfig(gameId), | |
url = gaConfig.getUrl(!0, realtime) + gameId; | |
return $http.post(url, batchCalls, config).then(validateBatchResponse) | |
}, this.getDimensions = function(gameId) { | |
var config = getConfig(gameId), | |
url = gaConfig.getUrl(!1, !1) + gameId + "/dimensions"; | |
return $http.get(url, config).then(function(response) { | |
return $q.when(response.data) | |
}).catch(function(response) { | |
return $q.reject(response.data) | |
}) | |
}, this.getStatus = function(gameId, numbers) { | |
var result = gaUtilsCache.get("game_status" + (numbers ? "_numbers" : "") + "_" + gameId, "localStorage"); | |
if (result) return $q.when(result); | |
var status = { | |
gameId: gameId, | |
eventCount: 0, | |
rejectedEvents: 0, | |
concurrentUsers: 0, | |
topSdk: null, | |
initialized: !1, | |
data: !1, | |
data24: !1, | |
error: !1 | |
}; | |
return this.getDimensions(gameId).then(function(response) { | |
status.initialized = !0; | |
var hasKeys; | |
for (hasKeys in response) break; | |
hasKeys && (status.data = !0); | |
var metrics = [{ | |
category: "operations", | |
event: "event_count", | |
aggregation: "event_count" | |
}]; | |
return numbers && (metrics = [{ | |
category: "operations", | |
event: "event_count", | |
aggregation: "event_count", | |
filter: { | |
dimension: "sdk_version", | |
values: ["*"] | |
} | |
}, { | |
category: "operations", | |
event: "rejected_events", | |
aggregation: "event_count" | |
}, { | |
category: "operations", | |
event: "concurrent_users", | |
aggregation: "sum" | |
}]), this.getMetrics(gameId, metrics).then(function(numbers) { | |
return numbers.event_count.dimensions && numbers.event_count.dimensions[0] && null !== numbers.event_count.dimensions[0].key && (status.topSdk = numbers.event_count.dimensions[0].key, status.topSdk = "null" === status.topSdk ? "Unknown" : status.topSdk), status.eventCount = numbers.event_count.total || 0, status.rejectedEvents = numbers.rejected_events && numbers.rejected_events.total || 0, status.concurrentUsers = numbers.concurrent_users && numbers.concurrent_users.total || 0, status.data24 = !!numbers.event_count.total, status.eventCount - status.rejectedEvents > 0 && (status.data = !0), $q.when(status) | |
}) | |
}.bind(this)).catch(function(response) { | |
return response && "no_game_api_key" === response.error || (status.error = !0), $q.when(status) | |
}).then(function(response) { | |
return gaUtilsCache.put("game_status" + (numbers ? "_numbers" : "") + "_" + gameId, response, "localStorage", statusCacheInterval), $q.when(response) | |
}) | |
}, this.realtimeNumbers = function(gameId) { | |
var query = gaUtilsQuery.getQuery({ | |
gameId: gameId, | |
compare: !1, | |
interval: "lastWeek", | |
metric: { | |
category: "operations", | |
event: "rejected_events" | |
}, | |
filter: null, | |
group: "time", | |
aggregation: "event_count" | |
}), | |
query2 = angular.copy(query); | |
query2.metric = { | |
category: "operations", | |
event: "concurrent_users" | |
}, query2.aggregation = "sum"; | |
var promises = { | |
events: gaApiData.get(query), | |
users: gaApiData.get(query2) | |
}; | |
return $q.all(promises).then(function(response) { | |
var result = { | |
rejectedEvents: response.events.noData ? 0 : response.events.data.aggregated[0].total, | |
users: response.users.noData ? 0 : response.users.data.aggregated[0].total | |
}; | |
return $q.when(result) | |
}) | |
}, this.getNumbers = function(gameId) { | |
var result = gaUtilsCache.get("gameNumbers_" + gameId, "localStorage"); | |
if (result) return $q.when(result); | |
var promises = [this.getMetricNumber(gameId, { | |
category: "core", | |
event: "DAU" | |
}), this.getMetricNumber(gameId, { | |
category: "core", | |
event: "installs" | |
}), this.getMetricNumber(gameId, { | |
category: "core", | |
event: "ARPDAU" | |
})]; | |
return $q.all(promises).then(function(result) { | |
return gaUtilsCache.put("gameNumbers_" + gameId, result, "localStorage", gameNumbersCacheInterval, 1), $q.when(result) | |
}) | |
}, this.getMetricNumber = function(gameId, metric, aggregation, interval) { | |
interval = interval || "yesterday"; | |
var query = gaUtilsQuery.getQuery({ | |
gameId: gameId, | |
compare: !0, | |
interval: interval, | |
metric: metric, | |
filter: null, | |
group: "time", | |
aggregation: aggregation || "mean" | |
}); | |
return gaApiData.get(query).then(function(response) { | |
var result = { | |
title: response.data.aggregated[0].meta.title, | |
value: response.data.aggregated[0].total || 0, | |
cValue: response.data.aggregated[0].cTotal || 0 | |
}; | |
return result.diff = result.value - result.cValue, result.percent = 0 === result.diff ? 0 : result.diff / result.cValue, result.percentClass = result.percent ? result.percent > 0 ? "ga color green" : "ga color red" : "", result.percent > 10 || 1 / 0 === result.percent ? (result.percent = 10, result.percentClass += " more") : (result.percent < -10 || result.percent === -1 / 0) && (result.percent = -10, result.percentClass += " less"), $q.when(result) | |
}).catch(function() { | |
var result = { | |
title: " ", | |
value: 0, | |
cValue: 0 | |
}; | |
return result.diff = 0, result.percent = 0, $q.when(result) | |
}) | |
}, this.saveGameLinkNotification = function(gameId, hideNotification) { | |
return gaApiUserDbAuthenticatedGame.saveGameLinkNotification(gameId, hideNotification) | |
} | |
}), angular.module("ga.services.dataStatus", ["ga.api.data", "ga.utils.date", "ui.router"]).service("gaServicesDataStatus", function($state, gaApiData, gaUtilsDate) { | |
var lessThan = "is less than", | |
moreThan = "is more than"; | |
this.lag = { | |
updateInterval: 6e4, | |
listeners: [], | |
timer: null, | |
last: null, | |
on: function(callback, id) { | |
"$id" in id && (id.$on("$destroy", this.lag.off.bind(this, id.$id)), id = id.$id), id = (id || callback).toString(), this.lag.listeners.push({ | |
id: id, | |
callback: callback | |
}), 1 === this.lag.listeners.length && this.lag.update(), this.lag.last && callback(null, this.lag.last) | |
}.bind(this), | |
off: function(id) { | |
id = id.toString(), this.lag.listeners = this.lag.listeners.filter(function(listener) { | |
return listener.id !== id | |
}), this.lag.listeners.length || clearTimeout(this.lag.timer) | |
}.bind(this), | |
update: function() { | |
clearTimeout(this.lag.timer), gaApiData.getValue("/operations/lag", $state.params.gameId, !0).then(this.lag.updateSuccess.bind(this)).catch(this.lag.updateError.bind(this)) | |
}.bind(this), | |
updateError: function() { | |
this.lag.listeners.forEach(function(listener) { | |
listener.callback("response error", null) | |
}), this.lag.listeners.length && (this.lag.timer = setTimeout(this.lag.update.bind(this), this.lag.updateInterval)) | |
}.bind(this), | |
updateSuccess: function(response) { | |
var callbackParams = []; | |
if (response && response.lag && null !== response.lag.seconds) { | |
var serverNow = gaUtilsDate.moment(1e3 * response.timestamp).utc(), | |
processing = serverNow.clone().add(-response.lag.seconds, "seconds"), | |
lag = {}; | |
lag.s = lag.raw = parseInt(response.lag.seconds, 10) + 120, lag.h = Math.floor(lag.s / 3600), lag.s = lag.s - 60 * lag.h * 60, lag.m = Math.floor(lag.s / 60), lag.s = lag.s - 60 * lag.m, lag.ts = serverNow.valueOf(), lag.tsProcessing = processing.valueOf(), lag.tsProcessingHour = processing.clone().startOf("hour").valueOf(), lag.offsetHours = serverNow.clone().startOf("hour").add(1, "hours").diff(processing.startOf("hour"), "hours"), lag.isCurrentHour = lag.raw < 2700 ? !0 : !1, lag.warning = lag.h >= 1 || lag.m >= 45 ? "critical" : lag.m >= 15 ? "warning" : null, lag.message = lag.h >= 1 ? [moreThan, lag.h > 5 ? 5 : lag.h, "hr" + (lag.h > 1 ? "s" : "") + "."].join(" ") : lag.m >= 45 ? [moreThan, 45, "mins."].join(" ") : lag.m >= 30 ? [lessThan, 45, "mins."].join(" ") : lag.m >= 20 ? [lessThan, 30, "mins."].join(" ") : lag.m >= 15 ? [lessThan, 20, "mins."].join(" ") : lag.m >= 10 ? [lessThan, 15, "mins."].join(" ") : lag.m >= 9 ? [lessThan, 10, "mins."].join(" ") : [lessThan, lag.m, "mins."].join(" "), this.lag.last = lag, callbackParams = [null, this.lag.last] | |
} else callbackParams = ["invalid response"]; | |
this.lag.listeners.forEach(function(listener) { | |
listener.callback.apply(null, callbackParams) | |
}), this.lag.listeners.length && (this.lag.timer = setTimeout(this.lag.update.bind(this), this.lag.updateInterval)) | |
}.bind(this) | |
} | |
}), angular.module("ga.services.tracking", ["ui.router", "ga.config", "ga.utils.cookie", "ga.utils.crypto", "ga.values.user"]).service("gaServicesTracking", function($q, $window, $state, gaConfig, gaUtilsCookie, gaUtilsCrypto, gaValuesUser) { | |
var isInitialized = !1, | |
build = "0.0.1", | |
sdk_version = "JS 0.0.1", | |
platform = $window.location.host; | |
platform = platform.indexOf("virtual.ga.com") > -1 ? "dev" : platform.indexOf("test1.gameanalytics.com") > -1 ? "test" : platform.indexOf("latest.gameanalytics.com") > -1 ? "latest" : platform.indexOf("go.gameanalytics.com") > -1 ? "production" : "unknown", this.getUserId = function() { | |
if (gaValuesUser.details.id) return platform + "_" + gaValuesUser.details.id; | |
var id = gaUtilsCookie.get("ga_user_id"); | |
return id || (id = "ga_user_" + Math.random().toString().replace(".", ""), gaUtilsCookie.set("ga_user_id", id, 365)), id | |
}, this.getSessionId = function() { | |
var id = gaUtilsCookie.get("ga_session_id"); | |
return id || (id = "ga_session_" + Math.random().toString().replace(".", ""), gaUtilsCookie.set("ga_session_id", id)), id | |
}, this.submitEvent = function(category, event, data) { | |
return this.addEvent(category, event, data) | |
}; | |
var processQueueTimer, queue = {}, | |
processQueueInterval = 2e3; | |
this.processQueue = function() { | |
clearTimeout(processQueueTimer); | |
for (var category in queue) this.submitData(category, queue[category]), queue[category] = [], delete queue[category]; | |
processQueueTimer = setTimeout(this.processQueue.bind(this), processQueueInterval) | |
}, this.submitData = function(category, data) { | |
var deferred = $q.defer(), | |
json_data = JSON.stringify(data), | |
md5_auth = gaUtilsCrypto.md5(json_data + atob(atob(gaConfig.gaSecret))), | |
options = { | |
type: "POST", | |
url: "https://api.gameanalytics.com/1/" + atob(atob(gaConfig.gaKey)) + "/" + category + "/", | |
data: json_data, | |
headers: { | |
Authorization: md5_auth, | |
"Content-Type": "text/plain" | |
} | |
}; | |
return angular.element.ajax(options).done(function(response) { | |
deferred.resolve(response) | |
}).fail(function(response) { | |
deferred.reject(response) | |
}), deferred.promise | |
}, this.addEvent = function(category, event, data, direct) { | |
return data.user_id = this.getUserId(), data.session_id = this.getSessionId(), data.build = build, data.event_id = event, direct ? this.submitData(category, data) : (queue[category] = queue[category] || [], queue[category].push(data), $q.when()) | |
}, this.init = function() { | |
return isInitialized ? !1 : (isInitialized = !0, void this.addEvent("user", "init", { | |
sdk_version: sdk_version, | |
platform: platform | |
}, !0).then(this.processQueue.bind(this))) | |
}, this.trackState = function(state, params) { | |
state = state || $state.current.name, params = params || angular.copy($state.params); | |
var ignore = ["game.dashboards"]; | |
if (!(ignore.indexOf(state) > -1)) { | |
switch (state) { | |
case "game.dashboards.dashboard": | |
var idInt = parseInt(params.dashboardId, 10); | |
if (idInt !== idInt) state = "game.dashboards-" + params.dashboardId; | |
else { | |
if (!idInt) return; | |
state = "game.dashboards-custom" | |
} | |
state = state + "." + params.action; | |
break; | |
case "game.heatmap": | |
state = "game.heatmap.hasdata"; | |
break; | |
case "game.heatmap-nodata": | |
state = "game.heatmap.nodata"; | |
break; | |
case "game.heatmap-firsttime": | |
state = "game.heatmap.firsttime" | |
} | |
state = "state." + state, state = state.split(".").join(":"), this.addEvent("design", state, { | |
value: 1 | |
}) | |
} | |
} | |
}), angular.module("ga.services.state", ["ga.utils.urlState"]).provider("gaState", function() { | |
var stateObject = {}, | |
_states = {}, | |
states = {}, | |
parse = function(string) { | |
try { | |
return JSON.parse(string) | |
} catch (e) { | |
return null | |
} | |
}; | |
this.initState = function(id, options) { | |
return _states[id] ? !0 : (options = angular.element.extend(!0, { | |
type: "none", | |
properties: {} | |
}, options), _states[id] = options, _states[id].values = {}, void(_states[id].changes = {})) | |
}, this.$get = function($rootScope, gaUtilsUrlState) { | |
var getPersist = function(id) { | |
var state; | |
switch (_states[id].type) { | |
case "url": | |
state = gaUtilsUrlState.getState(); | |
break; | |
case "sessionStorage": | |
case "localStorage": | |
state = parse(window[_states[id].type].getItem("ga.state." + id)) | |
} | |
_states[id].values = state || {} | |
}, | |
setPersist = function(id) { | |
var state = states[id].serialize(!0); | |
switch (_states[id].type) { | |
case "url": | |
gaUtilsUrlState.setState(state); | |
break; | |
case "sessionStorage": | |
case "localStorage": | |
window[_states[id].type].setItem("ga.state." + id, JSON.stringify(state)) | |
} | |
}, | |
emitChanges = function(id, key) { | |
var _state = _states[id], | |
state = states[id]; | |
clearTimeout(_state.timer), _state.changes[key] = _state.changes[key] || { | |
oldVal: state[key] | |
}, _state.timer = setTimeout(function() { | |
angular.forEach(_state.changes, function(change, k) { | |
change.newVal = state[k] | |
}), $rootScope.$broadcast(id + ".state", _state.changes), _state.changes = {}, setPersist(id) | |
}.bind(this)) | |
}, | |
get = function(id, key) { | |
var state = _states[id], | |
property = state.properties[key], | |
value = void 0 === state.values[key] ? property.init : state.values[key]; | |
return value | |
}, | |
set = function(id, key, value) { | |
var state = _states[id], | |
property = state.properties[key]; | |
if ("function" == typeof property.valid && !property.valid(value)) throw new TypeError("invalid value"); | |
if ("string" == typeof property.valid && typeof value !== property.valid) throw new TypeError("invalid value"); | |
angular.equals(value, _states[id].values[key]) || (emitChanges(id, key), state.values[key] = value) | |
}, | |
createState = function(state, id) { | |
getPersist(id), states[id] = {}, Object.defineProperty(stateObject, id, { | |
enumerable: !0, | |
get: function() { | |
return states[id] | |
} | |
}), Object.defineProperties(states[id], { | |
serialize: { | |
enumerable: !1, | |
value: function(excludeDefaults) { | |
var state = {}; | |
return angular.forEach(_states[id].properties, function(property, key) { | |
var value = states[id][key]; | |
excludeDefaults && value === property.init || (state[key] = value) | |
}), state | |
} | |
} | |
}), angular.forEach(_states[id].properties, function(property, key) { | |
Object.defineProperty(states[id], key, { | |
enumerable: !0, | |
get: get.bind(null, id, key), | |
set: set.bind(null, id, key) | |
}) | |
}) | |
}; | |
return angular.forEach(_states, createState), stateObject | |
} | |
}), angular.module("ga.services.content", []).service("gaServicesContent", function($q, $http, $templateCache) { | |
var notFoundTemplate = '<h1>Page not found</h1><h2>The page you were looking for was not found</h2><section><a data-href="/content/sdk">Go back</a></section>', | |
_content = {}, | |
parseElement = function(root, selector) { | |
try { | |
var element = root.find(selector).get(0); | |
return { | |
content: element.innerHTML || " ", | |
empty: !element.innerHTML, | |
inherit: null !== element.getAttribute("data-inherit") | |
} | |
} catch (e) { | |
return { | |
content: " ", | |
empty: !0 | |
} | |
} | |
}, | |
getUrl = function(section, page) { | |
return "static/ga-app/content/" + section + "/" + (page || "index") + ".html" | |
}; | |
this.loadContent = function(section, page) { | |
return $http.get(getUrl(section, page)).then(function(response) { | |
var matches = response.data.match(/<ga-content-code>([\S\s]*?)<\/ga-content-code>/g) || []; | |
return matches.forEach(function(match) { | |
var tmp = match.match(/<ga-content-code>([\S\s]*?)<\/ga-content-code>/); | |
response.data = response.data.replace(match, "<ga-content-code>" + tmp[1].replace(/</g, "<").replace(/>/g, ">") + "</ga-content-code>") | |
}), $q.when(this.putContent(section, page, response.data)) | |
}.bind(this)).catch(function() { | |
return $q.when(this.putContent(section, page, notFoundTemplate)) | |
}.bind(this)) | |
}, this.putContent = function(section, page, content) { | |
var root = angular.element("<div>" + content + "</div>"); | |
root.find("[data-href]").each(function() { | |
this.setAttribute("ng-href", "{{ gameId ? '/game/' + gameId : '' }}" + this.getAttribute("data-href")), this.removeAttribute("data-href") | |
}); | |
var parsed = { | |
header: parseElement(root, ">header"), | |
h1: parseElement(root, ">h1"), | |
h2: parseElement(root, ">h2"), | |
aside: parseElement(root, ">aside"), | |
section: parseElement(root, ">section"), | |
footer: parseElement(root, ">footer"), | |
finish: parseElement(root, "[data-finish]") | |
}; | |
page ? parsed.parent = _content[section] : parsed.children = [], angular.forEach(parsed, function(data, key) { | |
data.template = "content/" + section + "/" + (page || "index") + "/_el/" + key, $templateCache.put(data.template, data.content) | |
}); | |
var steps = root.find("[data-steps] > li"); | |
return steps.length && (parsed.steps = [], steps.each(function(index) { | |
var $this = angular.element(this), | |
step = { | |
title: this.getAttribute("data-title"), | |
nextStep: this.getAttribute("data-next-step") || "", | |
header: parseElement($this, ">header"), | |
h1: parseElement($this, ">h1"), | |
h2: parseElement($this, ">h2"), | |
aside: parseElement($this, ">aside"), | |
section: parseElement($this, ">section"), | |
footer: parseElement($this, ">footer") | |
}; | |
angular.forEach(step, function(data, key) { | |
"object" == typeof data && (data.template = "content/" + section + "/" + (page || "index") + "/_el/" + index + "/" + key), $templateCache.put(data.template, data.content) | |
}), parsed.steps.push(step) | |
})), page ? _content[section][page] = parsed : _content[section] = parsed, parsed | |
}, this.get = function(section, page) { | |
return _content[section] ? page ? _content[section][page] ? $q.when(_content[section][page]) : this.loadContent(section, page) : $q.when(_content[section]) : this.loadContent(section).then(function() { | |
return page ? this.loadContent(section, page) : $q.when(_content[section]) | |
}.bind(this)) | |
} | |
}), angular.module("ga.services.pardot", []).service("gaServicesPardot", function($window, $q) { | |
function loadScripts(src) { | |
var deferred = $q.defer(), | |
script = document.createElement("script"); | |
script.src = src, script.onload = script.onreadystatechange = function() { | |
script.onreadystatechange = script.onload = null, deferred.resolve() | |
}; | |
var head = document.getElementsByTagName("head")[0]; | |
return (head || document.body).appendChild(script), deferred.promise | |
} | |
var piAId = "21732", | |
piCIds = { | |
loginSignup: "2011", | |
invited: "2071" | |
}, | |
pardotLoaded = ("https:" === window.location.protocol ? "https://go.pardot.com/" : "http://easy.gameanalytics.com/", !1), | |
pardot = function() { | |
if (pardotLoaded) return $q.when(!1); | |
var src = ("https:" === document.location.protocol ? "https://pi" : "http://cdn") + ".pardot.com/pd.js"; | |
return loadScripts(src).then(function() { | |
return pardotLoaded = !0, $q.when(!0) | |
}) | |
}; | |
this.trackPage = function(campaign) { | |
piCIds[campaign] && ($window.piAId = piAId, $window.piCId = piCIds[campaign], pardot().then(function(loaded) { | |
loaded || setTimeout(function() { | |
piTracker() | |
}) | |
})) | |
}, this.addProspect = function(email, token) { | |
var iframe = '<iframe height="1" width="1" frameBorder="0" src="/pardot/iframe/' + email + "/" + token + '"></iframe>'; | |
return angular.element("body").append(iframe), $q.when(!0) | |
} | |
}), angular.module("ga.services.announcement", ["ga.utils.cookie", "ga.utils.detect"]).service("gaServicesAnnouncement", function(gaUtilsCookie, gaDetect) { | |
var $announcementContainer, template = function(options, contentOnly) { | |
var html = []; | |
return !contentOnly && html.push('<li class="' + (options.style || "") + '" data-id="' + options.id + '">'), html.push('<div class="' + (options.icon || "") + ' icon-padding">'), html.push(options.content || ""), options.close && html.push('<div class="ga-icon-delete"></div>'), html.push("</div>"), !contentOnly && html.push("</li>"), html.join("") | |
}, | |
activeAnnouncements = {}, | |
announcementsCount = 0; | |
$announcementContainer = "windows" === gaDetect.OS() ? angular.element('<ul class="ga announcements"><li class="overlay"><iframe frameborder="0"></iframe></li></ul>').appendTo("body") : angular.element('<ul class="ga announcements"></ul>').appendTo("body"), this.hide = function(id) { | |
var options = activeAnnouncements[id]; | |
if (options) { | |
var element = $announcementContainer.find("li[data-id=" + options.id + "]"); | |
if (!element.length) return void delete activeAnnouncements[id]; | |
options.cookie && gaUtilsCookie.set("ga-announcement-" + options.id, 1, 365), element.removeClass("show"), setTimeout(function() { | |
element.remove() | |
}, 300), delete activeAnnouncements[id], announcementsCount--, angular.element("body").removeClass("a" + (announcementsCount + 1)), angular.element("body").addClass("a" + announcementsCount) | |
} | |
}, this.add = function(options) { | |
if (options = angular.element.extend({ | |
id: Math.random().toString().replace(".", ""), | |
style: "", | |
icon: "", | |
content: "", | |
cookie: !1, | |
replace: !1, | |
close: !0 | |
}, options || {}), options.cookie && gaUtilsCookie.get("ga-announcement-" + options.id)) return !1; | |
if (activeAnnouncements[options.id]) { | |
if (options.replace) { | |
var container = $announcementContainer.find("li[data-id=" + options.id + "]"), | |
stateOptions = activeAnnouncements[options.id]; | |
return container.removeClass(stateOptions.style).addClass(options.style), stateOptions.content = options.content, stateOptions.close = options.close || stateOptions.close, stateOptions.icon = options.icon || stateOptions.icon, stateOptions.style = options.style || stateOptions.style, void container.html(template(stateOptions, !0)) | |
} | |
} else { | |
announcementsCount++, activeAnnouncements[options.id] = options; | |
var element = angular.element(template(options)); | |
$announcementContainer.prepend(element), setTimeout(function() { | |
element.addClass("show"), angular.element("body").removeClass("a" + (announcementsCount - 1)), angular.element("body").addClass("a" + announcementsCount) | |
}) | |
} | |
}, $announcementContainer.on("click", ".ga-icon-delete, .hide-me", function(e) { | |
var id = angular.element(e.target).closest("li[data-id]").data("id"); | |
this.hide(id) | |
}.bind(this)) | |
}), angular.module("ga.services.dialogs", ["ga.ui.modal", "ga.dialogs.metricpicker", "ga.dialogs.access", "ga.dialogs.linkGame", "ga.dialogs.archive", "ga.dialogs.emailReportsPreview"]).service("gaDialogs", function($q, $rootScope, $timeout, gaUiModal) { | |
this.metricpickerNew = function(gameId, metric) { | |
return gaUiModal.page({ | |
controller: "gaDialogsMetricpicker", | |
templateUrl: "/static/ga-app/modules/dialogs/metricpicker/metricpicker.html", | |
width: 700, | |
parameters: { | |
gameId: gameId, | |
metric: metric | |
} | |
}) | |
}, this.access = function(options) { | |
return gaUiModal.page({ | |
controller: "gaDialogsAccess", | |
templateUrl: "/static/ga-app/modules/dialogs/access/access.html", | |
width: 700, | |
parameters: { | |
options: options | |
} | |
}) | |
}, this.linkGame = function(options) { | |
return gaUiModal.page({ | |
controller: "gaDialogsLinkGame", | |
templateUrl: "/static/ga-app/modules/dialogs/link-game/link-game.html", | |
width: 700, | |
parameters: { | |
options: options | |
} | |
}) | |
}, this.emailReportsPreview = function(options) { | |
return gaUiModal.page({ | |
controller: "gaDialogsEmailReportsPreview", | |
templateUrl: "/static/ga-app/modules/dialogs/email-reports-preview/email-reports-preview.html", | |
width: 700, | |
parameters: { | |
options: options | |
} | |
}) | |
}, this.archive = function(studiosAndGames) { | |
return gaUiModal.page({ | |
controller: "gaDialogsArchive", | |
templateUrl: "/static/ga-app/modules/dialogs/archive/archive.html", | |
width: 700, | |
parameters: { | |
studiosAndGames: studiosAndGames | |
} | |
}) | |
}, this.metricPicker = function(event, category, filter) { | |
var deferred = $q.defer(), | |
$tmpScope = $rootScope.$new(!0); | |
event && category && ($tmpScope.tmpMetric = { | |
event: event, | |
category: category | |
}); | |
var tmpListener = $tmpScope.$watch("tmpMetric", function(newVal, oldVal) { | |
newVal !== oldVal && ($timeout(function() { | |
gaUiModal.hide("subModal") | |
}), deferred.resolve($tmpScope.tmpMetric)) | |
}); | |
return $tmpScope.filter = filter || null, gaUiModal.show({ | |
header: "Select a metric", | |
scope: $tmpScope, | |
iframe: !0, | |
newScope: !1, | |
width: 720, | |
customClass: "secondary", | |
content: '<ga-ui-metricpicker metric="tmpMetric" filter="filter"></ga-ui-metricpicker>', | |
buttons: [{ | |
title: "Cancel", | |
"class": "ga-btn-alt", | |
keyCode: 27 | |
}], | |
always: function() { | |
tmpListener(), $tmpScope.$destroy(), deferred.reject() | |
} | |
}, "subModal"), deferred.promise | |
} | |
}), angular.module("ga.dialogs.metricpicker", ["ga.api.data"]).service("gaDialogsMetricpickerService", function($q, gaApiData) { | |
var metrics = {}, | |
loadMetrics = function(gameId) { | |
return gaApiData.getValue("/metrics", gameId).then(function(rawData) { | |
return rawData | |
}) | |
}, | |
parseMetrics = function(rawMetrics) { | |
angular.forEach(rawMetrics, function(metrics, category) { | |
console.log(category, metrics.length, "metrics") | |
}) | |
}; | |
this.getMetrics = function(gameId) { | |
return metrics[gameId] ? $q.when(metrics[gameId]) : loadMetrics(gameId).then(function(rawMetrics) { | |
return parseMetrics(rawMetrics), $q.when(rawMetrics) | |
}) | |
} | |
}).controller("gaDialogsMetricpicker", function($scope, $q, gaDialogsMetricpickerService) { | |
return $scope.gameId ? void gaDialogsMetricpickerService.getMetrics($scope.gameId) : void $scope._reject() | |
}), angular.module("ga.dialogs.access", ["ga.api.userDb.authenticated.invite", "ga.api.userDb.authenticated.game", "ga.api.userDb.authenticated.studio", "ga.ui.notify", "ga.ui.modal"]).controller("gaDialogsAccess", function($scope, gaApiUserDbAuthenticatedInvite, gaApiUserDbAuthenticatedGame, gaApiUserDbAuthenticatedStudio, gaUiNotify, gaUiModal) { | |
$scope.accessType = $scope.options.type; | |
var entityTitle = $scope.options.title; | |
$scope.user = { | |
email: "" | |
}, $scope.isInvite = $scope.options.userAccessId ? !1 : !0, $scope.requestActive = !1, $scope.isInvite ? ($scope.title = "Invite user to " + entityTitle, $scope.btnTitle = "Send invite", $scope.selectedRole = null, $scope.invite = !0, $scope.emailReports = { | |
daily: !1, | |
weekly: !0, | |
monthly: !1 | |
}) : ($scope.username = entityTitle, $scope.title = "Edit role for " + entityTitle, $scope.btnTitle = "Save changes", $scope.selectedRole = 1 === parseInt($scope.options.role, 10) ? "admin" : "viewer", $scope.invite = !1), $scope.delete = function() { | |
if (!$scope.requestActive && !$scope.isInvite) { | |
$scope.requestActive = !0; | |
var userAccessId = parseInt($scope.options.userAccessId, 10); | |
userAccessId && gaUiModal.confirm("Please confirm that you want to revoke " + $scope.accessType + " access for " + entityTitle + ".", "Revoke access", !1, { | |
hideClose: !0 | |
}).then(function() { | |
gaApiUserDbAuthenticatedInvite.delete({ | |
type: $scope.accessType, | |
id: userAccessId | |
}).then(function() { | |
$scope.requestActive = !1, $scope._resolve({ | |
deletion: !0 | |
}) | |
}) | |
}).catch(function() { | |
$scope.requestActive = !1 | |
}) | |
} | |
}, $scope.save = function() { | |
if (!$scope.requestActive) | |
if ($scope.requestActive = !0, $scope.invite) { | |
var reports = []; | |
$scope.emailReports.daily && reports.push("daily"), $scope.emailReports.weekly && reports.push("weekly"), $scope.emailReports.monthly && reports.push("monthly"), "game" === $scope.options.type ? gaApiUserDbAuthenticatedGame.addUser($scope.options.gameId, $scope.user.email, "admin" === $scope.selectedRole ? 1 : 2, reports).then(function(result) { | |
result = result && result.length > 0 ? result[0] : {}, $scope.requestActive = !1, $scope._resolve(result) | |
}).catch(function(result) { | |
$scope.requestActive = !1, gaUiNotify.show(result[0].msg, 6e3, "warning") | |
}) : gaApiUserDbAuthenticatedStudio.addUser($scope.options.studioId, $scope.user.email, "admin" === $scope.selectedRole ? 1 : 2, reports).then(function() { | |
$scope.requestActive = !1, $scope._resolve() | |
}).catch(function(result) { | |
gaUiNotify.show(result[0].msg, 6e3, "warning"), $scope.requestActive = !1 | |
}) | |
} else gaApiUserDbAuthenticatedInvite.change({ | |
type: $scope.options.type, | |
id: parseInt($scope.options.userAccessId, 10), | |
role: "admin" === $scope.selectedRole ? 1 : 2 | |
}).then(function() { | |
$scope._resolve(), $scope.requestActive = !1 | |
}) | |
} | |
}), angular.module("ga.dialogs.linkGame", ["ga.ui.floatLabel", "ga.api.userDb.authenticated.appfigures"]).controller("gaDialogsLinkGame", function($scope, gaApiUserDbAuthenticatedAppfigures) { | |
$scope.game = angular.copy($scope.options.game), $scope.iconPath = "/static/ga-app/images/stores/", $scope.apps = [], $scope.state = null, $scope.search = function() { | |
$scope.state = "searching", $scope.apps = [], gaApiUserDbAuthenticatedAppfigures.search($scope.game.title).then(function(results) { | |
$scope.searching = !1, results && results.length ? ($scope.state = null, $scope.apps = results.map(function(app) { | |
return "google_play" === app.store ? app.storeIcon = "google-play.png" : "apple" === app.store && "Desktop" === app.devices[0] ? app.storeIcon = "mac.png" : "apple" === app.store ? app.storeIcon = "ios.png" : "amazon_appstore" === app.store && (app.storeIcon = "amazon.png"), app | |
})) : $scope.state = "no_results" | |
}).catch(function(error) { | |
console.log(error) | |
}) | |
}, $scope.selectApp = function(app) { | |
$scope._resolve(app) | |
} | |
}), angular.module("ga.dialogs.archive", ["ga.api.userDb.authenticated.game", "ga.api.userDb.authenticated.studio", "ga.ui.notify", "ga.utils.helpers"]).controller("gaDialogsArchive", function($q, $scope, gaUiNotify, gaApiUserDbAuthenticatedGame, gaApiUserDbAuthenticatedStudio, gaHelpers) { | |
$scope.studiosAndGamesCopy = gaHelpers.copy($scope.studiosAndGames).filter(function(studio) { | |
return !studio.demo | |
}), angular.forEach($scope.studiosAndGamesCopy, function(studio) { | |
studio.archivedChange = studio.archived, angular.forEach(studio.games, function(game) { | |
game.archivedChange = game.archived, game.archivedGameVisual = studio.archived ? !0 : game.archived | |
}) | |
}), $scope.title = "Archive", $scope.changed = !1, $scope.changedStudios = [], $scope.changedGames = [], $scope.requestActive = !1; | |
var gameArchiveRequest = function(gameId, archived) { | |
return gaApiUserDbAuthenticatedGame.archiveGame(gameId, archived) | |
}, | |
studioArchiveRequest = function(studioId, archived) { | |
return gaApiUserDbAuthenticatedStudio.archiveStudio(studioId, archived) | |
}; | |
$scope.save = function() { | |
$scope.requestActive = !0; | |
var promises = []; | |
angular.forEach($scope.changedStudios, function(changedStudio) { | |
promises.push(studioArchiveRequest(changedStudio.id, changedStudio.archived)) | |
}), angular.forEach($scope.changedGames, function(changedGame) { | |
promises.push(gameArchiveRequest(changedGame.id, changedGame.archived)) | |
}), promises.length && $q.all(promises).then(function() { | |
$scope.requestActive = !1, $scope._resolve() | |
}).catch(function(result) { | |
$scope.requestActive = !1, gaUiNotify.show(result[0].msg, 6e3, "warning") | |
}) | |
}; | |
var clickStudio = function(studio) { | |
var studioCheckboxState = !studio.archivedChange; | |
studio.archivedChange = studioCheckboxState, studioCheckboxState === !0 ? angular.forEach(studio.games, function(game) { | |
game.archivedGameVisual = !0 | |
}) : angular.forEach(studio.games, function(game) { | |
game.archivedGameVisual = game.archivedChange | |
}), checkChanges() | |
}, | |
clickGame = function(game, studio) { | |
var gameCheckboxState = !game.archivedGameVisual; | |
studio.archivedChange === !0 && (gameCheckboxState = !0), game.archivedChange = gameCheckboxState, game.archivedGameVisual = gameCheckboxState, studio.archivedChange === !0 && (angular.forEach(studio.games, function(studioGame) { | |
studioGame.archivedChange !== studioGame.archivedGameVisual && studioGame.id !== game.id && (studioGame.archivedGameVisual = studioGame.archivedChange) | |
}), studio.archivedChange = !1), checkChanges() | |
}, | |
checkChanges = function() { | |
$scope.changedStudios = [], $scope.changedGames = [], angular.forEach($scope.studiosAndGamesCopy, function(studio) { | |
studio.archivedChange !== studio.archived && $scope.changedStudios.push({ | |
id: studio.id, | |
archived: studio.archivedChange | |
}), angular.forEach(studio.games, function(game) { | |
game.archivedChange !== game.archived && $scope.changedGames.push({ | |
id: game.id, | |
archived: game.archivedChange | |
}) | |
}) | |
}), $scope.changed = $scope.changedStudios.length || $scope.changedGames.length ? !0 : !1 | |
}; | |
checkChanges(), $scope.clickStudio = clickStudio, $scope.clickGame = clickGame | |
}), angular.module("ga.dialogs.emailReportsPreview", ["ga.utils.date"]).controller("gaDialogsEmailReportsPreview", function($scope, gaUtilsDate) { | |
$scope.previewData = { | |
daily: {}, | |
weekly: {}, | |
monthly: {}, | |
title: "Daily report", | |
metrics: [1, 2] | |
}, $scope.reports = { | |
selected: "daily", | |
metrics: { | |
daily: [{ | |
v1: "123,829", | |
v2: "109,729", | |
c: 11, | |
name: "DAU", | |
description: "The total number of unique active users." | |
}, { | |
v1: "12,909", | |
v2: "15,521", | |
c: -20, | |
name: "Installs", | |
description: "The number of unique users observed for the first time for your game by the GA servers." | |
}, { | |
v1: "104,829", | |
v2: "94,019", | |
c: 10, | |
name: "Conversion to paying", | |
description: "The number of players that made their first in-game purchase." | |
}, { | |
v1: "102", | |
v2: "77", | |
c: 24, | |
name: "Paying Users", | |
description: "The total number of unique paying users." | |
}, { | |
v1: "51%", | |
v2: "49%", | |
c: 2, | |
name: "Retention Day 1", | |
description: "The percent of players that first started the game 1 day before the date targeted by the report and then came back on the day targeted by the report." | |
}, { | |
v1: "29%", | |
v2: "28%", | |
c: 1, | |
name: "Retention Day 7", | |
description: "The percent of players that first started the game 7 days before the date targeted by the report and then came back on the day targeted by the report." | |
}, { | |
v1: "$400.544", | |
v2: "$380.544", | |
c: 2, | |
name: "Total Revenue", | |
description: "Total amount of revenue generated for the day. All valid currencies provided are converted to USD." | |
}, { | |
v1: "$0.04", | |
v2: "$0.04", | |
c: 0, | |
name: "ARPDAU", | |
description: "Average revenue per daily active user during the day. All valid currencies provided are converted to USD." | |
}, { | |
v1: "$18", | |
v2: "$17", | |
c: 11, | |
name: "ARPPU", | |
description: "Average revenue per paying user during the day targeted by the report. All valid currencies provided are converted to USD." | |
}], | |
weekly: [{ | |
v1: "982,038", | |
v2: "923,711", | |
c: 6, | |
name: "WAU", | |
description: "The total number of unique active users over the last 7 days." | |
}, { | |
v1: "74,661", | |
v2: "75,942", | |
c: -2, | |
name: "Weekly Installs", | |
description: "The number of unique users observed for the first time for your game by the GA servers." | |
}, { | |
v1: "710,682", | |
v2: "702,777", | |
c: 1, | |
name: "Conversion to paying", | |
description: "The number of players that made their first in-game purchase." | |
}, { | |
v1: "634", | |
v2: "601", | |
c: 5, | |
name: "Paying Users (Avg. daily)", | |
description: "The average of the daily number of unique paying users over the last 7 days." | |
}, { | |
v1: "43%", | |
v2: "46%", | |
c: -3, | |
name: "Retention Day 1", | |
description: "For weekly Day 1 Retention, we define a different weekly period, which is the week targeted by the report minus 1 day. Thus, Day 1 Retention is the percent of players that first started the game some day within the weekly period defined above and then returned 1 day later." | |
}, { | |
v1: "22%", | |
v2: "21%", | |
c: 1, | |
name: "Retention Day 7", | |
description: "For weekly Day 7 Retention, we define a different weekly period, which is the week targeted by the report minus 7 days. Thus, Day 7 Retention is the percent of players that first started the game some day within the weekly period defined above and then returned 7 days later." | |
}, { | |
v1: "$400.544", | |
v2: "$380.544", | |
c: 2, | |
name: "Total Revenue", | |
description: "Total amount of revenue generated for the week. All valid currencies provided are converted to USD." | |
}, { | |
v1: "$0.04", | |
v2: "$0.04", | |
c: 0, | |
name: "ARPDAU", | |
description: "Average revenue per daily active user during the week. All valid currencies provided are converted to USD." | |
}, { | |
v1: "$18", | |
v2: "$17", | |
c: 11, | |
name: "ARPPU", | |
description: "Average revenue per daily paying user, over the days of the week targeted by the report. All valid currencies provided are converted to USD." | |
}], | |
monthly: [{ | |
v1: "1,71M", | |
v2: "1,64M", | |
c: 4, | |
name: "MAU", | |
description: "The total number of unique active users over the last 30 days." | |
}, { | |
v1: "317,616", | |
v2: "278,011", | |
c: 12, | |
name: "Monthly Installs", | |
description: "The number of unique users observed for the first time for your game by the GA servers." | |
}, { | |
v1: "1,2M", | |
v2: "1,01M", | |
c: 25, | |
name: "Conversion to Paying", | |
description: "The number of players that made their first in-game purchase." | |
}, { | |
v1: "1210", | |
v2: "1592", | |
c: -24, | |
name: "Paying Users (Avg. daily)", | |
description: "The average of the daily number of unique paying users over the last month." | |
}, { | |
v1: "41%", | |
v2: "39%", | |
c: 2, | |
name: "Retention Day 1", | |
description: "For monthly Day 1 Retention, we define a different monthly period, which is the month targeted by the report minus 1 day. Thus, Day 1 Retention is the percent of players that first started the game some day within the monthly period defined above and then returned 1 day later." | |
}, { | |
v1: "18%", | |
v2: "14%", | |
c: 4, | |
name: "Retention Day 7", | |
description: "For monthly Day 7 Retention, we define a different monthly period, which is the month targeted by the report minus 7 days. Thus, Day 7 Retention is the percent of players that first started the game some day within the monthly period defined above and then returned 7 days later." | |
}, { | |
v1: "12%", | |
v2: "6%", | |
c: 6, | |
name: "Retention Day 30", | |
description: "For monthly Day 30 Retention, we define a different monthly period, which is the month targeted by the report minus 30 days. Thus, Day 30 Retention is the percent of players that first started the game some day within the monthly period defined above and then returned 30 days later." | |
}, { | |
v1: "$400.544", | |
v2: "$380.544", | |
c: 2, | |
name: "Total Revenue", | |
description: "Total amount of revenue generated for the month. All valid currencies provided are converted to USD." | |
}, { | |
v1: "$0.04", | |
v2: "$0.04", | |
c: 0, | |
name: "ARPDAU", | |
description: "Average revenue per daily active user during the month. All valid currencies provided are converted to USD." | |
}, { | |
v1: "$18", | |
v2: "$17", | |
c: 11, | |
name: "ARPPU", | |
description: "Average revenue per daily paying user, over the days the month targeted by the report. All valid currencies provided are converted to USD." | |
}] | |
} | |
}, $scope.previewData.daily = { | |
title: "Daily report", | |
date1: gaUtilsDate.moment().add("days", -1).valueOf(), | |
date2: null, | |
currentDate: gaUtilsDate.moment().valueOf(), | |
thisTitle: "Yesterday", | |
previousTitle: "A week ago", | |
metrics: [] | |
}, angular.forEach($scope.reports.metrics.daily, function(metric) { | |
var percent = metric.c; | |
$scope.previewData.daily.metrics.push({ | |
name: metric.name, | |
current: metric.v1, | |
last: metric.v2, | |
percent: parseInt(Math.abs(percent), 10).toString() + "%", | |
color: percent ? 0 > percent ? "#C30000" : "#00C300" : "#C3C3C3", | |
change: percent ? 0 > percent ? "∨" : "∧" : "" | |
}) | |
}), $scope.previewData.weekly = { | |
title: "Weekly report", | |
date1: gaUtilsDate.moment().startOf("week").add("days", -6).valueOf(), | |
date2: gaUtilsDate.moment().startOf("week").add("days").valueOf(), | |
currentDate: gaUtilsDate.moment().startOf("week").add("days", 1).valueOf(), | |
thisTitle: "Last week", | |
previousTitle: "Previous period", | |
metrics: [] | |
}, angular.forEach($scope.reports.metrics.weekly, function(metric) { | |
var percent = metric.c; | |
$scope.previewData.weekly.metrics.push({ | |
name: metric.name, | |
current: metric.v1, | |
last: metric.v2, | |
percent: parseInt(Math.abs(percent), 10).toString() + "%", | |
color: percent ? 0 > percent ? "#C30000" : "#00C300" : "#C3C3C3", | |
change: percent ? 0 > percent ? "∨" : "∧" : "" | |
}) | |
}), $scope.previewData.monthly = { | |
title: "Monthly report", | |
date1: gaUtilsDate.moment().add("months", -1).startOf("month").valueOf(), | |
date2: gaUtilsDate.moment().add("months", -1).endOf("month").valueOf(), | |
currentDate: gaUtilsDate.moment().add("months", -1).endOf("month").add("days", 1).valueOf(), | |
thisTitle: "Last month", | |
previousTitle: "Previous period", | |
metrics: [] | |
}, angular.forEach($scope.reports.metrics.monthly, function(metric) { | |
var percent = metric.c; | |
$scope.previewData.monthly.metrics.push({ | |
name: metric.name, | |
current: metric.v1, | |
last: metric.v2, | |
percent: parseInt(Math.abs(percent), 10).toString() + "%", | |
color: percent ? 0 > percent ? "#C30000" : "#00C300" : "#C3C3C3", | |
change: percent ? 0 > percent ? "∨" : "∧" : "" | |
}) | |
}) | |
}), angular.module("ga.pages.studio.settings.information", ["ga.services.user", "ga.api.userDb.authenticated.studio", "ga.config", "ga.ui.notify", "ga.ui.modal"]).controller("gaPagesStudioSettingsInformationController", function($scope, $rootScope, $state, gaServicesUser, gaConfig, gaUiNotify, gaApiUserDbAuthenticatedStudio, gaUiModal) { | |
var studioId = parseInt($state.params.studioId, 10), | |
studio = gaServicesUser.studio(studioId), | |
saving = !1; | |
$scope.errors = {}, $scope.validated = !0, $scope.changed = !1, $scope.name = studio.name, $scope.imageFile = studio.imageFile, $scope.defaultImage = "/static/ga-app/images/default-studio-icon.png", $scope.imageBaseUrl = gaConfig.images.baseUrl, $scope.uploadFile = null, $scope.validate = function() { | |
0 === $scope.name.length ? ($scope.errors.name = "Name can not be zero characters", $scope.validated = !1) : ($scope.errors.name = null, $scope.validated = !0), $scope.changed = !0 | |
}, $scope.save = function(redirectObj) { | |
saving || (saving = !0, gaApiUserDbAuthenticatedStudio.saveStudio(studioId, { | |
name: $scope.name, | |
imageFile: $scope.imageFile | |
}).then(function() { | |
redirectObj ? gaServicesUser.getUserData().then(function() { | |
$rootScope.$broadcast("studioChange", null), $state.go(redirectObj.state, redirectObj.params) | |
}) : (gaUiNotify.show("Studio saved", 4e3, "default"), gaServicesUser.getUserData().then(function() { | |
$rootScope.$broadcast("studioChange", null), studio = gaServicesUser.studio(studioId), saving = !1 | |
})), $scope.changed = !1 | |
}).catch(function() { | |
gaUiNotify.show("Something went wrong while saving", 2e3, "warning"), saving = !1 | |
})) | |
}, $scope.discard = function() { | |
$scope.name = studio.name, $scope.imageFile = studio.imageFile, $scope.changed = !1 | |
}, $scope.$watch("imageFile", function(newVal, oldVal) { | |
newVal && newVal !== oldVal && ($scope.changed = !0) | |
}); | |
var ignoreSaveState = !1; | |
$scope.$on("$stateChangeStart", function(event, toState, toParams) { | |
$scope.changed && !ignoreSaveState && (event.preventDefault(), gaUiNotify.loading(!1), gaUiModal.show({ | |
scope: $scope, | |
width: 500, | |
header: "Unsaved changes", | |
content: "Do you want to save the changes you made or discard the changes and leave the page?", | |
buttons: [{ | |
title: "Save", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "save" | |
}, { | |
title: "Discard changes", | |
"class": "ga-btn-text right", | |
keyCode: 27, | |
action: "go" | |
}], | |
actions: { | |
go: function() { | |
ignoreSaveState = !0, $state.go(toState, toParams) | |
}, | |
save: function() { | |
ignoreSaveState = !0, $scope.save({ | |
state: toState, | |
params: toParams | |
}) | |
} | |
} | |
})) | |
}) | |
}), angular.module("ga.pages.studio.settings.games", ["ga.services.user", "ga.ui.modal", "ga.ui.notify", "ga.utils.tracking"]).controller("gaPagesStudioSettingsGamesController", function($scope, $state, gaUiModal, gaUiNotify, gaServicesUser, gaUtilsTracking) { | |
var studioId = parseInt($state.params.studioId, 10), | |
studio = gaServicesUser.studio(studioId); | |
$scope.games = studio.games, $scope.gotosettings = function(game) { | |
$state.go("game.settings.information", { | |
gameId: game.id | |
}) | |
}; | |
var createGame = function() { | |
var promise = gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/user/game-create/game-create.html", | |
controller: "gaPagesUserGameCreateController", | |
parameters: { | |
studioId: studioId, | |
step: 2 | |
} | |
}); | |
gaUtilsTracking.trackPageRaw("/game/add"), promise.then(function(newGameId) { | |
gaUiNotify.show("Game successfully created", 4e3, "default"), $state.go("game.content.section", { | |
section: "sdk", | |
gameId: newGameId | |
}) | |
}) | |
}; | |
$scope.createGame = createGame | |
}), angular.module("ga.pages.studio.settings.users", ["ga.api.userDb.authenticated.studio", "ga.api.userDb.authenticated.invite", "ga.services.user", "ga.config", "ga.ui.notify", "ga.services.dialogs", "ga.ui.modal"]).controller("gaPagesStudioSettingsUsersController", function($scope, $state, gaConfig, gaServicesUser, gaUiModal, gaUiNotify, gaDialogs, gaApiUserDbAuthenticatedStudio, gaApiUserDbAuthenticatedInvite) { | |
var studioId = parseInt($state.params.studioId, 10), | |
studio = gaServicesUser.studio(studioId), | |
defaultImage = "/static/ga-app/images/default-game-icon.png", | |
imageBaseUrl = gaConfig.images.baseUrl, | |
getUsers = function() { | |
gaApiUserDbAuthenticatedStudio.getStudioUsers(studioId).then(function(result) { | |
var users = [], | |
tmpOwner = { | |
email: result.owner.email, | |
invite: !1, | |
name: result.owner.first_name + " " + result.owner.last_name, | |
role: "Studio owner", | |
owner: !0, | |
self: !1 | |
}; | |
gaServicesUser.id === result.owner.id && (tmpOwner.self = !0), users.push(tmpOwner); | |
var games = []; | |
if (result.accesses && result.accesses.length) { | |
var invited = [], | |
members = []; | |
result.accesses.some(function(usr) { | |
if (usr.invite_pending) invited.push({ | |
email: usr.invite_email, | |
invite: !0, | |
id: usr.id, | |
role: getStudioRole(usr.role_id) | |
}); | |
else { | |
var tmpUsr = { | |
email: usr.email, | |
invite: !1, | |
id: usr.id, | |
userId: usr.user_id, | |
name: usr.first_name + " " + usr.last_name, | |
role: getStudioRole(usr.role_id), | |
roleId: usr.role_id, | |
self: !1 | |
}; | |
gaServicesUser.id === usr.user_id ? (tmpUsr.self = !0, users.unshift(tmpUsr)) : members.push(tmpUsr) | |
} | |
}), members = members.sort(function(a, b) { | |
return a.name.localeCompare(b.name) | |
}), users = users.concat(members), invited = invited.sort(function(a, b) { | |
return a.email.localeCompare(b.email) | |
}), users = users.concat(invited) | |
} | |
$scope.studioUsers = users, result.games && result.games.length && (result.games = result.games.sort(function(a, b) { | |
return a.title.localeCompare(b.title) | |
}), games = [], result.games.some(function(game) { | |
var tmpGame = { | |
gameTitle: game.title, | |
imagePath: game.image_file ? imageBaseUrl + game.image_file : defaultImage, | |
id: game.id, | |
users: [] | |
}; | |
if (game.accesses) { | |
var invites = [], | |
members = []; | |
game.accesses.some(function(user) { | |
user.invite_pending ? invites.push({ | |
email: user.invite_email, | |
invite: !0, | |
name: null, | |
roleId: user.role_id, | |
role: getGameRole(user.role_id), | |
id: user.id | |
}) : members.push({ | |
email: user.email, | |
invite: !1, | |
name: user.first_name + " " + user.last_name, | |
roleId: user.role_id, | |
role: getGameRole(user.role_id), | |
id: user.id | |
}) | |
}), members = members.sort(function(a, b) { | |
return a.name > b.name | |
}), tmpGame.users = tmpGame.users.concat(members), invites = invites.sort(function(a, b) { | |
return a.email > b.email | |
}), tmpGame.users = tmpGame.users.concat(invites) | |
} | |
games.push(tmpGame) | |
})), $scope.studioGames = games | |
}).catch(function() { | |
console.log("error gettings users") | |
}) | |
}, | |
getStudioRole = function(roleid) { | |
return 1 === roleid ? "Studio admin" : "Studio viewer" | |
}, | |
getGameRole = function(roleid) { | |
return 1 === roleid ? "Game admin" : "Game viewer" | |
}; | |
$scope.gameSettings = function(id) { | |
$state.go("game.settings.information", { | |
gameId: id | |
}) | |
}, $scope.deleteInvite = function(userAccessId, type) { | |
gaUiModal.confirm("Please confirm that you wan't to delete the invitation.", "Delete invitation").then(function() { | |
gaApiUserDbAuthenticatedInvite.delete({ | |
type: type, | |
id: userAccessId | |
}).then(function() { | |
getUsers() | |
}) | |
}) | |
}, $scope.inviteStudioUser = function() { | |
gaDialogs.access({ | |
type: "studio", | |
role: null, | |
userAccessId: null, | |
studioId: studio.id, | |
title: studio.name | |
}).then(function() { | |
getUsers(), gaUiNotify.show("Studio invite has been sent", 4e3, "default") | |
}) | |
}, $scope.inviteGameUser = function(game) { | |
gaDialogs.access({ | |
type: "game", | |
role: null, | |
userAccessId: null, | |
gameId: game.id, | |
title: game.gameTitle | |
}).then(function(result) { | |
result && result.access_created === !0 ? gaUiNotify.show("User access created", 4e3, "default") : gaUiNotify.show("Game invite has been sent", 4e3, "default"), getUsers() | |
}) | |
}, $scope.editUser = function(userAccess, type, game) { | |
"studio" === type ? gaDialogs.access({ | |
type: "studio", | |
studioName: studio.name, | |
studioId: studio.id, | |
userAccessId: userAccess.id, | |
role: userAccess.roleId, | |
title: userAccess.name | |
}).then(function(result) { | |
result && result.deletion === !0 ? gaUiNotify.show("The user was removed from the studio", 4e3, "default") : gaUiNotify.show("User saved", 4e3, "default"), getUsers() | |
}) : gaDialogs.access({ | |
type: "game", | |
gameTitle: game.gameTitle, | |
studioId: studio.id, | |
role: userAccess.roleId, | |
userAccessId: userAccess.id, | |
gameId: game.id, | |
title: userAccess.name | |
}).then(function(result) { | |
result && result.deletion === !0 ? gaUiNotify.show("The user was removed from the game", 4e3, "default") : gaUiNotify.show("User saved", 4e3, "default"), getUsers() | |
}) | |
}, $scope.goToUserSettings = function() { | |
$state.go("user.settings.profile") | |
}, getUsers() | |
}), angular.module("ga.pages.amt", ["ga.api.data", "ga.api.meta", "ga.ui.modal", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.utils.date", "ga.utils.cache", "ui.router"]).filter("reverse", function() { | |
return function(items) { | |
return items.slice().reverse() | |
} | |
}).filter("filterTests", function() { | |
return function(items) { | |
return items.slice().reverse() | |
} | |
}).controller("gaPagesAmtController", function($rootScope, $scope, $q, $state, $timeout, gaApiData, gaApiMeta, gaUiModal, gaUtilsDate) { | |
$scope.metrics = null, $scope.dimensions = null, $scope.daterange = gaUtilsDate.getPeriodRange("last30Days"), $scope.compare = !1, $scope.tests = [], $scope.testStatus = 0, $scope.currentTest = null, $scope.UID = "AMT", $scope.filter = { | |
OK: !0, | |
ERROR: !0, | |
LongResponse: !0, | |
NullTotals: !0, | |
NoData: !0 | |
}, $scope.filterTableCompleted = function(item) { | |
return item.status > 1 | |
}, $scope.filterTable = function(item) { | |
var show = !1; | |
return 0 === item.status ? !1 : 1 === item.status ? !0 : (!$scope.filter.OK || 1 !== item.results.status || item.results.notes && item.results.notes.length || (show = !0), $scope.filter.ERROR && 0 === item.results.status && (show = !0), $scope.filter.LongResponse && item.results.notes && item.results.notes.indexOf("LongResponse") > -1 && (show = !0), $scope.filter.NullTotals && item.results.notes && item.results.notes.indexOf("NullTotals") > -1 && (show = !0), $scope.filter.NoData && item.results.notes && item.results.notes.indexOf("NoData") > -1 && (show = !0), show) | |
}; | |
var deferred, init = function() { | |
var metrics = $q.defer(), | |
dimensions = $q.defer(), | |
promises = { | |
metrics: metrics.promise, | |
dimensions: dimensions.promise | |
}; | |
gaApiData.getValue("/metrics", $state.params.gameId).then(function(rawData) { | |
metrics.resolve(rawData.core) | |
}), gaApiData.getValue("/dimensions", $state.params.gameId).then(function(rawData) { | |
dimensions.resolve(rawData) | |
}), $q.all(promises).then(function(data) { | |
$scope.dimensions = data.dimensions, $scope.metrics = data.metrics, $scope.tests = createTests() | |
}) | |
}, | |
createTests = function(metrics) { | |
$scope.tests = [], metrics = metrics || angular.copy($scope.metrics); | |
var tests = []; | |
return angular.forEach(metrics, function(metric) { | |
var meta = gaApiMeta.getMetric("core", metric); | |
angular.forEach(meta.aggregation, function(aggregation) { | |
if ("histogram" !== aggregation) { | |
var query = createQuery(metric); | |
query.group = meta.groupTime === !1 ? "value" : "time", query.aggregation = aggregation, tests.push({ | |
query: query, | |
status: 0, | |
results: {} | |
}), angular.forEach($scope.dimensions, function(values, dimension) { | |
var subQuerySome = angular.copy(query), | |
subQueryAll = angular.copy(query); | |
subQuerySome.filter = { | |
dimension: dimension, | |
values: values.slice(0, 3) | |
}, subQueryAll.filter = { | |
dimension: dimension, | |
values: ["*"] | |
}, tests.push({ | |
query: subQuerySome, | |
status: 0, | |
results: {} | |
}), tests.push({ | |
query: subQueryAll, | |
status: 0, | |
results: {} | |
}) | |
}) | |
} | |
}) | |
}), tests | |
}, | |
createQuery = function(metric) { | |
var meta = gaApiMeta.getMetric("core", metric), | |
query = { | |
returnAll: !0, | |
metric: { | |
category: "core", | |
event: metric | |
}, | |
interval: angular.copy($scope.daterange) | |
}; | |
return meta.currency && (query.metric.currency = "USD"), query | |
}, | |
resetTests = function() { | |
$scope.testStatus = 0, $scope.results = [], angular.forEach($scope.tests, function(test) { | |
test.status = 0, test.results = {} | |
}) | |
}, | |
cancelTests = function() { | |
deferred.reject("cancelled"), gaApiData.removeUID($scope.UID), $scope.testStatus = 2 | |
}, | |
executeTests = function() { | |
return 0 !== $scope.testStatus ? !1 : ($scope.testStatus = 1, void _executeTests()) | |
}, | |
_executeTests = function() { | |
var metricTest = null; | |
$scope.tests.some(function(test) { | |
var uncompleted = 0 === test.status; | |
return uncompleted && (metricTest = test), uncompleted | |
}), null === metricTest ? ($scope.currentTest = null, $scope.testStatus = 2) : ($scope.currentTest = metricTest, $scope.currentTest.status = 1, loadData($scope.currentTest).then(function() { | |
$scope.currentTest.status = 2, $scope.currentTest.results.status = 1, $scope.currentTest.results.notes.length && ($scope.currentTest.results.status = 2), _executeTests() | |
}, function(status) { | |
"cancelled" === status ? $scope.currentTest = null : ($scope.currentTest.status = 2, $scope.currentTest.results.status = 0, _executeTests()) | |
})) | |
}, | |
loadData = function(testObject) { | |
var time = Date.now(); | |
return deferred = $q.defer(), gaApiData.get(testObject.query, $scope.UID).then(function(responseObject) { | |
testObject.results.response = responseObject, testObject.results.time = Date.now() - time, testObject = testData(testObject), deferred.resolve(!0) | |
}, function() { | |
deferred.reject() | |
}), deferred.promise | |
}, | |
testData = function(testObject) { | |
if (testObject.results.notes = [], testObject.results.response.parsed.noData) | |
if (angular.isArray(testObject.results.response.parsed.data.timeseries)) { | |
var hasTimeData = testObject.results.response.parsed.data.timeseries.some(function(data1) { | |
return data1.data.some(function(data2) { | |
return data2.data.some(function(item) { | |
return null !== item.total | |
}) | |
}) | |
}); | |
testObject.results.notes.push(hasTimeData ? "NullTotals" : "NoData") | |
} else testObject.results.notes.push("NoData"); | |
return testObject.results.time >= 1e3 && testObject.results.notes.push("LongResponse"), testObject | |
}, | |
datepicker = function() { | |
var $tmpScope = $rootScope.$new(!0); | |
$tmpScope.range = { | |
main: angular.copy($scope.daterange), | |
compare: null | |
}, gaUiModal.show({ | |
header: "Select a date interval", | |
scope: $tmpScope, | |
newScope: !1, | |
width: 775, | |
customClass: "secondary", | |
content: '<ga-ui-datepicker-directive data-range="range" data-no-buttons></ga-ui-datepicker-directive>', | |
buttons: [{ | |
title: "Apply", | |
"class": "ga-btn-alt orange right", | |
action: "apply" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
apply: function() { | |
$scope.daterange = angular.copy($tmpScope.rangeLocal.main), $scope.tests = createTests() | |
} | |
}, | |
always: function() { | |
$tmpScope.$destroy() | |
} | |
}, "subModal") | |
}; | |
$scope.intervalTitle = function() { | |
return gaUtilsDate.getIntervalTitle($scope.daterange) | |
}, $scope.executeTests = executeTests, $scope.resetTests = resetTests, $scope.cancelTests = cancelTests, $scope.datepicker = datepicker, $timeout(init) | |
}), angular.module("ga.pages.querytester", ["ga.services.user", "ga.services.state", "ga.api.data", "ga.api.meta", "ga.utils.query", "ga.utils.transform.chart", "ga.ui.datepicker", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.ui.tooltip", "ga.ui.modal", "ga.ui.json", "ga.visualizations.chartCanvas"]).config(function(gaStateProvider) { | |
gaStateProvider.initState("querytester", { | |
type: "sessionStorage", | |
properties: { | |
interval: { | |
init: { | |
main: "last30Days", | |
compare: !1 | |
}, | |
valid: function(value) { | |
try { | |
var string = JSON.stringify(value), | |
pattern = new RegExp('^{"main":(.*?),"compare":(.*?)}{1}$'), | |
match = string.match(pattern), | |
main = typeof JSON.parse(match[1]), | |
compare = typeof JSON.parse(match[2]); | |
return "string" !== main && "object" !== main ? !1 : "boolean" !== compare && "object" !== compare ? !1 : !0 | |
} catch (e) { | |
return !1 | |
} | |
} | |
}, | |
filter: { | |
init: null, | |
valid: function(value) { | |
return null === value ? !0 : "object" == typeof value && value.dimension && angular.isArray(value.values) ? !0 : !1 | |
} | |
}, | |
group: { | |
init: "time", | |
valid: "string" | |
}, | |
aggregation: { | |
init: "mean", | |
valid: "string" | |
}, | |
currency: { | |
init: null, | |
valid: "string" | |
}, | |
metric: { | |
init: [{ | |
category: "core", | |
event: "DAU" | |
}], | |
valid: function(value) { | |
return angular.isArray(value) || null === value | |
} | |
} | |
} | |
}) | |
}).controller("gaPagesQuerytesterController", function($scope, $timeout, gaServicesUser, gaApiData, gaApiMeta, gaUtilsQuery, gaUtilsChartTransform, gaUiModal, gaState) { | |
$scope.run = function() { | |
$scope.query.returnAll = !0, $scope.running = !0, $scope.chart = { | |
settings: null | |
}, gaApiData.get($scope.query).then(function(result) { | |
$scope.running = !1, $scope.urls = result.urls.join("\n"), $scope.result = result.parsed; | |
var resultRaw = result.response; | |
$scope.resultRaw = resultRaw; | |
var chartData = { | |
left: JSON.parse(JSON.stringify(result.parsed)) | |
}; | |
chartData.left.type = "line"; | |
var settings = { | |
height: 200, | |
width: 484, | |
padding: { | |
left: 40, | |
right: 10, | |
top: 20, | |
bottom: 20 | |
}, | |
xAxis: { | |
ticks: 3 | |
}, | |
yAxis: { | |
lines: 9, | |
ticks: 3, | |
zeroLine: !0, | |
zeroArea: !0 | |
}, | |
legends: 3, | |
tooltip: !0, | |
compareToggle: !0, | |
chartData: {}, | |
inc: 0 | |
}, | |
canvasChartSettings = gaUtilsChartTransform.canvasChartSettings(chartData, settings, !1); | |
$scope.chart.settings = canvasChartSettings | |
}).catch(function(result) { | |
$scope.running = !1, $scope.result = "string" == typeof result ? { | |
error: result | |
} : { | |
error: !0 | |
}, $scope.urls = (result && result.urls || []).join("\n"); | |
var resultRaw = result && result.response; | |
$scope.resultRaw = resultRaw, $scope.chartSettings = null | |
}) | |
}, $scope.buildQuery = function() { | |
var options = { | |
range: $scope.selection.interval.selected, | |
currency: $scope.selection.currency.selected | |
}, | |
query = { | |
metric: $scope.selection.metric.selected, | |
filter: $scope.selection.filter.selected, | |
aggregation: $scope.selection.aggregation.selected, | |
group: $scope.selection.group.selected | |
}; | |
try { | |
$scope.query = gaUtilsQuery.getQuery(query, options) | |
} catch (e) { | |
$scope.query = {} | |
} | |
return setState(), !0 | |
}, $scope.metricPicker = function() { | |
var $tmpScope = $scope.$new(!0); | |
$tmpScope.tmpMetric = angular.copy($scope.selection.metric.selected && $scope.selection.metric.selected[0] || null), $tmpScope.$watch("tmpMetric", function(metric, oldMetric) { | |
return metric === oldMetric ? !1 : ($scope.selection.metric.selected = [metric], void gaUiModal.hide("main")) | |
}), gaUiModal.show({ | |
header: "Select a metric", | |
scope: $tmpScope, | |
newScope: !1, | |
width: 720, | |
content: '<ga-ui-metricpicker metric="tmpMetric"></ga-ui-metricpicker>', | |
buttons: [{ | |
title: "Cancel", | |
"class": "ga-btn-alt", | |
keyCode: 27 | |
}], | |
always: function() { | |
$tmpScope.$destroy() | |
} | |
}, "main") | |
}, $scope.dimensionPicker = function() { | |
var $tmpScope = $scope.$new(!0); | |
$tmpScope.filter = angular.copy($scope.selection.filter.selected), $tmpScope.selected = angular.copy($scope.selection.filter.selected), gaUiModal.show({ | |
header: "Select a dimension", | |
scope: $tmpScope, | |
newScope: !1, | |
width: 720, | |
content: '<ga-ui-dimensionpicker selected="selected" filter="filter"></ga-ui-dimensionpicker>', | |
buttons: [{ | |
title: "Apply", | |
"class": "ga-btn orange right", | |
action: "apply" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
apply: function() { | |
$tmpScope.selected && $tmpScope.selected.dimension && $tmpScope.selected.values.length && ($scope.selection.filter.selected = $tmpScope.selected) | |
} | |
}, | |
always: function() { | |
$tmpScope.$destroy() | |
} | |
}, "main") | |
}, $scope.meta = null; | |
var setStateTimer, testSelection = function() { | |
return $scope.selection.group.disabled = !$scope.meta, $scope.selection.aggregation.disabled = !$scope.meta, $scope.selection.currency.disabled = !$scope.meta || !$scope.meta.currency, $scope.selection.group.invalid = !1, $scope.selection.aggregation.invalid = !1, $scope.meta && ($scope.selection.group.selected && ("value" !== $scope.selection.group.selected || $scope.meta.groupValues) && ("dimension" !== $scope.selection.group.selected || $scope.selection.filter.selected) ? "time" === $scope.selection.group.selected && $scope.meta.groupTime === !1 && ($scope.selection.group.invalid = !0) : $scope.selection.group.invalid = !0, $scope.meta.aggregation.indexOf($scope.selection.aggregation.selected) < 0 && ($scope.selection.aggregation.invalid = !0)), !0 | |
}, | |
getState = function() {}, | |
setState = function() { | |
clearTimeout(setStateTimer), setStateTimer = setTimeout(function() { | |
angular.forEach($scope.selection, function(value, key) { | |
gaState.querytester[key] = value.selected | |
}) | |
}, 250) | |
}; | |
$scope.selection = {}, $scope.selection.group = { | |
selected: gaState.querytester.group | |
}, $scope.$watch("selection.group.selected", function(val, oldVal) { | |
$scope.selection.group.title = val ? val.slice(0, 1).toUpperCase() + val.slice(1) : "", val !== oldVal && testSelection() && $scope.buildQuery() | |
}), $scope.selection.aggregation = { | |
selected: gaState.querytester.aggregation | |
}, $scope.$watch("selection.aggregation.selected", function(val, oldVal) { | |
var title = (val || "").replace("event_", ""); | |
$scope.selection.aggregation.title = val ? title.slice(0, 1).toUpperCase() + title.slice(1) : "", val !== oldVal && testSelection() && $scope.buildQuery() | |
}), $scope.selection.filter = { | |
selected: gaState.querytester.filter | |
}, $scope.$watch("selection.filter.selected", function(val, oldVal) { | |
$scope.selection.filter.title = val ? val.values.map(function(a) { | |
return a | |
}).join(",") : "No dimension selected", val !== oldVal && testSelection() && $scope.buildQuery() | |
}), $scope.selection.currency = { | |
selected: gaState.querytester.currency || gaServicesUser.settings.currencyDefault | |
}, $scope.$watch("selection.currency.selected", function(val, oldVal) { | |
$scope.selection.currency.title = val ? val : "-", val !== oldVal && $scope.buildQuery() | |
}), $scope.selection.metric = { | |
selected: gaState.querytester.metric | |
}, $scope.$watch("selection.metric.selected", function(val, oldVal) { | |
val && val.length ? ($scope.meta = gaApiMeta.getMetric(val[0]), $scope.selection.metric.title = gaApiMeta.getMetricDisplay(val[0], !0)) : ($scope.meta = null, $scope.selection.metric.title = "No metric selected"), val !== oldVal && testSelection() && $scope.buildQuery() | |
}), $scope.selection.interval = { | |
selected: gaState.querytester.interval | |
}, $scope.$watch("selection.interval.selected", function(val, oldVal) { | |
switch (val.main) { | |
case "last30Days": | |
$scope.selection.interval.title = "Last 30 days"; | |
break; | |
case "lastWeek": | |
$scope.selection.interval.title = "Last week"; | |
break; | |
case "yesterday": | |
$scope.selection.interval.title = "Yesterday" | |
} | |
val !== oldVal && $scope.buildQuery() | |
}), $timeout(testSelection).then($scope.buildQuery).then(getState) | |
}), angular.module("ga.pages.querybuilder", ["ui.router", "ga.api.data", "ga.api.meta", "ga.ui.modal", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.ui.json", "ga.utils.date", "ga.utils.cache"]).controller("gaPagesQuerybuilderController", function($rootScope, $scope, $timeout, $state, gaApiData, gaApiMeta, gaUiModal, gaUtilsDate) { | |
$scope.currencies = { | |
available: gaApiMeta.getCurrencies(), | |
selectActive: !1, | |
query: "" | |
}, $scope.widget = { | |
id: 1, | |
name: "Test Widget", | |
type: "table", | |
grid: {}, | |
query: { | |
interval: gaUtilsDate.getPeriodRange("last30Days"), | |
currency: "", | |
aggregation: "", | |
group: "time", | |
metric: null, | |
filter: null, | |
noParse: "true", | |
returnAll: !0 | |
} | |
}, $scope.forceDisable = !1, $scope.$watch("widget.query.metric", function(newVal) { | |
if ($scope.widget.query.filter = null, newVal) { | |
if ($scope.meta = gaApiMeta.getMetric(newVal.category, newVal.event), $scope.meta.aggregation.indexOf($scope.widget.query.aggregation) < 0 && ($scope.widget.query.aggregation = ""), $scope.widget.query.currency = $scope.meta.currency ? "USD" : "", $scope.meta.groupTime === !1) { | |
var setAggregation = $scope.meta.aggregation.slice(0, 1); | |
setAggregation.length ? ($scope.widget.query.aggregation = setAggregation[0], $scope.forceDisable = !1) : ($scope.widget.query.aggregation = "", $scope.forceDisable = !0) | |
} | |
} else $scope.meta = null, $scope.widget.query.currency = "" | |
}); | |
var request = function() { | |
var query = angular.copy($scope.widget.query); | |
if (query.top = 10, query.interval = query.interval || gaUtilsDate.getPeriodRange("last30Days"), query.interval.start = query.interval.start, query.interval.end = query.interval.end, query.metric.currency = query.currency, query.noParse = "true" === query.noParse ? !0 : !1, query.newParser = !0, query.returnAll = !0, query.gameId = $state.params.gameId, $scope.loading = !0, query.aggregation) query.group = "dimension"; | |
else { | |
var meta = gaApiMeta.getMetric(query.metric.category, query.metric.event); | |
query.aggregation = meta.aggregation[0] || "mean" | |
} | |
var url = gaApiData.makeRequestURL(query, null, !0); | |
$scope.requestURL = gaApiData.makeRequestURL(query); | |
var promise = gaApiData.getValue(url, null, !0); | |
promise.then(function(data) { | |
$scope.loading = !1, $scope.RAW = data | |
}, function(data) { | |
$scope.loading = !1, $scope.RAW = data | |
}) | |
}, | |
metricpicker = function() { | |
var $tmpScope = $rootScope.$new(!0); | |
$tmpScope.tmpMetric = angular.copy($scope.widget.query.metric); | |
var tmpListener = $tmpScope.$watch("tmpMetric", function(newVal, oldVal) { | |
newVal !== oldVal && ($scope.widget.query.metric = angular.copy($tmpScope.tmpMetric), $timeout(function() { | |
gaUiModal.hide("subModal") | |
})) | |
}); | |
gaUiModal.show({ | |
header: "Select a metric", | |
scope: $tmpScope, | |
newScope: !1, | |
width: 720, | |
customClass: "secondary", | |
content: '<ga-ui-metricpicker metric="tmpMetric" data-no-combine></ga-ui-metricpicker>', | |
buttons: [{ | |
title: "Cancel", | |
"class": "ga-btn-alt", | |
keyCode: 27 | |
}], | |
always: function() { | |
tmpListener(), $tmpScope.$destroy() | |
} | |
}, "subModal") | |
}, | |
dimensionpicker = function() { | |
var $tmpScope = $rootScope.$new(!0); | |
$tmpScope.tmpFilter = angular.copy($scope.widget.query.filter), $tmpScope.tmpSelected = null, $tmpScope.metric = angular.copy($scope.widget.query.metric), gaUiModal.show({ | |
header: "Select a filter", | |
scope: $tmpScope, | |
newScope: !1, | |
width: 720, | |
customClass: "secondary", | |
content: '<ga-ui-dimensionpicker no-compare filter="tmpFilter" metric="metric" selected="tmpSelected"></ga-ui-dimensionpicker>', | |
buttons: [{ | |
title: "Apply", | |
"class": "ga-btn-alt orange right", | |
action: "apply" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
apply: function() { | |
$scope.widget.query.filter = $tmpScope.tmpSelected.values && $tmpScope.tmpSelected.values.length ? angular.copy($tmpScope.tmpSelected) : null | |
} | |
}, | |
always: function() { | |
$tmpScope.$destroy() | |
} | |
}, "subModal") | |
}, | |
datepicker = function() { | |
var $tmpScope = $rootScope.$new(!0); | |
$tmpScope.range = { | |
main: angular.copy($scope.widget.query.interval), | |
compare: $scope.widget.query.compareInterval ? angular.copy($scope.widget.query.compareInterval) : null | |
}, $tmpScope.compareModeAvailable = !1, gaUiModal.show({ | |
header: "Select a date interval", | |
scope: $tmpScope, | |
newScope: !1, | |
width: 775, | |
customClass: "secondary", | |
content: '<ga-ui-datepicker-directive data-range="range" data-no-buttons></ga-ui-datepicker-directive>', | |
buttons: [{ | |
title: "Apply", | |
"class": "ga-btn-alt orange right", | |
action: "apply" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
apply: function() { | |
$scope.widget.query.interval = $tmpScope.rangeLocal.main, $scope.widget.query.compareInterval = $tmpScope.compareMode ? $tmpScope.rangeLocal.compare : null | |
} | |
}, | |
always: function() { | |
$tmpScope.$destroy() | |
} | |
}, "subModal") | |
}; | |
$scope.intervalTitle = function() { | |
return gaUtilsDate.getIntervalTitles($scope.widget.query.interval, $scope.widget.query.compareInterval) | |
}, $scope.request = request, $scope.metricpicker = metricpicker, $scope.dimensionpicker = dimensionpicker, $scope.datepicker = datepicker | |
}), angular.module("ga.pages.explore", ["ga.ui.explore"]).controller("gaPagesExploreController", function($scope) { | |
$scope.exploreSettingsInit = { | |
standalone: !0 | |
} | |
}), angular.module("ga.pages.cohorts", ["ui.router", "ga.ui.datepicker", "ga.utils.date", "ga.utils.transform", "ga.utils.cache", "ga.api.meta", "ga.api.data", "ga.ui.modal", "ga.ui.tour", "ga.utils.tracking", "ga.services.user", "ga.visualizations.cohortTable", "ga.components.moment"]).controller("gaPagesCohortsController", function($scope, $rootScope, $timeout, $state, $q, $filter, $cookies, $stateParams, gaUtilsTracking, gaServicesUser, gaUiTour, gaUtilsCache, gaUtilsGridTransform, moment, gaApiData, gaApiMeta, gaUtilsDate, gaUiModal) { | |
var bgColors = ["E7EEF4", "D4E1ED", "C2D5E7", "AFC9E1", "9CBDDB", "89B0D4", "75A3CD", "6498C8", "508AC0", "3E7FBB"], | |
datepickerRanges = { | |
weeks: [{ | |
id: "last4weeks", | |
name: "Last 4 weeks" | |
}, { | |
id: "last12weeks", | |
name: "Last 12 weeks" | |
}, { | |
id: "last24weeks", | |
name: "Last 24 weeks" | |
}], | |
months: [{ | |
id: "last3months", | |
name: "Last 3 months" | |
}, { | |
id: "last6months", | |
name: "Last 6 months" | |
}, { | |
id: "last12months", | |
name: "Last 12 months" | |
}] | |
}, | |
blacklisted = ["WAU", "MAU", "session_length", "session_count", "churn_28", "event_count", "installs"], | |
defaultInterval = gaUtilsDate.getPeriodRange("last30Days"), | |
defaultDatepickerData = { | |
interval: { | |
main: { | |
start: defaultInterval.start, | |
end: defaultInterval.end | |
}, | |
compare: null | |
}, | |
selection: "last30Days", | |
compare: !1, | |
title: "Date range", | |
disableCompare: !0, | |
customRange: datepickerRanges.weeks | |
}; | |
$scope.globalOptions = { | |
datepicker: defaultDatepickerData, | |
granularity: "cohort_day", | |
showHeatmap: !0, | |
aggregation: "mean" | |
}, $scope.metricForPicker = null, $scope.metric = null, $scope.loading = !0, $scope.weekTooltipNotice = "", $scope.table = { | |
settings: { | |
maxRows: 10, | |
pager: !0, | |
colPager: !1, | |
sortable: !0, | |
more: !1, | |
totals: !0, | |
sumSwitcher: !1 | |
}, | |
tableView: "list", | |
datasets: null, | |
installCol: null | |
}, $scope.aggregations = { | |
mean: !1, | |
sum: !1, | |
event_count: !1 | |
}, $scope.nodata = !1; | |
var cachedParsedData = null; | |
$scope.datepickerWatch = $scope.$watch("globalOptions.datepicker.interval", function(newVal, oldVal) { | |
newVal === oldVal || $scope.updatingRules || performRequest() | |
}), $scope.heatmapWatch = $scope.$watch("globalOptions.showHeatmap", function(newVal, oldVal) { | |
if (newVal !== oldVal) { | |
if ($scope.loading) return; | |
gaUtilsTracking.trackEvent({ | |
category: "cohort", | |
action: "heatmap", | |
label: $scope.globalOptions.showHeatmap ? "show" : "hide" | |
}), $scope.table.showColors = $scope.globalOptions.showHeatmap, saveState() | |
} | |
}), $scope.$on("userSettingsChange", function() { | |
performRequest(), updateWeekNotice() | |
}); | |
var init = function() { | |
var cached = gaUtilsCache.get("cohort-state-" + $stateParams.gameId, "localStorage"); | |
cached ? loadState(cached) : changeMetric({ | |
category: "core", | |
currency: "", | |
event: "retention" | |
}), updateWeekNotice() | |
}, | |
updateWeekNotice = function() { | |
$scope.weekTooltipNotice = "Sunday" === gaServicesUser.settings.startOfWeek ? "Cohort weeks always start Monday" : "" | |
}, | |
saveState = function() { | |
var saveObject = { | |
metric: $scope.metric, | |
options: $scope.globalOptions | |
}; | |
delete saveObject.metric.meta, gaUtilsCache.put("cohort-state-" + $stateParams.gameId, saveObject, "localStorage", 6048e5) | |
}, | |
loadState = function(cached) { | |
if (cached.options.datepicker && "custom" !== cached.options.datepicker.selection) { | |
var interval = gaUtilsDate.getPeriodRange(cached.options.datepicker.selection); | |
cached.options.datepicker.interval.main = interval | |
} | |
$scope.globalOptions = cached.options, changeMetric(cached.metric) | |
}, | |
performRequest = function() { | |
$scope.metric && ($scope.loading = !0, "retention" === $scope.metric.event || "returning_users" === $scope.metric.event ? request() : getValidCohorts().then(function(cohorts) { | |
request(cohorts) | |
})) | |
}, | |
request = function(cohorts) { | |
var intervalEnd, intervalStart = moment($scope.globalOptions.datepicker.interval.main.start).utc(), | |
rollup = ""; | |
"cohort_week" === $scope.globalOptions.granularity ? (intervalStart = intervalStart.startOf("isoweek").unix(), intervalEnd = moment().utc().unix(), rollup = "weekly") : "cohort_month" === $scope.globalOptions.granularity ? (intervalStart = intervalStart.startOf("month").unix(), intervalEnd = moment().utc().unix(), rollup = "monthly") : (intervalStart = intervalStart.unix(), intervalEnd = moment($scope.globalOptions.datepicker.interval.main.end).utc().unix()); | |
var interval = { | |
start: 1e3 * intervalStart, | |
end: 1e3 * intervalEnd | |
}, | |
installQuery = { | |
interval: interval, | |
currency: gaServicesUser.settings.currencyDefault, | |
noAggregation: !0, | |
metric: [{ | |
category: "core", | |
currency: "", | |
event: "installs" | |
}] | |
}; | |
rollup && (installQuery.rollup = rollup); | |
var meta = gaApiMeta.getMetric($scope.metric.category, $scope.metric.event); | |
meta.currency && ($scope.metric.currency = gaServicesUser.settings.currencyDefault), $scope.metric.aggregation = $scope.globalOptions.aggregation || meta.aggregation[0] || "mean", $scope.table.settings.sumSwitcher = "mean" !== $scope.metric.aggregation ? !0 : !1; | |
var metric, noAggregation; | |
"retention" === $scope.metric.event ? (metric = { | |
category: "core", | |
currency: "", | |
event: "retention_full" | |
}, noAggregation = !1) : "returning_users" === $scope.metric.event ? (metric = { | |
category: "core", | |
currency: "", | |
event: "returning_users_full" | |
}, noAggregation = !1) : (metric = $scope.metric, noAggregation = !0); | |
var query = { | |
interval: interval, | |
aggregation: $scope.metric.aggregation, | |
noAggregation: noAggregation, | |
group: "time", | |
metric: [metric] | |
}; | |
cohorts && (query.filter = { | |
dimension: $scope.globalOptions.granularity, | |
values: cohorts | |
}, query.group = "dimension", rollup && (query.rollup = rollup)); | |
var promises = { | |
metric: gaApiData.get(query), | |
installs: gaApiData.get(installQuery) | |
}; | |
if ("retention" === $scope.metric.event) { | |
var returningUserQuery = { | |
interval: interval, | |
aggregation: "mean", | |
noAggregation: !0, | |
group: "time", | |
metric: [{ | |
category: "core", | |
currency: "", | |
event: "returning_users_full" | |
}] | |
}; | |
promises.users = gaApiData.get(returningUserQuery) | |
} else if ("returning_users" === $scope.metric.event) { | |
var retentionUserQuery = { | |
interval: interval, | |
aggregation: "mean", | |
noAggregation: !0, | |
group: "time", | |
metric: [{ | |
category: "core", | |
currency: "", | |
event: "retention_full" | |
}] | |
}; | |
promises.users = gaApiData.get(retentionUserQuery) | |
} else { | |
if (-1 === ["DAU", "MAU", "WAU"].indexOf($scope.metric.event)) { | |
var userQuery = { | |
interval: interval, | |
noAggregation: !0, | |
group: "dimension", | |
metric: [{ | |
category: "core", | |
currency: "", | |
event: "DAU" | |
}], | |
filter: { | |
dimension: $scope.globalOptions.granularity, | |
values: cohorts | |
} | |
}; | |
rollup && (userQuery.rollup = rollup), promises.users = gaApiData.get(userQuery) | |
} | |
if (["ARPDAU", "ARPPU", "paying_users"].indexOf($scope.metric.event) > -1 || "business" === $scope.metric.category) { | |
var revenueQuery = { | |
interval: interval, | |
noAggregation: !0, | |
aggregation: "sum", | |
group: "dimension", | |
metric: [{ | |
category: "core", | |
currency: gaServicesUser.settings.currencyDefault, | |
event: "revenue" | |
}], | |
filter: { | |
dimension: $scope.globalOptions.granularity, | |
values: cohorts | |
} | |
}; | |
rollup && (revenueQuery.rollup = rollup), promises.revenue = gaApiData.get(revenueQuery) | |
} | |
if (["ARPDAU", "ARPPU", "revenue"].indexOf($scope.metric.event) > -1) { | |
var payingUsersQuery = { | |
interval: interval, | |
noAggregation: !0, | |
group: "dimension", | |
metric: [{ | |
category: "core", | |
currency: gaServicesUser.settings.currencyDefault, | |
event: "paying_users" | |
}], | |
filter: { | |
dimension: $scope.globalOptions.granularity, | |
values: cohorts | |
} | |
}; | |
rollup && (payingUsersQuery.rollup = rollup), promises.payingUsers = gaApiData.get(payingUsersQuery) | |
} | |
if ("conversion" === $scope.metric.event || "converting_users" === $scope.metric.event) { | |
var conversionQuery = { | |
interval: interval, | |
noAggregation: !0, | |
group: "dimension", | |
metric: [{ | |
category: "core", | |
currency: "", | |
event: "conversion" === $scope.metric.event ? "converting_users" : "conversion" | |
}], | |
filter: { | |
dimension: $scope.globalOptions.granularity, | |
values: cohorts | |
} | |
}; | |
rollup && (conversionQuery.rollup = rollup), promises.conversion = gaApiData.get(conversionQuery) | |
} | |
} | |
saveState(), $q.all(promises).then(function(data) { | |
var installs = null; | |
data.installs && (installs = parseInstalls(data.installs, cohorts)), data.metric && parseMetric(data.metric, installs, data.users, data.revenue, data.conversion, data.payingUsers) | |
}) | |
}, | |
parseMetric = function(data, installs, users, revenue, conversion, payingUsers) { | |
if (data.noData) return $scope.nodata = !0, $scope.table.settings.maxRows = 15, $scope.table.datasets = null, $scope.table.showColors = $scope.globalOptions.showHeatmap, $scope.table.dataChanged = { | |
dataChange: !0 | |
}, void($scope.loading = !1); | |
$scope.nodata = !1, "retention" !== $scope.metric.event || gaServicesUser.onboarding.cohort && gaServicesUser.onboarding.cohort.tour || (gaServicesUser.onboarding.set("cohort", "tour", !0), gaServicesUser.onboarding.save(), runTour()); | |
var parsed = gaUtilsGridTransform.parse(data), | |
parsedUsers = null, | |
parsedRevenue = null, | |
parsedConversion = null, | |
parsedPayingUsers = null; | |
"retention" === $scope.metric.event || "returning_users" === $scope.metric.event ? users && (parsedUsers = gaUtilsGridTransform.parse(users)) : (parsed = gaUtilsGridTransform.flipData(parsed), users && (parsedUsers = gaUtilsGridTransform.parse(users), parsedUsers = gaUtilsGridTransform.flipData(parsedUsers)), revenue && (parsedRevenue = gaUtilsGridTransform.parse(revenue), parsedRevenue = gaUtilsGridTransform.flipData(parsedRevenue)), conversion && (parsedConversion = gaUtilsGridTransform.parse(conversion), parsedConversion = gaUtilsGridTransform.flipData(parsedConversion)), payingUsers && (parsedPayingUsers = gaUtilsGridTransform.parse(payingUsers), parsedPayingUsers = gaUtilsGridTransform.flipData(parsedPayingUsers))), installs && (parsed = applyInstalls(parsed, installs)), parsed = applyCohortValues({ | |
data: parsed, | |
users: parsedUsers, | |
revenue: parsedRevenue, | |
conversion: parsedConversion, | |
payingUsers: parsedPayingUsers | |
}), cachedParsedData = angular.copy(parsed); | |
var nbRows = parsed.rows.length; | |
$scope.table.settings.maxRows = nbRows > 15 && 30 >= nbRows ? nbRows : 15 >= nbRows ? 15 : 30, $scope.table.datasets = parsed, $scope.table.showColors = $scope.globalOptions.showHeatmap, $scope.table.dataChanged = { | |
dataChange: !0 | |
}, $scope.loading = !1 | |
}, | |
applyInstalls = function(data, installs) { | |
return "retention" === $scope.metric.event || "returning_users" === $scope.metric.event ? angular.forEach(installs.installs, function(install, index) { | |
data.rows[index].axis.installs = install.sum | |
}) : angular.forEach(installs.installs, function(install) { | |
data.rows.some(function(row) { | |
return row.axis.dimensionValue === install.cohort ? (row.axis.installs = install.sum, !0) : void 0 | |
}) | |
}), data.footer.axis.installs = installs.sum, data | |
}, | |
parseInstalls = function(data, cohorts) { | |
var installSum = [], | |
total = 0; | |
if ("retention" === $scope.metric.event || "returning_users" === $scope.metric.event) data.data && data.data.timeseries && data.data.timeseries.length && data.data.timeseries[0].data[0].data && angular.forEach(data.data.timeseries[0].data[0].data, function(install, index) { | |
installSum.push({ | |
index: index, | |
sum: install.total | |
}), total += install.total | |
}); | |
else if (data.data && data.data.timeseries && data.data.timeseries.length && data.data.timeseries[0].data[0].data) { | |
var installs = data.data.timeseries[0].data[0].data; | |
angular.forEach(cohorts, function(cohort) { | |
angular.forEach(installs, function(install, index) { | |
install.ts / 1e3 === parseInt(cohort) && (installSum.push({ | |
cohort: cohort, | |
index: index, | |
sum: install.total | |
}), total += install.total) | |
}) | |
}) | |
} | |
return { | |
installs: installSum, | |
sum: total | |
} | |
}, | |
getValidCohorts = function() { | |
var deferred = $q.defer(), | |
values = [], | |
interval = $scope.globalOptions.datepicker.interval.main, | |
intervalStart = 0, | |
intervalEnd = 0; | |
return "cohort_week" === $scope.globalOptions.granularity ? (intervalStart = moment(interval.start).utc().startOf("isoweek").unix(), intervalEnd = moment(interval.end).utc().endOf("isoweek").unix()) : "cohort_month" === $scope.globalOptions.granularity ? (intervalStart = moment(interval.start).utc().startOf("month").unix(), intervalEnd = moment(interval.end).utc().endOf("month").unix()) : (intervalStart = moment(interval.start).utc().unix(), intervalEnd = moment(interval.end).utc().unix()), gaApiData.getValue("/dimensions", $state.params.gameId).then(function(rawData) { | |
angular.forEach(rawData, function(dimensions, key) { | |
$scope.globalOptions.granularity === key && (angular.forEach(dimensions, function(value) { | |
value && value >= intervalStart && intervalEnd >= value && values.push(value) | |
}), deferred.resolve(values)) | |
}) | |
}), deferred.promise | |
}, | |
changeMetric = function(metric) { | |
var meta = gaApiMeta.getMetric(metric.category, metric.event); | |
metric.meta = meta, $scope.metric = metric, $scope.metricForPicker = metric, $scope.metricForPicker.eventDisplay || ($scope.metricForPicker.eventDisplay = gaApiMeta.getMetricDisplay(metric.category, metric.event)), "retention" === metric.event || "returning_users" === metric.event ? changeGranularity("cohort_day", !0) : "cohort_day" === $scope.globalOptions.granularity && changeGranularity("cohort_week", !0), $scope.aggregations.mean = -1 === meta.aggregation.indexOf("mean") && meta.aggregation.length ? !1 : !0, $scope.aggregations.sum = -1 === meta.aggregation.indexOf("sum") ? !1 : !0, $scope.aggregations.event_count = -1 === meta.aggregation.indexOf("event_count") ? !1 : !0, $scope.showDisplayValues = !$scope.aggregations.mean && ($scope.aggregations.event_count || $scope.aggregations.sum) || $scope.aggregations.event_count || $scope.aggregations.sum ? !0 : !1, $scope.aggregations[$scope.globalOptions.aggregation] || ($scope.aggregations.mean ? $scope.globalOptions.aggregation = "mean" : $scope.aggregations.sum ? $scope.globalOptions.aggregation = "sum" : $scope.aggregations.event_count && ($scope.globalOptions.aggregation = "event_count")), gaUtilsTracking.trackEvent({ | |
category: "cohort", | |
action: "metric", | |
label: metric.event | |
}), performRequest() | |
}, | |
changeGranularity = function(granularity, noreq) { | |
$scope.globalOptions.granularity !== granularity && ($scope.globalOptions.granularity = granularity, $scope.globalOptions.datepicker.customRange = "cohort_week" === granularity ? datepickerRanges.weeks : "cohort_month" === granularity ? datepickerRanges.months : null, noreq || (gaUtilsTracking.trackEvent({ | |
category: "cohort", | |
action: "granularity", | |
label: granularity | |
}), performRequest())) | |
}, | |
changeAggregation = function(aggregation, noreq) { | |
$scope.globalOptions.aggregation = aggregation, noreq || performRequest() | |
}, | |
useMetricpicker = function() { | |
var $tmpScope = $rootScope.$new(!0); | |
$tmpScope.tmpMetric = angular.copy($scope.metricForPicker); | |
var tmpListener = $tmpScope.$watch("tmpMetric", function(newVal, oldVal) { | |
newVal !== oldVal && ($timeout(function() { | |
gaUiModal.hide("subModal") | |
}), $scope.initializing = !1, changeMetric($tmpScope.tmpMetric)) | |
}); | |
$tmpScope.filter = { | |
blacklisted: blacklisted, | |
disableStarEvents: !0 | |
}, gaUiModal.show({ | |
header: "Select a metric", | |
scope: $tmpScope, | |
newScope: !1, | |
width: 720, | |
customClass: "secondary", | |
content: '<ga-ui-metricpicker metric="tmpMetric" filter="filter"></ga-ui-metricpicker>', | |
buttons: [{ | |
title: "Cancel", | |
"class": "ga-btn-alt", | |
keyCode: 27 | |
}], | |
always: function() { | |
tmpListener(), $tmpScope.$destroy() | |
} | |
}, "subModal") | |
}, | |
applyCohortValues = function(options) { | |
if (!options.data) return null; | |
var data = options.data || null, | |
users = options.users || null, | |
revenue = options.revenue || null, | |
conversion = options.conversion || null, | |
payingUsers = options.payingUsers || null, | |
max = null, | |
min = null; | |
angular.forEach(data.rows, function(row) { | |
angular.forEach(row.values, function(val) { | |
val.value && (min || max ? (min > val.value && (min = val.value), max < val.value && (max = val.value)) : (min = val.value, max = val.value)) | |
}) | |
}); | |
var delta = (max - min) / 10; | |
return angular.forEach(data.rows, function(row, index) { | |
angular.forEach(row.values, function(val, subIndex) { | |
if (val.value) { | |
var intervalIndex = Math.round((val.value - min) / delta); | |
intervalIndex || (intervalIndex = 1), val.color = bgColors[intervalIndex - 1], users && users.rows[index].values[subIndex] && (val.users = $filter("formatUnitType")(users.rows[index].values[subIndex].value, users.meta.cols[subIndex])), revenue && revenue.rows[index].values[subIndex] && (val.revenue = $filter("formatUnitType")(revenue.rows[index].values[subIndex].value, revenue.meta.cols[subIndex])), conversion && conversion.rows[index].values[subIndex] && (val.conversion = $filter("formatUnitType")(conversion.rows[index].values[subIndex].value, conversion.meta.cols[subIndex])), payingUsers && payingUsers.rows[index].values[subIndex] && (val.payingUsers = $filter("formatUnitType")(payingUsers.rows[index].values[subIndex].value, payingUsers.meta.cols[subIndex])) | |
} | |
}) | |
}), data | |
}, | |
exportToCsv = function() { | |
if (!$scope.loading) { | |
gaUtilsTracking.trackPageRaw("/game/export/cohort"); | |
var data = getCsvData(), | |
name = $scope.metric.category + "_" + $scope.metric.event + "_" + $scope.globalOptions.granularity, | |
form = angular.element("#cohort-export-csv-form"); | |
form.find("[name=X-Authorization]").val(gaServicesUser.token), form.find("[name=csv_name]").val(sanitizeCsvStr(name) + ".csv"), form.find("[name=csv_data]").val(data), form.submit() | |
} | |
}, | |
getCsvData = function() { | |
var csv = [], | |
header = [cachedParsedData.header.axis.value], | |
footer = [cachedParsedData.footer.axis.value]; | |
return $scope.table.settings.sumSwitcher && "Sum" === $scope.table.settings.sumSelected && (footer[0] = "Sum"), angular.forEach(cachedParsedData.header.values, function(value, index) { | |
0 === index && header.push("Users"), header.push(value.value + (value.subValue ? " (" + value.subValue + ")" : "")) | |
}), angular.forEach(cachedParsedData.footer.values, function(value, index) { | |
0 === index && footer.push(cachedParsedData.footer.axis.installs), footer.push($scope.table.settings.sumSwitcher && "Sum" === $scope.table.settings.sumSelected ? value.sum : value.value) | |
}), csv.push(header), angular.forEach(cachedParsedData.rows, function(row) { | |
var tmpRow = []; | |
tmpRow.push("date" === cachedParsedData.meta.axis.type ? $filter("formatUnitType")(row.axis.value, "rawdate") : row.axis.value), tmpRow.push(row.axis.installs), angular.forEach(row.values, function(value) { | |
tmpRow.push(value.value) | |
}), csv.push(tmpRow) | |
}), csv.push(footer), csv = csv.map(function(row) { | |
return row.join(";") | |
}), csv = csv.join("\n") | |
}, | |
sanitizeCsvStr = function(string) { | |
return string.replace(/\*/g, "all").replace(/[^a-z0-9]/gi, "_").replace(/_{2,}/g, "_").toLowerCase() | |
}, | |
destroyWatches = function() { | |
$scope.datepickerWatch && ($scope.datepickerWatch(), $scope.datepickerWatch = null), $scope.heatmapWatch && ($scope.heatmapWatch(), $scope.heatmapWatch = null) | |
}, | |
runTour = function() { | |
gaUiTour.reset(), gaUiTour.addStep({ | |
title: "Granulate", | |
text: "See your data broken down into days, weeks or months cohorts. Retention, specifically, is only available in Days granularity.", | |
element: ".granularityselect", | |
watcher: {}, | |
arrow: "top-left", | |
anchor: "bottom-left-center", | |
zindex: 1200, | |
skippable: !0 | |
}), gaUiTour.addStep({ | |
title: "Metrics", | |
text: "Choose from a select group of metrics.", | |
element: ".metricsselect", | |
watcher: {}, | |
arrow: "top-left", | |
anchor: "bottom-center", | |
zindex: 1200, | |
skippable: !0 | |
}), gaUiTour.addStep({ | |
title: "Toggle heatmap", | |
text: "Toggle heatmap colours in the table cells to enhance value distribution.", | |
element: ".toggleheatmap", | |
watcher: {}, | |
arrow: "top-right", | |
anchor: "bottom-right-center", | |
zindex: 1200, | |
skippable: !0 | |
}), gaUiTour.addStep({ | |
title: "Details", | |
text: "Hover a specific value cell to see even more detailed information.", | |
element: 'td[data-position="1,1"]', | |
image: "", | |
watcher: {}, | |
arrow: "top-left", | |
anchor: "bottom-left-center", | |
zindex: 1200, | |
skippable: !0 | |
}), gaUiTour.setOptions({ | |
navigation: !0 | |
}), gaUiTour.start() | |
}; | |
init(), $scope.$on("$destroy", function() { | |
destroyWatches() | |
}), $scope.useMetricpicker = useMetricpicker, $scope.changeGranularity = changeGranularity, $scope.changeAggregation = changeAggregation, $scope.exportToCsv = exportToCsv, $scope.runTour = runTour | |
}), angular.module("ga.pages.game.settings.information", ["ga.services.user", "ga.api.userDb.authenticated.game", "ga.config", "ga.ui.notify", "ga.ui.modal"]).controller("gaPagesGameSettingsInformationController", function($scope, $rootScope, $state, gaServicesUser, gaConfig, gaUiNotify, gaApiUserDbAuthenticatedGame, gaUiModal) { | |
$scope.showViewOnly = $state.$current.data.showViewOnly || !1; | |
var saving = !1, | |
gameId = parseInt($state.params.gameId, 10), | |
game = gaServicesUser.game(gameId); | |
$scope.errors = {}, $scope.validated = !0; | |
var defaultImage = "static/ga-app/images/default-game-icon.png", | |
imageBaseUrl = gaConfig.images.baseUrl; | |
$scope.uploadFile = null, $scope.gameInfo = { | |
title: game.title, | |
imageFilePath: game.imageFile ? imageBaseUrl + game.imageFile : defaultImage, | |
imageFile: game.imageFile ? game.imageFile : null, | |
changed: !1 | |
}; | |
var getkeys = function() { | |
gaApiUserDbAuthenticatedGame.getGameData(gameId).then(function(result) { | |
$scope.keys = { | |
key: result.key, | |
secret: result.secret_key, | |
api: result.data_api_key | |
} | |
}).catch(function() { | |
gaUiNotify.show("Something went wrong getting game keys", 2e3, "warning") | |
}) | |
}; | |
$scope.validate = function() { | |
0 === $scope.gameInfo.title.length ? ($scope.errors.name = "Title can not be zero characters", $scope.validated = !1) : ($scope.errors.name = null, $scope.validated = !0), $scope.gameInfo.changed = !0 | |
}, $scope.save = function(redirectObj) { | |
saving || (saving = !0, gaApiUserDbAuthenticatedGame.saveGame(gameId, { | |
title: $scope.gameInfo.title, | |
imageFile: $scope.gameInfo.imageFile | |
}).then(function() { | |
redirectObj ? gaServicesUser.getUserData().then(function() { | |
$rootScope.$broadcast("currentGameChange", null), $state.go(redirectObj.state, redirectObj.params) | |
}) : ($scope.gameInfo.changed = !1, gaUiNotify.show("Game saved", 4e3, "default"), gaServicesUser.getUserData().then(function() { | |
$rootScope.$broadcast("currentGameChange", null), game = gaServicesUser.game(gameId), saving = !1 | |
})) | |
}).catch(function() { | |
gaUiNotify.show("Something went wrong while saving", 2e3, "warning"), saving = !1 | |
})) | |
}, $scope.discard = function() { | |
$scope.gameInfo = { | |
title: game.title, | |
imageFile: game.imageFile ? game.imageFile : null, | |
imageFilePath: game.imageFile ? imageBaseUrl + game.imageFile : defaultImage, | |
changed: !1 | |
} | |
}, $scope.$watch("gameInfo.imageFile", function(newVal, oldVal) { | |
newVal && newVal !== oldVal && newVal !== game.imageFile && ($scope.gameInfo.imageFilePath = newVal ? imageBaseUrl + newVal : defaultImage, $scope.gameInfo.changed = !0) | |
}), getkeys(); | |
var ignoreSaveState = !1; | |
$scope.$on("$stateChangeStart", function(event, toState, toParams) { | |
$scope.gameInfo.changed && !ignoreSaveState && (event.preventDefault(), gaUiNotify.loading(!1), gaUiModal.show({ | |
scope: $scope, | |
width: 500, | |
header: "Unsaved changes", | |
content: "Do you want to save the changes you made or discard the changes and leave the page?", | |
buttons: [{ | |
title: "Save", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "save" | |
}, { | |
title: "Discard changes", | |
"class": "ga-btn-text right", | |
keyCode: 27, | |
action: "go" | |
}], | |
actions: { | |
go: function() { | |
ignoreSaveState = !0, $state.go(toState, toParams) | |
}, | |
save: function() { | |
ignoreSaveState = !0, $scope.save({ | |
state: toState, | |
params: toParams | |
}) | |
} | |
} | |
})) | |
}) | |
}), angular.module("ga.pages.game.settings.exportData", ["ui.router", "ga.api.data", "ga.ui.datepicker", "ga.ui.modal", "ga.utils.date", "ga.pages.game.settings.exportData.modal", "ga.components.moment"]).controller("gaPagesGameSettingsExportDataController", function($scope, $q, $compile, $timeout, $http, $state, $window, gaApiData, gaUtilsDate, gaUiModal, moment) { | |
$scope.gameId = $state.params.gameId, $scope.options = { | |
dateRange: { | |
main: { | |
start: null, | |
end: null | |
}, | |
restrictInterval: { | |
start: moment.utc({ | |
year: 2014, | |
month: 3, | |
day: 1 | |
}), | |
end: null | |
} | |
} | |
}, $scope.exportData = function() { | |
var tsStart = $scope.options.dateRange.main.start, | |
tsEnd = $scope.options.dateRange.main.end; | |
tsStart && tsEnd && ($scope.processing = !0, gaApiData.getDataDownloadLinks($scope.gameId, { | |
start: tsStart, | |
end: tsEnd | |
}).then(function(result) { | |
showDownloadModal(result), $scope.processing = !1 | |
}).catch(function() { | |
$scope.processing = !1 | |
})) | |
}; | |
var showDownloadModal = function(links) { | |
var proxyLinks = links.map(function(link) { | |
var match = link.url.match(/\/(\d{4})\/(\d{2})\/(\d{2})\/(\d+)\/(.+?)\.json\.gz\?.+?Expires=(\d+?)&Signature=(.+)/); | |
return match && 8 === match.length ? { | |
url: window.location.protocol + "//" + window.location.host + "/export-data/" + match[4] + "-" + match[1] + "-" + match[2] + "-" + match[3] + "-" + match[5] + ".json.gz?e=" + match[6] + "&s=" + match[7] | |
} : { | |
url: "invalid" | |
} | |
}).filter(function(link) { | |
return link | |
}), | |
dateTitle = gaUtilsDate.getIntervalTitle({ | |
start: gaUtilsDate.moment.utc($scope.options.dateRange.main.start), | |
end: gaUtilsDate.moment.utc($scope.options.dateRange.main.end) | |
}); | |
gaUiModal.page({ | |
controller: "gaPagesGameSettingsExportDataModalController", | |
templateUrl: "/static/ga-app/modules/pages/game/settings/export-data/export-modal.html", | |
width: 800, | |
parameters: { | |
links: proxyLinks, | |
title: dateTitle | |
} | |
}) | |
} | |
}), angular.module("ga.pages.game.settings.exportData.modal", ["ga.utils.helpers.focusElement", "ga.utils.tracking"]).controller("gaPagesGameSettingsExportDataModalController", function($scope, gaUtilsTracking) { | |
$scope.dataExport = { | |
links: $scope.links, | |
amountOfLinks: $scope.links.length, | |
parsedLinks: null, | |
linkType: "RAW" | |
}; | |
var parseLinks = function(type, links) { | |
$scope.dataExport.parsedLinks = "LINUX" === type ? 'wget -O "' + links.map(function(o) { | |
return getFileName(o.url) + '" "' + o.url | |
}).join('" & wget -O "') + '"' : links.map(function(o) { | |
return o.url | |
}).join("\n") | |
}, | |
getFileName = function(url) { | |
return url = url.substring(0, -1 === url.indexOf("#") ? url.length : url.indexOf("#")), url = url.substring(0, -1 === url.indexOf("?") ? url.length : url.indexOf("?")), url.substring(url.lastIndexOf("/") + 1, url.length) | |
}; | |
$scope.selectLinkType = function(linkType) { | |
$scope.dataExport.linkType = linkType, parseLinks($scope.dataExport.linkType, $scope.dataExport.links), setTimeout(focusLinks) | |
}; | |
var focusLinks = function() { | |
angular.element.find("#data-export-links-text-area")[0].select() | |
}; | |
parseLinks($scope.dataExport.linkType, $scope.dataExport.links), gaUtilsTracking.trackPageRaw("/game/export/data") | |
}), angular.module("ga.pages.game.settings.users", ["ga.services.user", "ga.api.userDb.authenticated.game", "ga.api.userDb.authenticated.invite", "ga.services.dialogs", "ga.ui.notify", "ga.ui.modal"]).controller("gaPagesGameSettingsUsersController", function($scope, $state, gaServicesUser, gaUiModal, gaApiUserDbAuthenticatedGame, gaDialogs, gaUiNotify, gaApiUserDbAuthenticatedInvite) { | |
var gameId = parseInt($state.params.gameId, 10), | |
game = gaServicesUser.game(gameId); | |
$scope.gameUsers = []; | |
var getUsers = function() { | |
gaApiUserDbAuthenticatedGame.getAccesses().then(function(result) { | |
if (result && result[0]) { | |
var users = [], | |
members = [], | |
invited = []; | |
if (result[0].studio && result[0].studio.owner) { | |
var tmpOwner = { | |
email: result[0].studio.owner.email, | |
invite: !1, | |
name: result[0].studio.owner.first_name + " " + result[0].studio.owner.last_name, | |
role: "Studio owner", | |
owner: !0, | |
self: !1, | |
studio: !0 | |
}; | |
gaServicesUser.id === result[0].studio.owner.id && (tmpOwner.self = !0), users.push(tmpOwner) | |
} | |
result[0].studio && result[0].studio.accesses && result[0].studio.accesses.some(function(userAccess) { | |
var tmpUsr = { | |
email: userAccess.email, | |
invite: !1, | |
id: userAccess.id, | |
userId: userAccess.user_id, | |
name: userAccess.first_name + " " + userAccess.last_name, | |
role: getStudioRole(userAccess.role_id), | |
roleId: userAccess.role_id, | |
self: !1, | |
studio: !0 | |
}; | |
users.push(tmpUsr) | |
}), result[0].accesses && (result[0].accesses.some(function(userAccess) { | |
if (userAccess.invite_pending) invited.push({ | |
email: userAccess.invite_email, | |
invite: !0, | |
id: userAccess.id, | |
role: getGameRole(userAccess.role_id), | |
studio: !1 | |
}); | |
else { | |
var tmpUsr = { | |
email: userAccess.email, | |
invite: !1, | |
id: userAccess.id, | |
userId: userAccess.user_id, | |
name: userAccess.first_name + " " + userAccess.last_name, | |
role: getGameRole(userAccess.role_id), | |
roleId: userAccess.role_id, | |
self: !1, | |
studio: !1 | |
}; | |
gaServicesUser.id === userAccess.user_id ? (tmpUsr.self = !0, users.unshift(tmpUsr)) : members.push(tmpUsr) | |
} | |
}), members = members.sort(function(a, b) { | |
return a.name.localeCompare(b.name) | |
}), users = users.concat(members), invited = invited.sort(function(a, b) { | |
return a.email.localeCompare(b.email) | |
}), users = users.concat(invited)), $scope.gameUsers = users | |
} | |
}) | |
}; | |
$scope.deleteInvite = function(id) { | |
gaUiModal.confirm("Please confirm that you wan't to delete the invitation.", "Delete invitation").then(function() { | |
gaApiUserDbAuthenticatedInvite.delete({ | |
type: "game", | |
id: id | |
}).then(function() { | |
getUsers() | |
}) | |
}) | |
}, $scope.inviteUser = function() { | |
gaDialogs.access({ | |
type: "game", | |
role: null, | |
userid: null, | |
gameId: game.id, | |
title: game.title | |
}).then(function(result) { | |
result && result.access_created === !0 ? gaUiNotify.show("User access created", 4e3, "default") : gaUiNotify.show("Game invite has been sent", 4e3, "default"), getUsers() | |
}) | |
}, $scope.editUser = function(userAccess) { | |
gaDialogs.access({ | |
type: "game", | |
role: userAccess.roleId, | |
userAccessId: userAccess.id, | |
gameId: game.id, | |
gameTitle: game.title, | |
title: userAccess.name | |
}).then(function(result) { | |
result && result.deletion === !0 ? gaUiNotify.show("The user was removed from the game", 4e3, "default") : gaUiNotify.show("User saved", 4e3, "default"), getUsers() | |
}) | |
}, $scope.goToUserSettings = function() { | |
$state.go("user.settings.profile") | |
}; | |
var getGameRole = function(roleid) { | |
return 1 === roleid ? "Game admin" : "Game viewer" | |
}, | |
getStudioRole = function(roleid) { | |
return 1 === roleid ? "Studio admin" : "Studio viewer" | |
}; | |
getUsers() | |
}), angular.module("ga.pages.game.settings.emailReports", ["ui.router", "ga.api.userDb.authenticated.report", "ga.api.userDb.authenticated.game", "ga.ui.modal", "ga.services.user", "ga.pages.game.settings.emailReports.addSubscriber", "ga.services.dialogs", "ga.ui.notify"]).controller("gaPagesGameSettingsEmailReportsController", function($scope, $q, $compile, $timeout, $http, $state, gaApiUserDbAuthenticatedReport, gaApiUserDbAuthenticatedGame, gaUiModal, gaServicesUser, gaDialogs, gaUiNotify) { | |
$scope.gameId = $state.params.gameId; | |
var ignoreSaveState = !1; | |
$scope.newSubscriber = { | |
email: "", | |
disabled: !1, | |
error: "", | |
selected: { | |
daily: !1, | |
weekly: !0, | |
monthly: !1 | |
} | |
}, $scope.reportId = 0, $scope.subscribers = [], $scope.orgSubscribers = []; | |
var getReport = function() { | |
var deferred = $q.defer(); | |
return gaApiUserDbAuthenticatedReport.getGameReports().then(function(data) { | |
data.length ? ($scope.reportId = data[0].id, deferred.resolve($scope.reportId)) : (deferred.reject("No report found for this game"), console.log("No reports found for game")) | |
}), deferred.promise | |
}, | |
getSubscribers = function() { | |
var deferred = $q.defer(), | |
tmpSubscribers = { | |
subscribers: {}, | |
users: {} | |
}; | |
return getGameUsers().then(function(data) { | |
tmpSubscribers.users = data, gaApiUserDbAuthenticatedReport.getReportSubscribers($scope.reportId).then(function(data) { | |
angular.forEach(data, function(subscriber) { | |
tmpSubscribers.users[subscriber.email] ? tmpSubscribers.users[subscriber.email] = angular.extend(tmpSubscribers.users[subscriber.email] || {}, subscriber) : tmpSubscribers.subscribers[subscriber.email] = subscriber | |
}); | |
var subscribers = [], | |
users = []; | |
angular.forEach(tmpSubscribers.subscribers, function(subscriber) { | |
subscribers.push(subscriber) | |
}), subscribers = subscribers.sort(function(a, b) { | |
return a.email.localeCompare(b.email) | |
}), angular.forEach(tmpSubscribers.users, function(user) { | |
users.push(user) | |
}), users = users.sort(function(a, b) { | |
return a.email.localeCompare(b.email) | |
}).sort(function(a, b) { | |
return a.sortId > b.sortId | |
}), deferred.resolve({ | |
subscribers: subscribers, | |
users: users | |
}) | |
}) | |
}), deferred.promise | |
}, | |
getGameUsers = function() { | |
var deferred = $q.defer(), | |
gameUsers = {}; | |
return gaApiUserDbAuthenticatedGame.getGameUsers().then(function(data) { | |
angular.forEach(data, function(user) { | |
gameUsers[user.email] = { | |
id: 0, | |
user_id: user.id, | |
report_id: $scope.reportId, | |
email: user.email, | |
gameUser: !0, | |
daily: !1, | |
weekly: !1, | |
monthly: !1, | |
sortId: user.studio_owner ? 0 : _getSortId(user.studio_user, user.role_id), | |
role: user.studio_owner ? "Studio owner" : getRoleTitle(user.studio_user, user.role_id), | |
self: gaServicesUser.details.email === user.email ? -1 : 0 | |
} | |
}), deferred.resolve(gameUsers) | |
}), deferred.promise | |
}, | |
_getSortId = function(studio, role_id) { | |
return role_id + (studio ? 0 : 2) | |
}, | |
addSubscriberClick = function() { | |
gaUiModal.page({ | |
controller: "gaPagesGameSettingsEmailReportsAddSubscriberController", | |
templateUrl: "/static/ga-app/modules/pages/game/settings/email-reports/dialogs/add-subscriber.html", | |
width: 700, | |
parameters: { | |
reportId: $scope.reportId | |
} | |
}).then(function() { | |
getSubscribers().then(function(users) { | |
$scope.orgSubscribers = angular.copy(users), $scope.subscribers = users | |
}), gaUiNotify.show("Subscriber added", 4e3) | |
}) | |
}, | |
save = function(redirectObj) { | |
var promises = [], | |
updateList = !1; | |
angular.forEach($scope.subscribers.users, function(subscriber, index) { | |
angular.equals(subscriber, $scope.orgSubscribers.users[index]) || (subscriber.id || (updateList = !0), promises.push(putSubscriber(subscriber))) | |
}), angular.forEach($scope.subscribers.subscribers, function(subscriber, index) { | |
angular.equals(subscriber, $scope.orgSubscribers.subscribers[index]) || (subscriber.id || (updateList = !0), promises.push(putSubscriber(subscriber))) | |
}), promises.length ? (checkStatus(), $q.all(promises).then(function() { | |
redirectObj ? $state.go(redirectObj.state, redirectObj.params) : (updateList ? getReport().then(function() { | |
getSubscribers().then(function(users) { | |
$scope.orgSubscribers = angular.copy(users), $scope.subscribers = users, checkStatus() | |
}) | |
}) : ($scope.orgSubscribers = angular.copy($scope.subscribers), checkStatus()), gaUiNotify.show("Changes saved", 4e3)) | |
}).catch(function() { | |
getReport().then(function() { | |
getSubscribers().then(function(users) { | |
$scope.orgSubscribers = angular.copy(users), $scope.subscribers = users, checkStatus() | |
}) | |
}), gaUiNotify.show("Something went wrong while saving", 4e3, "warning") | |
})) : checkStatus() | |
}, | |
putSubscriber = function(subscriber) { | |
return subscriber.id ? gaApiUserDbAuthenticatedReport.updateReportSubscriber(subscriber.id, subscriber) : gaApiUserDbAuthenticatedReport.createReportSubscriber($scope.reportId, subscriber) | |
}, | |
deleteSubscriber = function(subscriber) { | |
var index = $scope.subscribers.subscribers.indexOf(subscriber); | |
gaUiModal.show({ | |
scope: $scope, | |
width: 500, | |
header: "Remove subscriber", | |
content: "Are you sure you want to remove <strong>" + subscriber.email + "</strong> from the list of subscribers?", | |
buttons: [{ | |
title: "Remove", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "doRemove" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
doRemove: function() { | |
gaApiUserDbAuthenticatedReport.deleteReportSubscriber(subscriber.id).then(function() { | |
$scope.subscribers.subscribers.splice(index, 1), gaUiNotify.show("Subscriber removed", 4e3) | |
}) | |
} | |
} | |
}) | |
}, | |
checkStatus = function() { | |
$scope.changed = !angular.equals($scope.orgSubscribers, $scope.subscribers) | |
}, | |
discard = function() { | |
$scope.subscribers = angular.copy($scope.orgSubscribers), $scope.changed = !1 | |
}, | |
showPreview = function() { | |
gaDialogs.emailReportsPreview() | |
}, | |
getRoleTitle = function(studio, roleid) { | |
return (studio ? "Studio " : "Game ") + (1 === roleid ? "admin" : "viewer") | |
}; | |
getReport().then(function() { | |
getSubscribers().then(function(users) { | |
$scope.orgSubscribers = angular.copy(users), $scope.subscribers = users | |
}) | |
}), $scope.$on("$stateChangeStart", function(event, toState, toParams) { | |
$scope.changed && !ignoreSaveState && (event.preventDefault(), gaUiNotify.loading(!1), gaUiModal.show({ | |
scope: $scope, | |
width: 500, | |
header: "Unsaved changes", | |
content: "Do you want to save the changes you made or discard the changes and leave the page?", | |
buttons: [{ | |
title: "Save", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "save" | |
}, { | |
title: "Discard changes", | |
"class": "ga-btn-text right", | |
keyCode: 27, | |
action: "go" | |
}], | |
actions: { | |
go: function() { | |
ignoreSaveState = !0, $state.go(toState, toParams) | |
}, | |
save: function() { | |
ignoreSaveState = !0, $scope.save({ | |
state: toState, | |
params: toParams | |
}) | |
} | |
} | |
})) | |
}), $scope.save = save, $scope.deleteSubscriber = deleteSubscriber, $scope.addSubscriberClick = addSubscriberClick, $scope.showPreview = showPreview, $scope.checkStatus = checkStatus, $scope.discard = discard | |
}), angular.module("ga.pages.game.settings.emailReports.addSubscriber", ["ga.api.userDb.authenticated.report", "ga.ui.notify"]).controller("gaPagesGameSettingsEmailReportsAddSubscriberController", function($scope, gaApiUserDbAuthenticatedReport, gaUiNotify) { | |
$scope.email = "", $scope.emailReports = { | |
daily: !1, | |
weekly: !0, | |
monthly: !1 | |
}, $scope.errors = { | |
email: "" | |
}, $scope.disabled = !0; | |
var addSubscriber = function() { | |
if ($scope.email && ($scope.emailReports.daily || $scope.emailReports.weekly || $scope.emailReports.monthly)) { | |
var subscriber = { | |
id: 0, | |
user_id: 0, | |
report_id: $scope.reportId, | |
email: $scope.email, | |
daily: $scope.emailReports.daily, | |
weekly: $scope.emailReports.weekly, | |
monthly: $scope.emailReports.monthly | |
}; | |
gaApiUserDbAuthenticatedReport.createReportSubscriber($scope.reportId, subscriber).then(function(data) { | |
$scope._resolve(data) | |
}).catch(function(result) { | |
result[0].type && ("serverError" === result[0].type ? gaUiNotify.show(result[0].msg, 6e3, "warning") : $scope.errors.email = result[0].msg) | |
}) | |
} | |
}, | |
validate = function() { | |
$scope.disabled = !$scope.email || !$scope.emailReports.daily && !$scope.emailReports.weekly && !$scope.emailReports.monthly | |
}; | |
$scope.addSubscriber = addSubscriber, $scope.validate = validate | |
}), angular.module("ga.pages.game.settings.services", ["ga.services.dialogs", "ga.services.user", "ga.api.userDb.authenticated.game", "ga.api.userDb.authenticated.store_app", "ga.api.userDb.authenticated.appfigures", "ga.api.userDb", "ga.ui.notify", "ga.ui.modal", "ga.services.game"]).controller("gaPagesGameSettingsServicesController", function($scope, $state, $timeout, gaDialogs, gaServicesUser, gaApiUserDbAuthenticatedGame, gaApiUserDbAuthenticatedStoreApp, gaApiUserDbAuthenticatedAppfigures, gaUiNotify, gaUiModal, gaServicesGame, gaApiUserDb) { | |
var gameId = parseInt($state.params.gameId, 10), | |
game = gaServicesUser.game(gameId); | |
$scope.iconPath = "/static/ga-app/images/stores/", $scope.app = {}, $scope.state = "linking", $scope.copying = !1; | |
var loadStores = function() { | |
return gaApiUserDbAuthenticatedGame.getStoreApps().then(function(result) { | |
result && result.length ? (parseStore(result[0]), $scope.state = "loaded") : $scope.state = "no_app" | |
}).catch(function() { | |
gaUiNotify.show("Error loading connected app store", 4e3, "warning"), $scope.state = "no_app" | |
}) | |
}; | |
$scope.addStore = function() { | |
gaDialogs.linkGame({ | |
game: game | |
}).then(function(app) { | |
return $scope.state = "linking", gaApiUserDbAuthenticatedAppfigures.getAppMeta(app.id) | |
}).then(function(meta) { | |
return meta && meta.meta && delete meta.meta, gaApiUserDbAuthenticatedGame.createStoreApps({ | |
app_title: meta.name || "", | |
store_name: "apple" === meta.store ? meta.devices.indexOf("Desktop") > -1 ? "apple_mac" : "apple_ios" : meta.store, | |
appfigures_id: meta.id, | |
developer: meta.developer || "", | |
store_url: meta.view_url || "", | |
handheld: meta.devices.indexOf("Handheld") > -1, | |
tablet: meta.devices.indexOf("Tablet") > -1, | |
desktop: meta.devices.indexOf("Desktop") > -1, | |
image_url: meta.icon || "", | |
game_type: "0.00" === meta.price.price ? "free" : "paid", | |
categories: meta.categories.map(function(cat) { | |
return { | |
name: cat.name || "", | |
appfigures_id: cat.id, | |
appfigures_parent_id: cat.parent_id, | |
device: cat.device || "" | |
} | |
}), | |
raw_data: meta | |
}) | |
}).then(function(result) { | |
1 === result.length && (parseStore(result[0]), $scope.state = "loaded"), gaServicesGame.saveGameLinkNotification(gameId, !0) | |
}).catch(function() { | |
game && !game.link_game_notification && (gaServicesGame.saveGameLinkNotification(gameId, !0), $timeout(gaServicesUser.getUserData.bind(gaServicesUser), 50)) | |
}) | |
}, $scope.updateApp = function(app) { | |
gaApiUserDbAuthenticatedAppfigures.getAppMeta(app.appfigures_id).then(function(meta) { | |
return gaApiUserDbAuthenticatedStoreApp.update(app.id, { | |
app_title: meta.name || "", | |
developer: meta.developer || "", | |
store_url: meta.view_url || "", | |
handheld: meta.devices.indexOf("Handheld") > -1, | |
tablet: meta.devices.indexOf("Tablet") > -1, | |
desktop: meta.devices.indexOf("Desktop") > -1, | |
image_url: meta.icon || "", | |
game_type: "0.00" === meta.price.price ? "free" : "paid", | |
categories: meta.categories.map(function(cat) { | |
return { | |
name: cat.name, | |
appfigures_id: cat.id, | |
appfigures_parent_id: cat.parent_id, | |
device: cat.device | |
} | |
}), | |
raw_data: meta | |
}) | |
}).then(function() { | |
loadStores() | |
}).catch(function() { | |
gaUiNotify.show("Error updating!", 4e3, "warning") | |
}) | |
}, $scope.unlinkApp = function() { | |
$scope.app && $scope.app.id && gaUiModal.confirm("Are you sure you want to disconnect the game from the app store?", "Disconnect").then(function() { | |
gaApiUserDbAuthenticatedStoreApp.delete($scope.app.id).then(function(res) { | |
res[0] && ($scope.app = {}, gaUiNotify.show("App store disconnected", 4e3, "default"), $scope.state = "no_app") | |
}).catch(function() { | |
gaUiNotify.show("Something went wrong while disconnecting", 4e3, "warning") | |
}) | |
}) | |
}, $scope.copyGameIcon = function() { | |
$scope.copying = !0, gaApiUserDb.copyFile($scope.app.image_url).then(function(result) { | |
var imgPath = result[0].image_path; | |
return gaApiUserDbAuthenticatedGame.saveGame(gameId, { | |
title: game.title, | |
imageFile: imgPath | |
}) | |
}).then(function() { | |
gaUiNotify.show("Game icon replaced", 4e3, "default"), $scope.copying = !1, $timeout(gaServicesUser.getUserData.bind(gaServicesUser), 50) | |
}).catch(function() { | |
gaUiNotify.show("Something went wrong while replacing the game icon", 4e3, "warning"), $scope.copying = !1 | |
}) | |
}; | |
var parseStore = function(storeData) { | |
$scope.app = storeData, $scope.app.storeIcon = getStoreIcon($scope.app.store_name), $scope.app.storeName = getStoreName($scope.app.store_name), $scope.app.catList = $scope.app.categories.map(function(app) { | |
return app.name | |
}).join(", "), $scope.app.handheldCat = $scope.app.categories.filter(function(a) { | |
return "handheld" === a.device | |
}).map(function(a) { | |
return a.name | |
}).join(", "), $scope.app.tabletCat = $scope.app.categories.filter(function(a) { | |
return "tablet" === a.device | |
}).map(function(a) { | |
return a.name | |
}).join(", "), $scope.app.desktopCat = $scope.app.categories.filter(function(a) { | |
return "desktop" === a.device | |
}).map(function(a) { | |
return a.name | |
}).join(", ") | |
}, | |
getStoreIcon = function(name) { | |
var icon = ""; | |
return "google_play" === name ? icon = "google-play.png" : "apple_mac" === name ? icon = "mac.png" : "apple_ios" === name ? icon = "ios.png" : "amazon_appstore" === name && (icon = "amazon.png"), icon | |
}, | |
getStoreName = function(name) { | |
var storeName = ""; | |
return "google_play" === name ? storeName = "Google Play" : "apple_mac" === name ? storeName = "Mac App Store" : "apple_ios" === name ? storeName = "iOS App Store" : "amazon_appstore" === name && (storeName = "Amazon Appstore"), storeName | |
}; | |
loadStores().then(function() { | |
$state.params.pop && "no_app" === $scope.state && $scope.addStore() | |
}) | |
}), angular.module("ga.pages.explore2", ["ga.api.meta", "ga.ui.menu", "ga.utils.query"]).controller("gaPagesExplore2Controller", function($scope, gaApiMeta, gaUtilsQuery) { | |
$scope.explore = {}; | |
var i, sides = ["left", "right"]; | |
for (i in sides) { | |
var side = sides[i]; | |
$scope.explore[side] = { | |
disabled: !1, | |
metric: { | |
category: "core", | |
event: "DAU" | |
}, | |
meta: gaApiMeta.getMetric({ | |
category: "core", | |
event: "DAU" | |
}), | |
title: gaApiMeta.getMetricDisplay({ | |
category: "core", | |
event: "DAU" | |
}), | |
types: { | |
selected: "line", | |
options: [{ | |
title: "ga-icon-linechart", | |
value: "line", | |
disabled: !1 | |
}, { | |
title: "ga-icon-barchart", | |
value: "bar", | |
disabled: !1 | |
}, { | |
title: "ga-icon-area", | |
value: "area", | |
disabled: !1 | |
}] | |
}, | |
aggregations: { | |
selected: "mean", | |
options: [{ | |
title: "Mean", | |
value: "mean", | |
disabled: !1 | |
}, { | |
title: "Sum", | |
value: "sum", | |
disabled: !1 | |
}, { | |
title: "Count", | |
value: "event_count", | |
disabled: !1 | |
}, { | |
title: "Histogram", | |
value: "histogram", | |
disabled: !1 | |
}] | |
} | |
} | |
} | |
$scope.explore.range = { | |
main: "last30Days", | |
compare: !0 | |
}, $scope.explore.currency = { | |
selected: "USD", | |
options: [{ | |
title: "USD", | |
value: "USD", | |
disabled: !1 | |
}, { | |
title: "EUR", | |
value: "EUR", | |
disabled: !1 | |
}] | |
}, $scope.explore.filter = null, $scope.explore.grouping = { | |
selected: "time", | |
options: [{ | |
title: "Time", | |
value: "time", | |
disabled: !1 | |
}, { | |
title: "Dimension", | |
value: "dimension", | |
disabled: !1 | |
}, { | |
title: "Value", | |
value: "value", | |
disabled: !0 | |
}] | |
}; | |
var toggleCompare = function($event) { | |
$scope.explore.range.compare = !$scope.explore.range.compare, $event.stopPropagation(), $event.preventDefault() | |
}; | |
$scope.toggleCompare = toggleCompare | |
}), angular.module("ga.pages.dashboards", ["ga.utils.urlState", "ga.ui.pardot", "ga.ui.widgetChart", "ga.ui.widgetPiechart", "ga.ui.widgetTable", "ga.ui.widgetMap", "ga.ui.widgetQuality", "ga.ui.popdown", "ga.ui.gridster", "ga.ui.dimensionpicker", "ga.ui.metricpicker", "ga.ui.modal", "ga.ui.tour", "ga.ui.sortable", "ga.ui.explore.overlay", "ga.filters.slice", "ga.ui.datepicker", "ga.ui.realtimeSdkStatus", "ga.utils.helpers.clickElement", "ga.utils.tracking", "ga.utils.cache", "ui.router", "ga.api.userDb.authenticated.dashboard", "ga.api.userDb.authenticated.status", "ga.api.meta", "ga.api.data", "ga.api.userDb", "ga.pages.dashboard.dialog.widgetEdit", "ga.pages.dashboard.dialog.widgetAdd", "ga.services.tracking", "ga.services.user", "ga.services.game", "ga.ui.notify", "ga.ui.menu", "ga.api.userDb.authenticated.game"]).controller("gaPagesDashboardsController", function($window, $document, $filter, $timeout, $rootScope, $scope, $q, $state, $cookieStore, gaServicesTracking, gaUtilsTracking, gaApiMeta, gaApiData, gaUiModal, gaUtilsUrlState, gaUiTour, gaUiTourNew, gaUtilsDate, gaApiUserDbAuthenticatedDashboards, orderByFilter, gaUiExploreOverlay, gaApiUserDb, gaServicesUser, gaApiUserDbAuthenticatedStatus, gaUiNotify, gaUtilsCache, gaApiUserDbAuthenticatedGame, gaServicesGame) { | |
var formatUnitType = $filter("formatUnitType"); | |
$scope.widgetStatus = [], $scope.state = gaUtilsUrlState.getState(), $scope.gameId = parseInt($state.params.gameId, 10) || 0, $scope.user = { | |
activated: gaServicesUser.activated, | |
id: gaServicesUser.id | |
}, $scope.game = { | |
demo: (gaServicesUser.game($scope.gameId) || {}).demo | |
}, $scope.action = "show", $scope.dashboards = [], $scope.dashboard = null, $scope.widget = null, $scope.showNoDataNotice = !1, $scope.processingNoticeData = {}, $scope.showProcessingNotice = !1; | |
var setRealtimeDateTimer, setRealtimeDate = function() { | |
if ($timeout.cancel(setRealtimeDateTimer), $scope.dashboard && "realtime" === $scope.dashboard.id) { | |
var baseDatetime = gaUtilsDate.moment().utc().startOf("hour"); | |
$scope.realtimeInterval = { | |
start: formatUnitType(baseDatetime.clone().add("days", -1).valueOf(), "datetime"), | |
end: formatUnitType(baseDatetime.valueOf(), "datetime"), | |
cStart: formatUnitType(baseDatetime.clone().add("days", -8).valueOf(), "datetime"), | |
cEnd: formatUnitType(baseDatetime.clone().add("days", -7).valueOf(), "datetime") | |
}, setRealtimeDateTimer = $timeout(setRealtimeDate, 1e3) | |
} | |
}, | |
stateCheck = function() { | |
if ("game.dashboards" === $state.current.name) { | |
var tmpGame = gaServicesUser.game(parseInt($state.params.gameId, 10)); | |
return tmpGame && tmpGame.demo && (gaUtilsTracking.trackPageRaw("/game/dashboards/demo"), gaUtilsTracking.trackEvent({ | |
category: "home", | |
action: "game", | |
label: "demo" | |
})), $timeout($state.go.bind($state, "game.dashboards.dashboard", { | |
action: "show", | |
dashboardId: "engagement", | |
gameId: $state.params.gameId | |
}, { | |
location: "replace" | |
})), !1 | |
} | |
var ignoreIntroPages = [], | |
dashboardId = ($state.params.dashboardId || "").match(/^\d+$/) ? parseInt($state.params.dashboardId, 10) : $state.params.dashboardId, | |
action = $state.params.action || "show"; | |
if ($scope.gameId = $state.params.gameId, $scope.dashboards = gaApiUserDbAuthenticatedDashboards.dashboards[$scope.gameId], "show" === action && !dashboardId && !$scope.dashboards.some(function(dashboard) { | |
return dashboard.id === dashboardId | |
})) return void $state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: $scope.dashboards[0].id | |
}, { | |
location: "replace" | |
}); | |
if (dashboardId && dashboardId !== ($scope.dashboard || {}).id) return gaUiNotify.loading(!0), void gaApiUserDbAuthenticatedDashboards.getDashboard(dashboardId).then(function(dashboard) { | |
gaUiNotify.loading(!1); | |
var doStateCheck = !0; | |
if (!dashboard) return $state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: 0 | |
}, { | |
location: "replace" | |
}), void($scope.gameId = null); | |
"realtime" === dashboard.id && $scope.widgetGlobalOptions.filter && $scope.widgetGlobalOptions.filter.values.length && ($scope.widgetGlobalOptions.filter.values = []), dashboard.widgets.sort(function(a, b) { | |
return a.grid.row === b.grid.row ? a.grid.col - b.grid.col : a.grid.row - b.grid.row | |
}), $scope.widgetStatus = []; | |
var lastWidgetGrid = { | |
row: 0, | |
sizey: 0 | |
}; | |
return angular.forEach(dashboard.widgets, function(widget) { | |
widget.grid.row >= lastWidgetGrid.row && (lastWidgetGrid = widget.grid); | |
var widgetStatusObject = { | |
id: widget.id, | |
state: "init", | |
status: "" | |
}; | |
widget.statusObject = widgetStatusObject, $scope.widgetStatus.push(widget.statusObject) | |
}), $scope.containerRow = lastWidgetGrid.row + lastWidgetGrid.sizey, "show" !== action || !angular.isString(dashboard.id) || dashboard.id.toString().match(/([0-9]+-demo)/) || gaServicesUser.onboarding.dashboard[dashboard.id] ? ("show" === action ? (doStateCheck = !1, $scope.dashboard = null, $timeout(function() { | |
$scope.dashboard = dashboard; | |
var did = angular.isNumber($scope.dashboard.id) || $scope.dashboard.id.match(/^\d+$/) ? "custom" : $scope.dashboard.id; | |
gaServicesTracking.submitEvent("design", "pages:game:dashboard:view:" + did, { | |
value: 1 | |
}), setRealtimeDate(), stateCheck(), "realtime" === $scope.dashboard.id && $rootScope.$broadcast("closeExploreAnnouncement") | |
})) : ($scope.dashboard = dashboard, setRealtimeDate()), angular.element("body,html").scrollTop(0), "intro" === action ? void(ignoreIntroPages.indexOf($scope.dashboard.id) >= 0 ? $scope.action = "show" : angular.isString($scope.dashboard.id) ? ($scope.action = action, $scope.introUrl = "/static/ga-app/modules/pages/game/dashboards/dialogs/dashboard-intro-page-" + $scope.dashboard.id + ".html", gaServicesTracking.submitEvent("design", "pages:game:dashboard:intro:" + $scope.dashboard.id, { | |
value: 1, | |
amount: 1 | |
})) : ($state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: 0 | |
}, { | |
location: "replace" | |
}), $scope.gameId = null)) : void(doStateCheck && stateCheck())) : ($scope.dashboard = dashboard, $state.go("game.dashboards.dashboard", { | |
action: "intro", | |
gameId: $scope.gameId, | |
dashboardId: $scope.dashboard.id | |
}, { | |
location: "replace" | |
}), void setRealtimeDate()) | |
}); | |
if ("intro" === action) { | |
if (ignoreIntroPages.indexOf($scope.dashboard.id) >= 0) return; | |
$scope.introUrl = "/static/ga-app/modules/pages/game/dashboards/dialogs/dashboard-intro-page-" + $scope.dashboard.id + ".html" | |
} | |
return "show" !== action || !angular.isString($scope.dashboard.id) || $scope.dashboard.id.toString().match(/([0-9]+-demo)/) || gaServicesUser.onboarding.dashboard[$scope.dashboard.id] ? (action !== $scope.action && "edit" === action ? dashboardId ? ($scope.action = action, $scope.dashboardState = angular.copy($scope.dashboard), $scope.execEditWidget ? editWidget() : $scope.execAddWidgets && addWidgets(), $scope.execEditWidget = !1, $scope.execAddWidgets = !1) : ($scope.previousDashboardId = $scope.dashboard && $scope.dashboard.id, $scope.dashboard = null, createDashboard(), $scope.action = action) : ($scope.action = action, gaUiTour.isRunning() || (!gaServicesUser.onboarding.dashboard.tour && "intro" !== action && $scope.dashboard && "realtime" !== $scope.dashboard.id ? (runTour(), gaServicesUser.onboarding.set("dashboard", "tour", !0), gaServicesUser.onboarding.save("dashboard", "tour", !0)) : !gaServicesUser.onboarding.dashboard.realtimeTour && "intro" !== action && $scope.dashboard && "realtime" === $scope.dashboard.id ? (runRealtimeTour(), gaServicesUser.onboarding.set("dashboard", "realtimeTour", !0), gaServicesUser.onboarding.save("dashboard", "realtimeTour", !0)) : stopTour())), "show" !== $scope.action && stopTour(!0), "show" === $scope.action ? (checkForDataProcessing(), checkForGameLink()) : $scope.showProcessingNotice = !1, void("show" === $scope.action && "acquisition" === $scope.dashboard.id ? checkForZeroState() : $scope.showNoDataNotice = !1)) : void $state.go("game.dashboards.dashboard", { | |
action: "intro", | |
gameId: $scope.gameId, | |
dashboardId: $scope.dashboard.id | |
}, { | |
location: "replace" | |
}) | |
}; | |
$scope.$on("$stateChangeSuccess", stateCheck); | |
var createDashboard = function() { | |
var dashboard = { | |
id: 0, | |
name: "Custom dashboard", | |
widgets: [], | |
init: !1 | |
}; | |
dashboardSettingsDialog(dashboard).then(function(dashboard) { | |
$scope.dashboard = dashboard | |
}, function() { | |
$state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: $scope.previousDashboardId || 0 | |
}, { | |
location: "replace" | |
}), $scope.previousDashboardId = 0 | |
}) | |
}, | |
dashboardSettings = function() { | |
dashboardSettingsDialog($scope.dashboard).then(function(dashboard) { | |
dashboard && ($scope.dashboard.name = dashboard.name) | |
}) | |
}, | |
dashboardSettingsDialog = function(dashboard) { | |
var deferred = $q.defer(), | |
$newScope = $rootScope.$new(); | |
$newScope.dashboard = angular.copy(dashboard); | |
var dashboardSettingsTemplate = '<div class=ga-form dashboard-settings"><label for="name">Dashboard name</label><input class="ga-input widget-name-input" name="name" ng-model="dashboard.name" /></div>', | |
buttons = [{ | |
title: "Confirm", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "confirm", | |
disabled: "!dashboard.name" | |
}]; | |
return dashboard.id && !dashboard.unsaved && buttons.push({ | |
title: "Delete dashboard", | |
"class": "ga-btn-text light red ga-icon-trash vertical-none left", | |
action: "delete" | |
}), buttons.push({ | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
action: "cancel", | |
keyCode: 27 | |
}), gaUiModal.show({ | |
scope: $newScope, | |
header: dashboard.id ? "Dashboard Settings" : "Create Dashboard", | |
content: dashboardSettingsTemplate, | |
width: 500, | |
actions: { | |
"delete": function() { | |
confirmDashboardDeletion($newScope.dashboard).then(function() { | |
deferred.resolve(null) | |
}, function() { | |
deferred.reject() | |
}) | |
}, | |
cancel: function() { | |
deferred.reject($newScope.dashboard) | |
}, | |
confirm: function() { | |
deferred.resolve($newScope.dashboard) | |
} | |
}, | |
always: function() { | |
$newScope.$destroy() | |
}, | |
buttons: buttons | |
}), deferred.promise | |
}, | |
confirmDashboardDeletion = function(dashboard) { | |
var deferred = $q.defer(), | |
doDelete = function(dashboard) { | |
gaApiUserDbAuthenticatedDashboards.deleteDashboard(dashboard.id, $scope.gameId).then(function() { | |
$state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: 0 | |
}, { | |
location: "replace" | |
}), $scope.dashboard = null, $scope.gameId = null, gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "custom", | |
label: "delete" | |
}), gaServicesTracking.submitEvent("design", "pages:game:dashboard:delete:custom", { | |
value: 1 | |
}), deferred.resolve() | |
}) | |
}; | |
return dashboard.id && gaUiModal.show({ | |
scope: $scope, | |
width: 500, | |
header: "Delete dashboard", | |
content: 'Are you sure you want to delete the dashboard <strong ng-bind="dashboard.name"></strong> and <strong>all</strong> widgets contained within?', | |
buttons: [{ | |
title: "Delete", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "doDelete" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
doDelete: function() { | |
doDelete($scope.dashboard) | |
} | |
} | |
}, "confirmDashboardDelete"), deferred.promise | |
}, | |
cancelDashboardChanges = function() { | |
var doCancel = function() { | |
$scope.dashboard.id ? gaApiUserDbAuthenticatedDashboards.lock($scope.dashboard.id, !0).then(function() { | |
$state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: $scope.dashboard.id | |
}, { | |
location: "replace" | |
}), $scope.dashboard = null | |
}) : ($state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: $scope.previousDashboardId || 0 | |
}, { | |
location: "replace" | |
}), $scope.previousDashboardId = null, $scope.dashboard = null) | |
}; | |
$scope.dashboard.id && "0" !== $scope.dashboard.id && angular.equals($scope.dashboardState, $scope.dashboard) ? doCancel() : gaUiModal.show({ | |
scope: $scope, | |
width: 500, | |
header: $scope.dashboard.id ? "Cancel dashboard changes" : "Cancel dashboard creation", | |
content: $scope.dashboard.id ? 'Are you sure you want to cancel dashboard <strong ng-bind="dashboard.name"></strong> changes?' : 'Are you sure you want to cancel dashboard <strong ng-bind="dashboard.name"></strong> creation?', | |
buttons: [{ | |
title: "Confirm", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "confirm" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
confirm: doCancel | |
} | |
}) | |
}; | |
$scope.isSavingDashboard = !1; | |
var saveDashboardChanges = function() { | |
return $scope.dashboard ? void($scope.isSavingDashboard || ($scope.isSavingDashboard = !0, gaApiUserDbAuthenticatedDashboards.saveDashboard($scope.dashboard, $scope.gameId).then(function(dashboard) { | |
$state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: dashboard.id | |
}, { | |
location: "replace" | |
}), 0 === $scope.dashboard.id ? (gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "custom", | |
label: "create" | |
}), gaServicesTracking.submitEvent("design", "pages:game:dashboard:create:custom", { | |
value: 1 | |
})) : (gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "custom", | |
label: "edit" | |
}), gaServicesTracking.submitEvent("design", "pages:game:dashboard:save:custom", { | |
value: 1 | |
})), $scope.dashboard = null, $scope.gameId = null, $scope.isSavingDashboard = !1 | |
}).catch(function() { | |
$scope.isSavingDashboard = !1 | |
}))) : void $state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: 0 | |
}, { | |
location: "replace" | |
}) | |
}, | |
widgetMenu = function() { | |
gaUiModal.show({ | |
scope: $scope, | |
newScope: !1, | |
header: "Add Widget", | |
content: '<div class="ga-dashboard-add"><ul class="ga-btn-group square huge box-shadow"><li class="ga-btn square huge ga-icon-dashboards" ng-click="addWidgets(); x__modal.actions.x_hide();">Add existing widgets</li><li class="ga-btn square huge ga-icon-add" ng-click="editWidget(); x__modal.actions.x_hide();">Create new widget</li></ul></div>', | |
buttons: [{ | |
title: "Cancel", | |
"class": "ga-btn-alt", | |
keyCode: 27 | |
}] | |
}) | |
}, | |
orderDashboards = function() { | |
var $newScope = $rootScope.$new(); | |
$newScope.dashboards = orderByFilter($scope.dashboards, "sortOrder"); | |
var updateSortOrder = function() { | |
var sortOrderList = []; | |
angular.forEach($newScope.dashboards, function(dashboard, index) { | |
dashboard.sortOrder = index, sortOrderList.push(dashboard.id) | |
}), gaApiUserDbAuthenticatedDashboards.saveDashboardsOrder(sortOrderList, $scope.gameId).then(function() {}), $scope.dashboards = $newScope.dashboards, gaUtilsTracking.trackPageRaw("/game/dashboards/sortdashboard") | |
}; | |
gaUiModal.show({ | |
scope: $newScope, | |
header: "Re-order dashboards", | |
content: '<div class="sort-dashboards-container"><ul ga-ui-sortable sortable-options="{}" ng-model=\'dashboards\' class="ga-default-list border boxes"><li ng-repeat="dashboardItem in dashboards" class="ga-icon-dashboard box draggable" ng-class="{\'sort-dashboards-lower\': $index>4}"> {{dashboardItem.name}}</li></ul></div>', | |
buttons: [{ | |
title: "Confirm", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "confirm" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
confirm: updateSortOrder | |
}, | |
always: function() { | |
$newScope.$destroy() | |
} | |
}) | |
}, | |
createWidget = function() { | |
return { | |
id: 0, | |
name: "", | |
grid: { | |
col: 1, | |
row: 1, | |
sizex: 2, | |
sizey: 1 | |
}, | |
type: "line", | |
query: { | |
metric: null, | |
aggregation: "mean", | |
group: "time", | |
filter: null | |
} | |
} | |
}, | |
editWidget = function(widget, $index) { | |
if ("edit" !== $scope.action) return $scope.execEditWidget = !0, void $state.go("game.dashboards.dashboard", { | |
action: "edit", | |
gameId: $scope.gameId, | |
dashboardId: $scope.dashboard.id | |
}, { | |
location: "replace" | |
}); | |
if (!widget) { | |
var canCreateMore = !0; | |
if (angular.forEach($scope.dashboard.widgets, function(widget) { | |
widget.grid.row >= 24 ? canCreateMore = !1 : 2 === widget.grid.sizey && widget.grid.row >= 23 && (canCreateMore = !1) | |
}), !canCreateMore) return !1 | |
} | |
editWidgetDialog(widget, $scope.dashboard).then(function(widget) { | |
void 0 !== $index ? (widget.update = !0, $scope.dashboard.widgets[$index] = widget) : $scope.dashboard.widgets.push(widget), $scope.$broadcast("reloadGridster") | |
}), widget && gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "widget", | |
label: "edit" | |
}) | |
}, | |
editWidgetDialog = function(widget, dashboard) { | |
var deferred = $q.defer(), | |
$newScope = $rootScope.$new(); | |
$newScope.widget = angular.copy(widget || createWidget()), $newScope.dashboard = angular.copy(dashboard); | |
var buttons = [{ | |
title: widget ? "Save changes" : "Add widget to dashboard", | |
"class": "ga-btn-alt orange right", | |
action: "confirm", | |
disabled: "isInvalid" | |
}]; | |
return buttons.push(dashboard && dashboard.init ? { | |
title: "Skip", | |
"class": "ga-btn-alt right", | |
action: "cancel" | |
} : { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27, | |
action: "cancel" | |
}), gaUiModal.show({ | |
scope: $newScope, | |
newScope: !1, | |
destroyScope: !0, | |
header: widget ? "Edit Widget" : "Create New Widget", | |
width: 850, | |
content: "<div ga-widget-edit></div>", | |
actions: { | |
confirm: function() { | |
deferred.resolve($newScope.widget), widget || gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "widget", | |
label: "create" | |
}) | |
}, | |
cancel: function() { | |
deferred.reject() | |
} | |
}, | |
buttons: buttons, | |
always: function() { | |
$newScope.$destroy() | |
} | |
}), deferred.promise | |
}, | |
addWidgets = function() { | |
return "edit" !== $scope.action ? ($scope.execAddWidgets = !0, void $state.go("game.dashboards.dashboard", { | |
action: "edit", | |
gameId: $scope.gameId, | |
dashboardId: $scope.dashboard.id | |
}, { | |
location: "replace" | |
})) : void addWidgetsDialog($scope.dashboard).then(function(widgets) { | |
$scope.dashboard.widgets = $scope.dashboard.widgets.concat(widgets), $scope.$broadcast("reloadGridster") | |
}) | |
}, | |
addWidgetsDialog = function(dashboard) { | |
var deferred = $q.defer(), | |
$newScope = $rootScope.$new(); | |
$newScope.dashboards = angular.copy($scope.dashboards), $newScope.dashboard = angular.copy(dashboard); | |
var buttons = [{ | |
title: "Add widgets to dashboard", | |
"class": "ga-btn-alt orange right", | |
action: "confirm", | |
disabled: "selected.widgets.length?false:true" | |
}]; | |
return buttons.push(dashboard && dashboard.init ? { | |
title: "Skip", | |
"class": "ga-btn-alt right", | |
action: "cancel" | |
} : { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27, | |
action: "cancel" | |
}), gaUiModal.show({ | |
scope: $newScope, | |
newScope: !1, | |
header: "Add Existing Widgets to Dashboard", | |
width: 750, | |
absolute: !0, | |
content: "<div ga-widget-add></div>", | |
actions: { | |
confirm: function() { | |
$newScope.selected.widgets = $newScope.selected.widgets.reverse().map(function(widget) { | |
return widget.id = 0, widget.grid.row = 1, widget.grid.col = 1, "spark" === widget.type ? (widget.grid.sizex = 1, widget.grid.sizey = 1) : "quality" === widget.type ? (widget.grid.sizex = 4, widget.grid.sizey = 2) : (widget.grid.sizex = 2, widget.grid.sizey = 1), widget | |
}), deferred.resolve($newScope.selected.widgets), gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "widget", | |
label: "copy", | |
value: $newScope.selected.widgets.length | |
}) | |
}, | |
cancel: function() { | |
deferred.reject() | |
} | |
}, | |
buttons: buttons, | |
always: function() { | |
$newScope.$destroy() | |
} | |
}), deferred.promise | |
}, | |
resizeWidget = function(widget, $index, size) { | |
if (-1 === size && 1 === widget.grid.sizex) return !1; | |
if (1 === size && 4 === widget.grid.sizex) return !1; | |
var newSize = [2, 1]; | |
1 === widget.grid.sizex && 1 === size ? newSize = [2, 1] : 2 === widget.grid.sizex && 1 === size ? newSize = [4, 2] : 2 === widget.grid.sizex && -1 === size ? newSize = [1, 1] : 4 === widget.grid.sizex && -1 === size && (newSize = [2, 1]), $scope.$broadcast("resizeWidgetGridster", $index, newSize) | |
}, | |
removeWidget = function(widget, $index) { | |
gaUiModal.show({ | |
scope: $scope, | |
width: 500, | |
header: "Delete widget", | |
content: "Are you sure you want to delete <strong>" + widget.name + "</strong> widget?", | |
buttons: [{ | |
title: "Delete", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "confirm" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
confirm: function() { | |
$scope.$broadcast("removeWidgetGridster", $index, function($index) { | |
widget.id && ($scope.dashboard.deletedWidgets = $scope.dashboard.deletedWidgets || [], $scope.dashboard.deletedWidgets.push(widget.id)), $scope.dashboard.widgets.splice($index, 1), $scope.$broadcast("reloadGridster") | |
}), gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "widget", | |
label: "delete" | |
}) | |
} | |
} | |
}) | |
}, | |
showExplore = function(widget, $event) { | |
var clickElement = angular.element($event.target), | |
overlayElement = $document.find("body"), | |
datepicker = angular.copy($scope.datepickerOptions), | |
globalFilter = $scope.widgetGlobalOptions.filter, | |
globalCurrency = $scope.widgetGlobalOptions.currency, | |
widgetTitle = widget.name ? widget.name : null, | |
widgetGroupBy = widget.query.group ? widget.query.group : null, | |
widgetVisualization = widget.type, | |
tmpMetric = angular.copy(angular.isArray(widget.query.metric) ? widget.query.metric[0] : widget.query.metric); | |
"retention_1" === tmpMetric.event && (tmpMetric.event = "retention"); | |
var widgetMetric = { | |
aggregation: widget.query.aggregation, | |
category: tmpMetric.category, | |
event: tmpMetric.event | |
}, | |
filter = null; | |
filter = globalFilter ? globalFilter : widget.query.hasOwnProperty("filter") && widget.query.filter ? widget.query.filter : null; | |
var currency = null; | |
currency = globalCurrency ? globalCurrency : widget.query.metric.hasOwnProperty("currency") && widget.query.metric.currency ? widget.query.metric.currency : "USD", widgetMetric.currency = currency; | |
var exploreSettingsInit = { | |
datepicker: datepicker, | |
filter: filter, | |
groupBy: widgetGroupBy, | |
currency: widgetMetric.currency, | |
title: widgetTitle, | |
visualization: widgetVisualization, | |
metric: widgetMetric, | |
rollup: $scope.widgetGlobalOptions.rollup || null | |
}, | |
widgetCompareToggleOff = clickElement.closest(".widget-inner").data("compareToogleOff"); | |
"boolean" == typeof widgetCompareToggleOff && (exploreSettingsInit.datepicker.compare = !widgetCompareToggleOff), gaUiExploreOverlay.show(overlayElement, exploreSettingsInit); | |
var id = $scope.dashboard.id, | |
intId = parseInt(id, 10); | |
id = intId !== intId ? id : "custom", gaServicesTracking.addEvent("design", "popup:explore:dashboards-" + id, { | |
value: 1 | |
}), gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "explore", | |
label: widget.name | |
}) | |
}, | |
activeWidgetIndex = function() { | |
var activeIndex = -1; | |
return $scope.widget ? ($scope.dashboard.widgets.some(function(widget, index) { | |
return widget.id === $scope.widget.id ? (activeIndex = index, !0) : !1 | |
}), activeIndex) : activeIndex | |
}, | |
getNextPrevWidget = function(direction) { | |
var index = activeWidgetIndex(); | |
return void 0 !== $scope.dashboard.widgets[index + direction] ? $scope.dashboard.widgets[index + direction] : void 0 | |
}, | |
gotoDashboard = function(dashboardId, action) { | |
action = action || "show", $state.go("game.dashboards.dashboard", { | |
action: action, | |
gameId: $scope.gameId, | |
dashboardId: dashboardId | |
}) | |
}, | |
selectAction = function(action) { | |
$state.go("game.dashboards.dashboard", { | |
action: action | |
}, { | |
location: "replace" | |
}) | |
}, | |
dimensionTitle = function(value) { | |
return gaApiMeta.getDimension(value).title | |
}; | |
$scope.$on("$destroy", function() { | |
$timeout.cancel(setRealtimeDateTimer) | |
}), $scope.dimensionTitle = dimensionTitle, $scope.gotoDashboard = gotoDashboard, $scope.selectAction = selectAction, $scope.dashboardSettings = dashboardSettings, $scope.saveDashboardChanges = saveDashboardChanges, $scope.cancelDashboardChanges = cancelDashboardChanges, $scope.orderDashboards = orderDashboards, $scope.widgetMenu = widgetMenu, $scope.editWidget = editWidget, $scope.addWidgets = addWidgets, $scope.resizeWidget = resizeWidget, $scope.removeWidget = removeWidget, $scope.showExplore = showExplore, $scope.getNextPrevWidget = getNextPrevWidget, $scope.activeWidgetIndex = activeWidgetIndex; | |
var showMeTour = function() { | |
$scope.dashboard && ("realtime" === $scope.dashboard.id ? runRealtimeTour() : runTour()) | |
}; | |
$scope.showMeTour = showMeTour; | |
var runRealtimeTour = function() { | |
gaUiTourNew.stop(), gaUiTourNew.addStep({ | |
title: "Introducing the Real-time Dashboard", | |
text: "The Real-time Dashboard is a vital addition to our Dashboards collection. Use it to monitor activities when running new acquisition or marketing campaigns. Let's take you through the features.", | |
nextText: "Take the tour" | |
}), gaUiTourNew.addStep({ | |
title: "Status keeps you updated", | |
text: "With Status you get an immediate response on your integrated SDK's along with the activity in your game only minutes delayed. Status can also let you know if any events are rejected from our collectors.", | |
element: ".integration-static-widget .title", | |
pos: ["bottom"], | |
zIndex: 900 | |
}), gaUiTourNew.addStep({ | |
title: "Timely updates", | |
text: "All metrics, except for the Status bar, are updated on an hourly basis, to get fast feedback when running new activities.", | |
element: ".ga-ui-gridster > li:first .ga-ui-progress", | |
pos: ["bottom", "left"], | |
zIndex: 900 | |
}), gaUiTourNew.addStep({ | |
title: "No margin for error", | |
text: "We made it easy for you to filter your Error report by different levels of severity. Making troubleshooting quick and easy.", | |
element: ".ga-ui-gridster > li:last .title", | |
pos: ["bottom"], | |
zIndex: 900 | |
}), gaUiTourNew.addStep({ | |
title: "Enhanced personalization", | |
text: "Set your timezone in User settings -> Locale settings, and choose your preferred date, time and number formats.", | |
element: ".ga.main-menu .popdown.ga-icon-user", | |
pos: ["right", "top"], | |
fixed: !0 | |
}), gaUiTourNew.start({ | |
navigation: !0 | |
}) | |
}, | |
runTour = function() { | |
gaUiTourNew.stop(), gaUiTourNew.addStep({ | |
title: "Date picker", | |
text: "You can choose a custom period or select one from our presets. Additionally, you can turn the time comparison period on or off.", | |
element: ".ga.bar.page.sub .left .datepicker", | |
pos: ["bottom", "right"], | |
fixed: !0, | |
zIndex: 900 | |
}), gaUiTourNew.addStep({ | |
title: "Filter your data", | |
text: "You can create a filter on your data by choosing certain parameters like country, build and more.", | |
element: ".ga.bar.page.sub .left .dimensionpicker", | |
pos: ["bottom", "right"], | |
fixed: !0, | |
zIndex: 900 | |
}), gaUiTourNew.addStep({ | |
title: "Get all the details", | |
text: "This is an extended graph and table view of the widget data. You can choose to group that data differently and export it to CSV.", | |
element: ".ga-ui-gridster>li:first-child .title.more", | |
pos: ["bottom"], | |
fixed: !1, | |
zIndex: 900 | |
}), gaUiTourNew.addStep({ | |
title: "Custom dashboards", | |
text: "Create your own dashboards with custom widgets or choose to use existing widgets. Create a custom dashboard.", | |
element: ".ga.bar.page .right .createdashboard", | |
pos: ["bottom", "left"], | |
fixed: !0 | |
}), gaUiTourNew.addStep({ | |
title: "Enhanced personalization", | |
text: "To set your date, time and number formats go to User settings -> Locale settings", | |
element: ".ga.main-menu .popdown.ga-icon-user", | |
pos: ["right", "top"], | |
fixed: !0 | |
}), gaUiTourNew.start({ | |
navigation: !0 | |
}) | |
}, | |
stopTour = function() { | |
$rootScope.$broadcast("killTour") | |
}; | |
$scope.dismissIntro = function() { | |
gaServicesUser.onboarding.set("dashboard", $scope.dashboard.id, !0), gaServicesUser.onboarding.save(), $state.go("game.dashboards.dashboard", { | |
action: "show", | |
gameId: $scope.gameId, | |
dashboardId: $scope.dashboard.id | |
}, { | |
location: "replace" | |
}) | |
}; | |
var checkForZeroState = function() { | |
angular.isString($scope.dashboard.id) && !gaServicesUser.onboarding.dashboard.acquisition_notice && "acquisition" === $scope.dashboard.id && ($scope.showNoDataNotice = !1, gaApiData.getValue("/dimensions", $state.params.gameId).then(function(data) { | |
!angular.isObject(data) || data.install_publisher || data.install_campaign || ($scope.showNoDataNotice = !0) | |
})) | |
}, | |
checkForDataProcessing = function() { | |
var game_id = $state.params.gameId; | |
if ($rootScope.gaProcessed && $rootScope.gaProcessed[game_id]) return void($scope.showProcessingNotice = !1); | |
var todayDate = gaUtilsDate.moment().utc().format("YYYY-MM-DD"); | |
gaApiUserDbAuthenticatedStatus.getProcessing().then(function(result) { | |
try { | |
result && result.results && result.results.length && todayDate !== result.results[0].processing && ($scope.processingNoticeData[game_id] = { | |
show: !0, | |
date: gaUtilsDate.moment(result.results[0].processing).utc().format("MMM. D. YYYY") | |
}, $scope.showProcessingNotice = !0) | |
} catch (e) {} | |
}) | |
}, | |
gamelinkShown = !1, | |
checkForGameLink = function() { | |
var game = gaServicesUser.game(parseInt($state.params.gameId, 10)); | |
game && !game.link_game_notification && game.admin && !gamelinkShown && (gamelinkShown = !0, gaServicesGame.getNumbers(game.id).then(function(numbers) { | |
return numbers && numbers[0] && numbers[0].value > 10 ? !0 : !1 | |
}).then(function(goOn) { | |
return goOn ? gaApiUserDbAuthenticatedGame.getStoreApps() : !1 | |
}).then(function(result) { | |
result && 0 === result.length && gaUiModal.show({ | |
scope: $scope, | |
width: 650, | |
header: "Introducing App Store Connect", | |
content: '<div class="app_store_connect_modal"><h2>Connect your game</h2>You can now connect your game to the Apple, Google or Amazon app stores.<br><strong>Link your game now and you are ready</strong> for new features to come such as benchmarking and segmenting.<div class="ga color grey">*Please note that you can only connect to one app store per game.</div></div>', | |
buttons: [{ | |
title: "Search for my game", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "gotoSettings" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
action: "dismiss" | |
}], | |
actions: { | |
gotoSettings: function() { | |
$state.go("game.settings.services", { | |
pop: !0 | |
}) | |
}, | |
dismiss: function() { | |
gaServicesGame.saveGameLinkNotification(game.id, !0), $timeout(gaServicesUser.getUserData.bind(gaServicesUser), 50) | |
} | |
} | |
}) | |
})) | |
}; | |
$scope.hideNoticeBar = function(name) { | |
$scope.showNoDataNotice = !1, gaServicesUser.onboarding.set("dashboard", name + "_notice", !0), gaServicesUser.onboarding.save("dashboard", name + "_notice", !0) | |
}, $scope.hideProcessedNoticeBar = function() { | |
$scope.showProcessingNotice = !1; | |
var game_id = $state.params.gameId; | |
$scope.processingNoticeData[game_id].show = !1, $rootScope.gaProcessed = $rootScope.gaProcessed || {}, $rootScope.gaProcessed[game_id] = !0 | |
}, $scope.changeWidgetTotalValue = function(widget, totalValue, event) { | |
event.stopPropagation() | |
}, $scope.datepickerOptions = { | |
interval: {}, | |
selection: "last30Days", | |
compare: !0, | |
title: "Date range" | |
}, $scope.state.d ? angular.isObject($scope.state.d) ? ($scope.datepickerOptions.selection = "custom", $scope.datepickerOptions.interval = angular.copy($scope.state.d), $scope.datepickerOptions.compare = !!$scope.datepickerOptions.interval.compare) : ($scope.datepickerOptions.selection = $scope.state.d, $scope.datepickerOptions.compare = 0 === $scope.state.dc ? !1 : !0) : $scope.datepickerOptions.compare = 0 === $scope.state.dc ? !1 : !0; | |
var datepickerCompareStatus = gaUtilsCache.get("dashboards-settings-compare", "localStorage"); | |
"boolean" == typeof datepickerCompareStatus && ($scope.datepickerOptions.compare = datepickerCompareStatus), "custom" !== $scope.datepickerOptions.selection && ($scope.datepickerOptions.interval.main = gaUtilsDate.getPeriodRange($scope.datepickerOptions.selection), $scope.datepickerOptions.interval.compare = $scope.datepickerOptions.compare ? gaUtilsDate.getPreviousPeriod($scope.datepickerOptions.interval.main) : null), $scope.$watch("datepickerOptions.interval", function(newVal, oldVal) { | |
if (newVal !== oldVal) { | |
$scope.datepickerOptions.compare ? delete $scope.state.dc : $scope.state.dc = 0, "last30Days" === $scope.datepickerOptions.selection ? delete $scope.state.d : "custom" === $scope.datepickerOptions.selection ? ($scope.state.d = $scope.datepickerOptions.interval, delete $scope.state.dc) : $scope.state.d = $scope.datepickerOptions.selection, $scope.widgetGlobalOptions.range = angular.copy($scope.datepickerOptions.interval); | |
var compareState = $scope.widgetGlobalOptions.range.compare ? !0 : !1; | |
gaUtilsCache.put("dashboards-settings-compare", compareState, "localStorage") | |
} | |
}), $scope.widgetGlobalOptions = { | |
range: angular.copy($scope.datepickerOptions.interval), | |
filter: $scope.state.f || null, | |
rollup: $scope.state.r || "daily" | |
}, $scope.filterMeta = $scope.widgetGlobalOptions.filter && $scope.widgetGlobalOptions.filter.values.length ? gaApiMeta.getDimension($scope.widgetGlobalOptions.filter.dimension) : null; | |
var removeFilter = function(index) { | |
$scope.widgetGlobalOptions.filter.values.splice(index, 1), $scope.widgetGlobalOptions.filter = $scope.widgetGlobalOptions.filter.values.length ? { | |
dimension: $scope.widgetGlobalOptions.filter.dimension, | |
values: $scope.widgetGlobalOptions.filter.values | |
} : null | |
}; | |
$scope.removeFilter = removeFilter, $scope.$watch("widgetGlobalOptions.filter", function(newVal, oldVal) { | |
null !== $scope.widgetGlobalOptions.filter && newVal !== oldVal && (newVal && newVal.values.length && newVal.dimension ? ($scope.filterMeta = gaApiMeta.getDimension(newVal.dimension), $scope.state.f = newVal) : ($scope.filterMeta = null, $scope.widgetGlobalOptions.filter = null, delete $scope.state.f)) | |
}, !0), $scope.$watch("widgetGlobalOptions.rollup", function(newVal, oldVal) { | |
null !== $scope.widgetGlobalOptions.rollup && newVal !== oldVal && (newVal ? $scope.state.r = newVal : ($scope.widgetGlobalOptions.rollup = null, delete $scope.state.r)) | |
}, !0), $scope.$watch("state", function(newState, oldState) { | |
gaUtilsUrlState.setState($scope.state), newState !== oldState && null === newState.currency && delete newState.currency; | |
var newStateCheck = angular.copy(newState), | |
ignoreDateChange = !1; | |
if (newStateCheck.daterange || (newStateCheck.daterange = "last30Days", oldState.daterange || (ignoreDateChange = !0)), newStateCheck.filter && newStateCheck.filter.dimension && newStateCheck.filter.values.length && (!oldState.filter || newStateCheck.filter.dimension !== oldState.filter.dimension) && gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "filter", | |
label: newStateCheck.filter.dimension | |
}), newStateCheck.daterangeCompare !== oldState.daterangeCompare) { | |
var compareLabel = ""; | |
compareLabel = void 0 === newStateCheck.daterangeCompare || newStateCheck.daterangeCompare ? angular.isString(newStateCheck.daterange) ? newStateCheck.daterange : newStateCheck.daterange.compare ? gaUtilsDate.getIntervalTitle(newStateCheck.daterange.compare) : "soff" : "off", gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "daterangecompare", | |
label: compareLabel | |
}) | |
} | |
if (!ignoreDateChange && newStateCheck.daterange && !angular.equals(newStateCheck.daterange, oldState.daterange)) { | |
var label = ""; | |
angular.isString(newStateCheck.daterange) ? label = newStateCheck.daterange : oldState.daterange && !angular.equals(newStateCheck.daterange.main, oldState.daterange.main) && (label = gaUtilsDate.getIntervalTitle(newStateCheck.daterange.main)), label && gaUtilsTracking.trackEvent({ | |
category: "dashboards", | |
action: "daterange", | |
label: label | |
}) | |
} | |
}, !0), $scope.popdown = "" | |
}), angular.module("ga.pages.dashboard.dialog.widgetEdit", ["ga.api.meta", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.ui.tooltip", "ga.ui.modal", "ga.utils.helpers.focusElement", "ga.utils.date"]).controller("gaWidgetEditController", function($scope, $rootScope, $timeout, $filter, gaUiModal, gaApiMeta, gaUtilsDate) { | |
var formatUnitType = $filter("formatUnitType"); | |
$scope.currencies = { | |
available: gaApiMeta.getCurrencies(), | |
selectActive: !1, | |
query: "", | |
lastSelected: null | |
}, $scope.aggregationTooltip = {}, $scope.widget && $scope.widget.query && $scope.widget.query.metric && $scope.widget.query.metric.currency && ($scope.currencies.lastSelected = $scope.widget.query.metric.currency); | |
var metricpicker = function() { | |
if ($scope.metric.disabled) return !1; | |
var $tmpScope = $rootScope.$new(!0); | |
$tmpScope.tmpMetric = angular.copy($scope.widget.query.metric); | |
var tmpListener = $tmpScope.$watch("tmpMetric", function(newVal, oldVal) { | |
newVal !== oldVal && (newVal && ("business" === newVal.category || "design" === newVal.category) && newVal.event && newVal.event.indexOf(":.*") > -1 && ($scope.widget.query.group = "value"), $scope.widget.query.metric = angular.copy($tmpScope.tmpMetric), $timeout(function() { | |
gaUiModal.hide("subModal") | |
})) | |
}); | |
gaUiModal.show({ | |
header: "Select a metric", | |
scope: $tmpScope, | |
newScope: !1, | |
width: 720, | |
customClass: "secondary", | |
content: '<ga-ui-metricpicker metric="tmpMetric"></ga-ui-metricpicker>', | |
buttons: [{ | |
title: "Cancel", | |
"class": "ga-btn-alt", | |
keyCode: 27 | |
}], | |
always: function() { | |
tmpListener(), $tmpScope.$destroy() | |
} | |
}, "subModal") | |
}, | |
dimensionpicker = function() { | |
if ($scope.dimension.disabled) return !1; | |
var $tmpScope = $rootScope.$new(!0); | |
$tmpScope.tmpFilter = angular.copy($scope.widget.query.filter), $tmpScope.tmpSelected = null, $tmpScope.metric = angular.copy($scope.widget.query.metric), gaUiModal.show({ | |
header: "Select a filter", | |
scope: $tmpScope, | |
newScope: !1, | |
width: 720, | |
customClass: "secondary", | |
content: '<ga-ui-dimensionpicker filter="tmpFilter" metric="metric" selected="tmpSelected"></ga-ui-dimensionpicker>', | |
buttons: [{ | |
title: "Apply", | |
"class": "ga-btn-alt orange right", | |
action: "apply" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
apply: function() { | |
$tmpScope.tmpSelected && $tmpScope.tmpSelected.values && $tmpScope.tmpSelected.values.length ? ($tmpScope.tmpFilter || ($scope.widget.query.group = "dimension"), $scope.widget.query.filter = angular.copy($tmpScope.tmpSelected), dimensionsProcess()) : ($scope.widget.query.filter = null, dimensionsProcess()) | |
} | |
}, | |
always: function() { | |
$tmpScope.$destroy() | |
} | |
}, "subModal") | |
}, | |
dimensionsProcess = function() { | |
$scope.widget.query.filter ? ($scope.filterMeta = gaApiMeta.getDimension($scope.widget.query.filter.dimension), $scope.filterValues = [], "*" === $scope.widget.query.filter.values[0] ? $scope.filterValues.push(($scope.filterMeta.parent ? $scope.filterMeta.parent.title + " > " + $scope.filterMeta.title : $scope.filterMeta.title) + " > All") : angular.forEach($scope.widget.query.filter.values, function(value) { | |
$scope.filterValues.push(formatUnitType(value, $scope.filterMeta.type)) | |
})) : ($scope.filterValues = [], $scope.filterMeta = null) | |
}, | |
validateWidget = function() { | |
return !widgetCheckRequirements() | |
}; | |
$scope.isValid = !0, $scope.isInvalid = !0, $scope.name = { | |
required: !1, | |
disabled: !1, | |
readonly: !1 | |
}, $scope.metric = { | |
required: !1, | |
disabled: !1, | |
readonly: !1 | |
}, $scope.dimension = { | |
required: !1, | |
disabled: !1, | |
readonly: !1 | |
}, $scope.group = { | |
time: !1, | |
dimension: !1, | |
value: !1 | |
}, $scope.aggregation = { | |
mean: !1, | |
sum: !1, | |
event_count: !1, | |
histogram: !1 | |
}, $scope.currency = { | |
disabled: !0, | |
eventCountDisabled: !0 | |
}, $scope.type = { | |
spark: !1 | |
}, $scope.$watch("widget.name", function(newVal, oldVal) { | |
newVal !== oldVal && widgetCheckRequirements() | |
}), $scope.$watch("widget.type", function(newVal, oldVal) { | |
newVal !== oldVal && widgetCheckType(newVal, oldVal) | |
}), $scope.$watch("widget.query.metric.currency", function(newVal, oldVal) { | |
newVal !== oldVal && ($scope.currencies.lastSelected = newVal) | |
}), $scope.$watch("widget.query.metric", function(newVal, oldVal) { | |
$scope.metricDisplay = newVal ? gaApiMeta.getMetricDisplay(newVal.category, newVal.event) : null, newVal !== oldVal && widgetCheckMetric(newVal, oldVal) | |
}), $scope.$watch("widget.query.filter", function(newVal, oldVal) { | |
newVal !== oldVal && widgetCheckFilter(newVal, oldVal), dimensionsProcess() | |
}), $scope.$watch("widget.query.group", function(newVal, oldVal) { | |
newVal !== oldVal && widgetCheckRequirements() | |
}), $scope.showHidePreview = function(show) { | |
$scope.isInvalid || show === !1 || ["pie", "table", "map", "quality"].indexOf($scope.widget.type) > -1 ? $scope.widgetPreview = null : ($scope.widgetPreviewOptions = { | |
range: { | |
main: gaUtilsDate.getPeriodRange("lastWeek"), | |
compare: !0 | |
} | |
}, $scope.widgetPreview = angular.copy($scope.widget)) | |
}; | |
var widgetCheckRequirementsTimer, widgetCheckRequirements = function() { | |
$timeout.cancel(widgetCheckRequirementsTimer), widgetCheckRequirementsTimer = $timeout(_widgetCheckRequirements, 250) | |
}, | |
_widgetCheckRequirements = function() { | |
var isValid = !0; | |
return $scope.dimension.readonly = !1, $scope.metric.disabled = !1, $scope.currency.eventCountDisabled = !0, $scope.widget.name ? "quality" === $scope.widget.type ? ($scope.name.required = !1, isValid = !0) : $scope.widget.query.metric ? ($scope.name.required = !1, $scope.metric.required = !1, "pie" !== $scope.widget.type || "value" === $scope.widget.query.group || $scope.widget.query.filter ? $scope.dimension.required = !1 : ($scope.dimension.required = "You need a dimension for this visualization", isValid = !1)) : ($scope.name.required = !1, $scope.metric.required = "Select a core metric or one or more events", $scope.dimension.required = !1, isValid = !1) : ($scope.name.required = "Please give it a meaningful name", $scope.metric.required = !1, $scope.dimension.required = !1, isValid = !1), $scope.meta ? ($scope.type.spark = $scope.type.map = $scope.meta.histogram ? "This visualization is not compatible with the selected metric" : "", $scope.aggregation = { | |
mean: $scope.meta.aggregation.indexOf("mean") > -1 || !$scope.meta.aggregation.length, | |
sum: $scope.meta.aggregation.indexOf("sum") > -1, | |
event_count: $scope.meta.aggregation.indexOf("event_count") > -1, | |
histogram: $scope.meta.aggregation.indexOf("histogram") > -1 | |
}, $scope.dimension.disabled = !1, $scope.group.time = "pie" !== $scope.widget.type && $scope.meta.groupTime !== !1, $scope.group.value = $scope.meta.groupValues || $scope.meta.starEvent, $scope.group.dimension = $scope.widget.query.filter ? $scope.meta.groupTime !== !1 : !1, $scope.currency.typeSelect = $scope.meta.currency && "core" !== $scope.meta.category ? $scope.meta.currency : null) : ($scope.group = { | |
time: !1, | |
dimension: !1, | |
value: !1 | |
}, $scope.aggregation = { | |
mean: !1, | |
sum: !1, | |
event_count: !1, | |
histogram: !1 | |
}, $scope.dimension.disabled = !0, $scope.currency.disabled = !0, "map" !== $scope.widget.type && "quality" !== $scope.widget.type && ($scope.widget.query.filter = null), $scope.type.spark = $scope.type.map = ""), "pie" === $scope.widget.type && "value" === $scope.widget.query.group ? $scope.dimension.disabled = !0 : "map" === $scope.widget.type ? ($scope.dimension.disabled = !1, $scope.dimension.readonly = !0, $scope.group.value = !1, $scope.group.time = !1) : "spark" === $scope.widget.type ? ($scope.group.dimension = !1, $scope.group.value = !1) : "quality" === $scope.widget.type && ($scope.metric.required = !1, $scope.metric.disabled = !0, $scope.dimension.disabled = !1), autoSelect(), $scope.widget.query.group || "quality" === $scope.widget.type || (isValid = !1), $scope.widget.query.aggregation || "quality" === $scope.widget.type || (isValid = !1), $scope.isInvalid = !isValid, $scope.aggregationTooltip = $scope.widget.query && $scope.widget.query.metric && $scope.widget.query.metric.category ? gaApiMeta.getAggregationTooltip($scope.widget.query.metric.category) : {}, isValid | |
}, | |
autoSelect = function() { | |
var index = 0, | |
aggregations = ["mean", "sum", "event_count", "histogram"]; | |
for (index = 0; index < aggregations.length && !$scope.aggregation[$scope.widget.query.aggregation];) $scope.aggregation[aggregations[index]] && ($scope.widget.query.aggregation = aggregations[index]), index++; | |
$scope.aggregation[$scope.widget.query.aggregation] || ($scope.widget.query.aggregation = ""); | |
var groups = ["time", "dimension", "value"]; | |
for (index = 0; index < groups.length && !$scope.group[$scope.widget.query.group];) $scope.group[groups[index]] && ($scope.widget.query.group = groups[index]), index++; | |
$scope.group[$scope.widget.query.group] || ($scope.widget.query.group = ""), $scope.dimension.disabled && ($scope.widget.query.filter = null), $scope.metric.disabled && ($scope.widget.query.metric = null), $scope.widget && $scope.widget.query && $scope.widget.query.metric && $scope.meta && $scope.meta.currency && !$scope.widget.query.metric.currency && ($scope.widget.query.metric.currency = "business" !== $scope.widget.query.metric.category && "Virtual" === $scope.currencies.lastSelected ? "USD" : $scope.currencies.lastSelected || "USD"), $scope.type.spark && "spark" === $scope.widget.type ? $scope.widget.type = "line" : $scope.type.map && "map" === $scope.widget.type && ($scope.widget.type = "line") | |
}, | |
widgetCheckMetric = function() { | |
$scope.widget.query.metric ? ($scope.meta = gaApiMeta.getMetric($scope.widget.query.metric.category, $scope.widget.query.metric.event), widgetCheckRequirements()) : ($scope.meta = null, widgetCheckRequirements()) | |
}, | |
widgetCheckFilter = function() { | |
widgetCheckRequirements() | |
}, | |
widgetCheckType = function(newVal, oldVal) { | |
"map" === newVal ? $scope.widget.query.filter = { | |
dimension: "country", | |
values: ["*"] | |
} : "map" === oldVal ? $scope.widget.query.filter = null : widgetCheckRequirements(), "quality" === newVal ? ($scope.widget.grid.sizex = 4, $scope.widget.grid.sizey = 2) : "spark" === newVal ? ($scope.widget.grid.sizex = 1, $scope.widget.grid.sizey = 1) : 1 === sisexState || "pie" === newVal ? ($scope.widget.grid.sizex = 2, $scope.widget.grid.sizey = 1) : ($scope.widget.grid.sizex = sisexState, $scope.widget.grid.sizey = siseyState) | |
}; | |
$scope.meta = $scope.widget && $scope.widget.query.metric ? gaApiMeta.getMetric($scope.widget.query.metric.category, $scope.widget.query.metric.event) : null, $scope.widget = $scope.widget || { | |
id: Math.random().toString().replace(".", ""), | |
name: "", | |
grid: { | |
col: 1, | |
row: 1, | |
sizex: 2, | |
sizey: 1 | |
}, | |
type: "line", | |
query: { | |
metric: null, | |
aggregation: "mean", | |
group: "time", | |
filter: null | |
} | |
}; | |
var sisexState = $scope.widget.grid.sizex, | |
siseyState = $scope.widget.grid.sizey; | |
return dimensionsProcess(), widgetCheckRequirements(), { | |
metricpicker: metricpicker, | |
dimensionpicker: dimensionpicker, | |
validateWidget: validateWidget, | |
dimensionsProcess: dimensionsProcess | |
} | |
}).directive("gaWidgetEdit", function() { | |
var linkingFunction = function($scope, $element, $attrs, $controller) { | |
$scope.metricpicker = $controller.metricpicker, $scope.dimensionpicker = $controller.dimensionpicker, $scope.validateWidget = $controller.validateWidget, $scope.dimensionsProcess = $controller.dimensionsProcess | |
}; | |
return { | |
restrict: "A", | |
replace: !1, | |
link: linkingFunction, | |
controller: "gaWidgetEditController", | |
templateUrl: "/static/ga-app/modules/pages/game/dashboards/dialogs/widget-edit.html", | |
scope: !1 | |
} | |
}), angular.module("ga.pages.dashboard.dialog.widgetAdd", []).controller("gaWidgetAddController", function($scope) { | |
$scope.selected = { | |
dashboard: null, | |
widgets: [] | |
}, $scope.notHidden = function(dashboard) { | |
return dashboard.hidden !== !0 | |
}; | |
var addWidget = function(widget) { | |
$scope.selected.widgets.unshift(angular.copy(widget)) | |
}, | |
removeWidget = function($index) { | |
$scope.selected.widgets.splice($index, 1) | |
}; | |
return { | |
addWidget: addWidget, | |
removeWidget: removeWidget | |
} | |
}).directive("gaWidgetAdd", function() { | |
var linkingFunction = function($scope, $element, $attrs, $controller) { | |
$scope.addWidget = $controller.addWidget, $scope.removeWidget = $controller.removeWidget | |
}; | |
return { | |
restrict: "A", | |
replace: !1, | |
link: linkingFunction, | |
controller: "gaWidgetAddController", | |
templateUrl: "/static/ga-app/modules/pages/game/dashboards/dialogs/widget-add.html", | |
scope: !1 | |
} | |
}), angular.module("ga.pages.game.funnel.controller", ["ga.api.meta", "ga.api.data", "ga.api.data.funnel", "ga.api.metric", "ga.api.userDb.authenticated.game", "ga.api.userDb.authenticated.funnel", "ga.ui.modal", "ga.ui.sortable", "ga.services.dialogs", "ga.utils.date", "ga.utils.tracking", "ga.services.user", "ga.components.moment", "ga.pages.game.funnel.view", "ga.pages.game.funnel.dialogs.list-date-ranges", "ga.pages.game.funnel.dialogs.process", "ga.pages.game.funnel.dialogs.edit-prompt"]).service("gaFunnelController", function($rootScope, $state, $q, $filter, $timeout, moment, gaUtilsDate, gaUiModal, gaApiMetric, gaApiMeta, gaDialogs, gaApiDataFunnel, gaApiUserDbAuthenticatedGame, gaApiUserDbAuthenticatedFunnel, gaApiData, gaServicesUser, gaUtilsTracking) { | |
var _loaded = !1, | |
currentGameId = null, | |
_tmpCreatedFunnel = null, | |
_isDemo = !1, | |
_data = { | |
backendFunnels: [], | |
rawFunnels: [], | |
parsedFunnels: [], | |
filteredFunnelList: [] | |
}, | |
_defaultSort = { | |
name: "lastEdited", | |
desc: !0 | |
}, | |
_notification = null, | |
_listFilters = null, | |
_imported = !1, | |
_sortStatusIndex = ["processed", "processing", "queued", "failed", "notQueued"], | |
_lastLoadedTime = 0, | |
_loadFunnels = function(gameId) { | |
return _isDemo ? (_data.parsedFunnels = _getDemoFunnels(), $q.when(!0)) : gaApiUserDbAuthenticatedGame.getFunnels(gameId).then(function(funnels) { | |
return funnels ? (_data.rawFunnels = funnels, gaApiDataFunnel.getList(gameId)) : $q.reject() | |
}).then(function(backendList) { | |
backendList && backendList.length && (_data.backendFunnels = backendList), _parseFunnels(), _loaded = !0, _lastLoadedTime = moment() | |
}) | |
}, | |
_setDefaultFilters = function() { | |
_listFilters = { | |
status: { | |
processed: !0, | |
processing: !0, | |
queued: !0, | |
failed: !0, | |
notQueued: !0, | |
empty: !0 | |
}, | |
onlyOwned: !1, | |
sort: angular.copy(_defaultSort) | |
} | |
}, | |
_getStatus = function(name) { | |
var returnObj = {}; | |
switch (name) { | |
case "RUNNING": | |
case "QUEUED": | |
returnObj = { | |
id: "processing", | |
title: "Processing...", | |
css: "yellow ga-icon-refresh" | |
}; | |
break; | |
case "EMPTY": | |
returnObj = { | |
id: "processed", | |
title: "Processed", | |
css: "green ga-icon-check", | |
hasData: !1 | |
}; | |
break; | |
case "COMPLETED": | |
returnObj = { | |
id: "processed", | |
title: "Processed", | |
css: "green ga-icon-check", | |
hasData: !0 | |
}; | |
break; | |
case "FAILED": | |
returnObj = { | |
id: "failed", | |
title: "Failed", | |
css: "red ga-icon-severity-error" | |
}; | |
break; | |
default: | |
returnObj = { | |
id: "notQueued", | |
title: "Not processed", | |
css: "grey" | |
} | |
} | |
return returnObj | |
}, | |
_parseFunnels = function() { | |
_data.parsedFunnels = _data.rawFunnels.map(function(funnel) { | |
return _parseFunnel(funnel) | |
}) | |
}, | |
_parseFunnel = function(funnel) { | |
var interval = { | |
start: 0, | |
end: 0 | |
}, | |
dateRanges = [], | |
defaultDateRange = 0, | |
dateRangeListFormatted = "", | |
status = _getStatus(), | |
statusStates = {}; | |
funnel.date_ranges && funnel.date_ranges.length && funnel.date_ranges.forEach(function(drange) { | |
var tmpDateRange = { | |
id: drange.id, | |
backendId: drange.backend_id, | |
start: 1e3 * moment.utc(drange.from_date).unix(), | |
end: 1e3 * moment.utc(drange.to_date).unix(), | |
owner: gaServicesUser.id === drange.created_by_id, | |
createdBy: drange.created_by_name, | |
status: _getStatus() | |
}; | |
tmpDateRange.dateRangeFormatted = gaUtilsDate.getIntervalTitle(tmpDateRange), drange.backend_id && ("__failed__" === drange.backend_id ? (tmpDateRange.status = _getStatus("FAILED"), statusStates[tmpDateRange.status.id] || (statusStates[tmpDateRange.status.id] = []), statusStates[tmpDateRange.status.id].push(tmpDateRange)) : "__empty__" === drange.backend_id ? (tmpDateRange.status = _getStatus("EMPTY"), statusStates[tmpDateRange.status.id] || (statusStates[tmpDateRange.status.id] = []), statusStates[tmpDateRange.status.id].push(tmpDateRange)) : _data.backendFunnels.some(function(b) { | |
return b.funnel_id === drange.backend_id ? (tmpDateRange.status = _getStatus(b.status), tmpDateRange.interval = { | |
start: 1e3 * b.start, | |
end: 1e3 * b.end | |
}, statusStates[tmpDateRange.status.id] || (statusStates[tmpDateRange.status.id] = []), statusStates[tmpDateRange.status.id].push(tmpDateRange), funnel.settings.dimensions && angular.forEach(funnel.settings.dimensions, function(val, dim) { | |
val.values && 1 === val.values.length && "*" === val.values[0] && b.dimensions[dim] && !b.dimensions[dim].negation && (val.values = b.dimensions[dim].values) | |
}), funnel.settings.excludedDimensions && angular.forEach(funnel.settings.excludedDimensions, function(val, dim) { | |
val.values && 1 === val.values.length && "*" === val.values[0] && b.dimensions[dim] && b.dimensions[dim].negation && (val.values = b.dimensions[dim].values) | |
}), !0) : void 0 | |
})), dateRanges.push(tmpDateRange) | |
}); | |
var statusStatesFormatted = {}; | |
if (dateRanges.length) { | |
if (dateRanges.sort(function(a, b) { | |
return b.end > a.end ? 1 : a.end === b.end ? 0 : -1 | |
}), statusStates.processed && statusStates.processed.length) { | |
var tmpStatus = "COMPLETED"; | |
statusStates.processed.length === statusStates.processed.filter(function(dr) { | |
return dr.status && !dr.status.hasData | |
}).length ? (tmpStatus = "EMPTY", dateRanges.some(function(dr) { | |
return "processed" === dr.status.id ? (interval = { | |
start: dr.start, | |
end: dr.end | |
}, defaultDateRange = dr.id, !0) : void 0 | |
})) : dateRanges.some(function(dr) { | |
return "processed" === dr.status.id && dr.status.hasData ? (interval = { | |
start: dr.start, | |
end: dr.end | |
}, defaultDateRange = dr.id, !0) : void 0 | |
}), status = _getStatus(tmpStatus) | |
} else statusStates.processing && statusStates.processing.length ? (status = _getStatus("RUNNING"), dateRanges.some(function(dr) { | |
return "processing" === dr.status.id ? (interval = { | |
start: dr.start, | |
end: dr.end | |
}, defaultDateRange = dr.id, !0) : void 0 | |
})) : statusStates.failed && statusStates.failed.length ? (status = _getStatus("FAILED"), dateRanges.some(function(dr) { | |
return "failed" === dr.status.id ? (interval = { | |
start: dr.start, | |
end: dr.end | |
}, defaultDateRange = dr.id, !0) : void 0 | |
})) : (interval = { | |
start: dateRanges[0].start, | |
end: dateRanges[0].end | |
}, defaultDateRange = dateRanges[0].id); | |
dateRanges.length > 1 && (dateRangeListFormatted = dateRanges.filter(function(dr) { | |
return dr.id !== defaultDateRange | |
}).map(function(dr) { | |
return dr.dateRangeFormatted + (dr.status && "processed" === dr.status.id && !dr.status.hasData ? " (No data)" : "") | |
}).join("<br />")); | |
var diffStatus = 0; | |
angular.forEach(statusStates, function(state, key) { | |
var title = key; | |
title = "<strong>" + title.charAt(0).toUpperCase() + title.slice(1) + "</strong>", statusStatesFormatted[key] = { | |
count: state.length, | |
ranges: title + "<br />" + state.map(function(dr) { | |
return dr.dateRangeFormatted | |
}).join("<br />") | |
}, diffStatus++ | |
}), 2 > diffStatus && (statusStatesFormatted = {}) | |
} | |
var metrics = []; | |
funnel.settings.events && funnel.settings.events.length && (metrics = funnel.settings.events.map(function(e) { | |
var arrEvent = e.split(":"), | |
arrFEvent = e.replace(/ /gi, " ").split(":"); | |
arrFEvent.splice(-1, 1); | |
var fpath = arrFEvent.join(" > ") + " >"; | |
return fpath = fpath.charAt(0).toUpperCase() + fpath.slice(1), { | |
category: arrEvent[0], | |
shortName: getMetricShortName(e), | |
formatted: getMetricFormatted(e), | |
event: arrEvent.splice(1).join(":") | |
} | |
})); | |
var filters = []; | |
funnel.settings.dimensions && angular.forEach(funnel.settings.dimensions, function(val, dim) { | |
var meta = gaApiMeta.getDimension(dim) || null; | |
filters.push({ | |
meta: meta, | |
dimension: dim, | |
values: val.values, | |
formattedValues: val.values.map(function(value) { | |
return "*" === value ? "All" : $filter("formatUnitType")(gaApiMeta.getDimension(value).title, meta.type) | |
}) | |
}) | |
}); | |
var excludes = []; | |
return funnel.settings.excludedDimensions && angular.forEach(funnel.settings.excludedDimensions, function(val, dim) { | |
var meta = gaApiMeta.getDimension(dim) || null; | |
excludes.push({ | |
meta: meta, | |
dimension: dim, | |
values: val.values, | |
formattedValues: val.values.map(function(value) { | |
return "*" === value ? "All" : $filter("formatUnitType")(gaApiMeta.getDimension(value).title, meta.type) | |
}) | |
}) | |
}), { | |
id: funnel.id, | |
name: funnel.funnel_name, | |
createdBy: funnel.created_by_name, | |
owner: gaServicesUser.id === funnel.created_by_id, | |
dateRangeFormatted: gaUtilsDate.getIntervalTitle(interval), | |
dateRangeListFormatted: dateRangeListFormatted, | |
dateRange: interval.end, | |
dateRanges: dateRanges, | |
defaultDateRange: defaultDateRange, | |
statusStates: statusStatesFormatted, | |
lastEdited: moment.utc(funnel.edited_date).unix(), | |
status: status, | |
metrics: metrics, | |
filters: filters, | |
excludes: excludes, | |
range: { | |
main: { | |
start: interval.start, | |
end: interval.end | |
} | |
} | |
} | |
}, | |
_nbOfStatusFilters = function() { | |
var nb = 0; | |
return angular.forEach(_listFilters.status, function(stat) { | |
nb += stat ? 1 : 0 | |
}), nb | |
}, | |
_filterFunnelList = function(category, value) { | |
if (_data.parsedFunnels) { | |
category && ("status" === category ? _listFilters.status[value] = _listFilters.status[value] && _nbOfStatusFilters() > 1 ? !1 : !0 : "onlyOwned" === category && (_listFilters.onlyOwned = !_listFilters.onlyOwned)); | |
var list = []; | |
return _data.parsedFunnels.some(function(f) { | |
var valid = !0; | |
if (_listFilters.onlyOwned && !f.owner && (valid = !1), f.dateRanges && f.dateRanges.length) { | |
var drvalid = !1; | |
f.dateRanges.some(function(dr) { | |
return _listFilters.status[dr.status.id] ? (drvalid = !0, !0) : void 0 | |
}), drvalid || (valid = !1) | |
} else _listFilters.status[f.status.id] || (valid = !1); | |
valid && list.push(f) | |
}), list = _sortFunnelList(list), _data.filteredFunnelList = list, $q.all(list) | |
} | |
return $q.all([]) | |
}, | |
_sortFunnelList = function(value) { | |
return _listFilters.sort || (_listFilters.sort = angular.copy(_defaultSort)), angular.isArray(value) ? value.sort(_applyFunnelSort) : (_listFilters.sort.name === value ? _listFilters.sort.desc ? _listFilters.sort = angular.copy(_defaultSort) : _listFilters.sort.desc = !0 : (_listFilters.sort.name = value, _listFilters.sort.desc = !1), void _data.filteredFunnelList.sort(_applyFunnelSort)) | |
}, | |
_applyFunnelSort = function(a, b) { | |
if ("status" === _listFilters.sort.name || ["lastEdited", "dateRange"].indexOf(_listFilters.sort.name) > -1) { | |
var sortA = a[_listFilters.sort.name], | |
sortB = b[_listFilters.sort.name]; | |
return "status" === _listFilters.sort.name && (sortA = _sortStatusIndex.indexOf(sortA.id), sortB = _sortStatusIndex.indexOf(sortB.id)), _listFilters.sort.desc ? sortB > sortA ? 1 : sortA === sortB ? 0 : -1 : sortA > sortB ? 1 : sortA === sortB ? 0 : -1 | |
} | |
return _listFilters.sort.desc ? b[_listFilters.sort.name].localeCompare(a[_listFilters.sort.name]) : a[_listFilters.sort.name].localeCompare(b[_listFilters.sort.name]) | |
}, | |
_nameDialog = function(name, duplicate) { | |
var deferred = $q.defer(), | |
$newScope = $rootScope.$new(), | |
title = "Create funnel"; | |
$newScope.values = { | |
name: "Untitled funnel" | |
}, name && ($newScope.values = { | |
name: name | |
}, title = duplicate ? "Duplicate funnel" : "Rename funnel"); | |
var createTemplate = '<div class="ga"><label for="name">Name</label><input class="ga-input full-width" name="name" ng-model="values.name" /></div>', | |
buttons = [{ | |
title: "Save", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "confirm", | |
disabled: "!values.name" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
action: "cancel", | |
keyCode: 27 | |
}]; | |
return gaUiModal.show({ | |
scope: $newScope, | |
header: title, | |
content: createTemplate, | |
width: 500, | |
actions: { | |
cancel: function() { | |
deferred.reject() | |
}, | |
confirm: function() { | |
deferred.resolve($newScope.values.name) | |
} | |
}, | |
always: function() { | |
$newScope.$destroy() | |
}, | |
buttons: buttons | |
}), deferred.promise | |
}, | |
getEmptyFunnel = function(name) { | |
return { | |
id: 0, | |
name: name || "Untitled funnel", | |
metrics: [], | |
filters: [], | |
excludes: [], | |
dateRanges: [], | |
range: { | |
main: gaUtilsDate.getPeriodRange("last30Days") | |
} | |
} | |
}, | |
getFunnelAndDateRangeFromBackendId = function(backendId) { | |
return getFunnelList($state.params.gameId).then(function(funnelList) { | |
if (funnelList && funnelList.length) { | |
var foundDateRangeId = !1, | |
returnObj = null; | |
return funnelList.some(function(funnel) { | |
return funnel.dateRanges && funnel.dateRanges.some(function(dr) { | |
dr.backendId === backendId && (foundDateRangeId = dr.id) | |
}), foundDateRangeId ? (returnObj = { | |
funnelId: funnel.id, | |
dateRangeId: foundDateRangeId | |
}, !0) : void 0 | |
}), returnObj ? returnObj : $q.reject() | |
} | |
return $q.reject() | |
}) | |
}, | |
getFunnelList = function(gameId, filters, reload) { | |
filters && (_listFilters = filters); | |
var expired = moment().diff(_lastLoadedTime, "seconds") > 60; | |
return reload || !_loaded || currentGameId !== gameId || expired ? (currentGameId === gameId && _listFilters || (currentGameId = gameId, _isDemo = gaServicesUser.game(parseInt(currentGameId, 10)).demo, _setDefaultFilters()), _loadFunnels(gameId).then(function() { | |
return _filterFunnelList() | |
})) : _filterFunnelList() | |
}, | |
getFunnel = function(gameId, funnelId, reload) { | |
var promises = !0; | |
return (reload || !_loaded || currentGameId !== gameId) && (currentGameId = gameId, _isDemo = gaServicesUser.game(parseInt(currentGameId, 10)).demo, _setDefaultFilters(), promises = _loadFunnels(gameId)), $q.all(promises).then(function() { | |
funnelId = isNaN(funnelId) ? funnelId : parseInt(funnelId, 10); | |
var tmpFunnel = null; | |
return _data.parsedFunnels.some(function(funnel) { | |
return isNaN(funnelId) && funnel.backendId === funnelId ? (tmpFunnel = funnel, !0) : isNaN(funnelId) || funnel.id !== funnelId ? void 0 : (tmpFunnel = funnel, !0) | |
}), tmpFunnel ? angular.copy(tmpFunnel) : $q.reject() | |
}) | |
}, | |
getFunnelWithData = function(gameId, funnelId, dateRangeId, reload) { | |
return getFunnel(gameId, funnelId, reload).then(function(tmpFunnel) { | |
return _isDemo ? _getDemoFunnelDateRange(tmpFunnel, dateRangeId) : (tmpFunnel.dateRangeFormatted = gaUtilsDate.getIntervalTitle(tmpFunnel.range.main), tmpFunnel && tmpFunnel.status && "processed" === tmpFunnel.status.id && !tmpFunnel.status.hasData ? _setDimensionValues(tmpFunnel).then(function(newFunnel) { | |
return _getFunnelWithData(newFunnel, dateRangeId) | |
}) : _getFunnelWithData(tmpFunnel, dateRangeId)) | |
}) | |
}, | |
_getFunnelWithData = function(funnel, dateRangeId) { | |
return gaApiDataFunnel.getFunnel($state.params.gameId, funnel, dateRangeId).then(function(data) { | |
return funnel.query = { | |
left: data.query | |
}, funnel.overview = data.overview, funnel | |
}).catch(function() { | |
return funnel | |
}) | |
}, | |
_setDimensionValues = function(funnel) { | |
var lookup = !1; | |
return funnel && funnel.filters && funnel.filters.some(function(filter) { | |
return filter.values && "*" === filter.values[0] ? (lookup = !0, !0) : void 0 | |
}), lookup ? gaApiData.getValue("/dimensions", $state.params.gameId).then(function(dimensions) { | |
return dimensions && funnel.filters.forEach(function(filter) { | |
filter.values && "*" === filter.values[0] && dimensions[filter.dimension] && (filter.values = dimensions[filter.dimension]) | |
}), funnel | |
}) : $q.when(funnel) | |
}, | |
saveFunnel = function(funnel) { | |
if (_isDemo) return $q.reject(); | |
var dimensions = {}; | |
funnel.filters && funnel.filters.length && funnel.filters.some(function(filter) { | |
dimensions[filter.dimension] = { | |
values: filter.values | |
} | |
}); | |
var excludedDimensions = {}; | |
funnel.excludes && funnel.excludes.length && funnel.excludes.some(function(filter) { | |
excludedDimensions[filter.dimension] = { | |
values: filter.values | |
} | |
}); | |
var tmpEvents = []; | |
funnel.metrics && funnel.metrics.length && (tmpEvents = funnel.metrics.map(function(metric) { | |
return metric.category + ":" + metric.event | |
})); | |
var options = { | |
events: tmpEvents, | |
dimensions: dimensions, | |
excludedDimensions: excludedDimensions | |
}; | |
return _saveFunnelToDB(funnel, options) | |
}, | |
_saveFunnelToDB = function(funnel, options) { | |
return funnel.id ? gaApiUserDbAuthenticatedFunnel.updateFunnel(funnel.id, funnel.name, options, funnel.dateRanges).then(function(result) { | |
if (result && result[0]) { | |
var parsedFunnel = _parseFunnel(result[0]); | |
return _data.parsedFunnels = _data.parsedFunnels.map(function(f) { | |
return f.id === funnel.id && (f = parsedFunnel), f | |
}), parsedFunnel | |
} | |
}) : gaApiUserDbAuthenticatedGame.createFunnel($state.params.gameId, funnel.name, options, funnel.dateRanges).then(function(f) { | |
return _loadFunnels($state.params.gameId).then(function() { | |
return getFunnel($state.params.gameId, f.id) | |
}) | |
}) | |
}, | |
reProcessFunnel = function(funnel) { | |
return processFunnel(funnel, !0) | |
}, | |
_processDateRange = function(options) { | |
var processOptions = angular.copy(options), | |
query = { | |
metric: { | |
category: processOptions.events[0].category, | |
event: processOptions.events[0].event | |
}, | |
filter: null, | |
group: "aggregated", | |
aggregation: "event_count", | |
interval: { | |
start: processOptions.start, | |
end: processOptions.end | |
}, | |
compareInterval: !1, | |
returnAll: !1, | |
merged: !1 | |
}; | |
return "business" === query.metric.category && (query.metric.currency = "USD"), gaApiData.get(query).then(function(result) { | |
var hasEvents = !1; | |
return result && result.data && result.data.aggregated && result.data.aggregated[0].total && result.data.aggregated[0].total > 0 && (hasEvents = !0), hasEvents ? (processOptions.events = processOptions.events.map(function(event) { | |
return event.category + ":" + event.event + ":.*" | |
}), gaApiDataFunnel.processFunnel($state.params.gameId, gaServicesUser.details.email, processOptions).catch(function() { | |
return null | |
})) : { | |
funnel_id: "__empty__", | |
status: "empty" | |
} | |
}) | |
}, | |
processFunnel = function(funnel, reprocess) { | |
return _isDemo ? $q.reject() : _validateFunnel(funnel).then(function() { | |
return _processFunnel(funnel, reprocess) | |
}).catch(function() { | |
return $q.reject({ | |
error: "Can't process the funnel" | |
}) | |
}) | |
}, | |
_processFunnel = function(funnel, reprocess) { | |
var promises = {}, | |
dimensions = {}; | |
funnel.filters && funnel.filters.length && funnel.filters.some(function(filter) { | |
dimensions[filter.dimension] = { | |
values: filter.values | |
} | |
}), funnel.excludes && funnel.excludes.length && funnel.excludes.some(function(filter) { | |
dimensions[filter.dimension] = { | |
values: filter.values, | |
negation: !0 | |
} | |
}); | |
var options = { | |
events: funnel.metrics.map(function(metric) { | |
return { | |
category: metric.category, | |
event: metric.event | |
} | |
}), | |
dimensions: dimensions, | |
start: 0, | |
end: 0, | |
name: funnel.name | |
}; | |
return funnel.dateRanges.some(function(dr) { | |
var notQueued = dr.status && "notQueued" === dr.status.id; | |
return reprocess && dr.backendId && !notQueued ? !1 : (options.start = dr.start, options.end = dr.end, void(promises[dr.id] = _processDateRange(options))) | |
}), $q.all(promises).then(function(results) { | |
if (results) { | |
var status = "processing", | |
emptyDateRange = null, | |
failed = 0, | |
count = 0; | |
return angular.forEach(results, function(data, key) { | |
data ? data.funnel_id && data.status && funnel.dateRanges.some(function(dr) { | |
dr.id === parseInt(key) && (dr.backendId = data.funnel_id, "__empty__" === data.funnel_id && (emptyDateRange || (emptyDateRange = dr, status = "empty"))), dr.status = { | |
id: "added" | |
} | |
}) : (failed++, funnel.dateRanges.some(function(dr) { | |
dr.id === parseInt(key) && (dr.backendId = "__failed__") | |
})), count++ | |
}), failed === count && (status = "failed"), saveFunnel(funnel).then(function(savedFunnel) { | |
return getFunnel($state.params.gameId, savedFunnel.id, !0) | |
}).then(function(funnel) { | |
var trackingLabel = ""; | |
return trackingLabel = "failed" === status ? "failed" : reprocess && "empty" === status ? "empty-existing" : "empty" === status ? "empty-new" : reprocess ? "queued-existing" : "queued", gaUtilsTracking.trackEvent({ | |
category: "funnels", | |
action: "process", | |
label: trackingLabel | |
}), { | |
funnel: funnel, | |
status: status, | |
dateRange: emptyDateRange | |
} | |
}) | |
} | |
}) | |
}, | |
_validateFunnel = function(funnel) { | |
var valid = gaServicesUser.details.email && funnel.metrics.length > 0 && funnel.dateRanges && funnel.dateRanges.length > 0; | |
return valid ? $q.when(!0) : $q.reject() | |
}, | |
importFunnels = function(gameId) { | |
if (_imported && currentGameId === gameId && !_isDemo) return $q.when(!0); | |
_imported = !0; | |
var importStatus = { | |
existingFunnels: !1, | |
imported: !0, | |
eventErrors: !1, | |
funnelErrors: !1 | |
}; | |
return gaApiUserDbAuthenticatedGame.saveOldFunnelsImported($state.params.gameId).then(function() { | |
return $timeout(gaServicesUser.getUserData.bind(gaServicesUser), 50), gaApiUserDbAuthenticatedGame.getOldFunnels(gameId).then(function(result) { | |
return result && result.length ? (importStatus.existingFunnels = !0, _parseOldFunnels(result).then(function(funnels) { | |
var promises = []; | |
return funnels && funnels.length ? (angular.forEach(funnels, function(funnel) { | |
funnel ? (funnel.importError && (importStatus.eventErrors = !0), promises.push(saveFunnel(funnel))) : importStatus.funnelErrors = !0 | |
}), 0 === promises.length && funnels.length > 0 && (importStatus.imported = !1), $q.all(promises).then(function() { | |
return importStatus | |
})) : importStatus | |
})) : importStatus | |
}) | |
}) | |
}, | |
importedDialog = function(status) { | |
var deferred = $q.defer(), | |
$newScope = $rootScope.$new(), | |
headline = "", | |
text = "", | |
btnText = "", | |
title = "Importing existing funnels"; | |
status.imported ? status.eventErrors ? (headline = "Funnels imported with events missing", text = "All existing funnels have been imported, however certain events could not be re-created. ", text += "You can change the order of events and remember that all funnels will need to be processed with a date range.", btnText = "View funnels") : status.funnelErrors ? (headline = "Most funnels are imported", text = "We managed to import most of your existing funnels, however certain funnels could not be re-created. ", text += "You can change the order of events and remember that all funnels will need to be processed with a date range.", btnText = "View funnels") : (headline = "Funnels imported succesfully", text = "All existing funnels have been imported and are now available. ", text += "You can change the order of events and start choosing dimensions you wish to include or exclude. ", text += "All funnels will need to be processed with a date range.", btnText = "View funnels") : (headline = "No funnels imported", text = "Unfortunately we could not re-create any of the existing funnels for this game. <br />", text += "You can create new funnels from design and business events tracked in the game and segment by different dimensions.", btnText = "Start using funnels"); | |
var createTemplate = '<div class="ga"><h3>' + headline + "</h3><p>" + text + "</p><p class=\"modal-notice\">Please note that the 'Started Game' event has been removed as part of the update</p></div>", | |
buttons = [{ | |
title: btnText, | |
"class": "ga-btn-alt orange", | |
keyCode: 13, | |
action: "confirm" | |
}]; | |
return gaUiModal.show({ | |
scope: $newScope, | |
header: title, | |
content: createTemplate, | |
customClass: "funnels-imported-modal", | |
width: 650, | |
actions: { | |
cancel: function() { | |
deferred.reject() | |
}, | |
confirm: function() { | |
deferred.reject() | |
} | |
}, | |
always: function() { | |
$newScope.$destroy() | |
}, | |
buttons: buttons | |
}), deferred.promise | |
}, | |
_parseOldFunnels = function(oldFunnels) { | |
var promises = []; | |
return angular.forEach(oldFunnels, function(funnel) { | |
promises.push(_parseOldFunnel(funnel)) | |
}), $q.all(promises) | |
}, | |
_parseOldFunnel = function(funnel) { | |
if (funnel.event_ids && funnel.event_ids.length) { | |
var promises = []; | |
return angular.forEach(funnel.event_ids, function(event) { | |
promises.push(gaApiMetric.getMetric(event)) | |
}), $q.all(promises).then(function(eventList) { | |
var tmpFunnel = getEmptyFunnel(funnel.funnel_name); | |
return eventList && eventList.length ? (angular.forEach(eventList, function(event) { | |
event ? tmpFunnel.metrics.push(event) : tmpFunnel.importError = !0 | |
}), tmpFunnel.metrics && tmpFunnel.metrics.length ? tmpFunnel : null) : null | |
}).catch(function() { | |
return null | |
}) | |
} | |
return [] | |
}, | |
saveAndProcessFunnel = function(funnel) { | |
return saveFunnel(funnel).then(function(savedFunnel) { | |
var tmpSavedFunnel = savedFunnel; | |
return processFunnel(savedFunnel).catch(function() { | |
console.log(tmpSavedFunnel) | |
}) | |
}) | |
}, | |
getCreatedFunnel = function() { | |
return _tmpCreatedFunnel || (_tmpCreatedFunnel = getEmptyFunnel("Untitled funnel")), _tmpCreatedFunnel | |
}, | |
createFunnelDialog = function() { | |
return _nameDialog().then(function(name) { | |
gaUtilsTracking.trackEvent({ | |
category: "funnels", | |
action: "create", | |
label: "new" | |
}); | |
var newFunnel = getEmptyFunnel(name); | |
return saveFunnel(newFunnel) | |
}) | |
}, | |
renameFunnelDialog = function(funnel) { | |
return _nameDialog(funnel.name).then(function(name) { | |
var tmpFunnel = angular.copy(funnel); | |
return tmpFunnel.name = name, saveFunnel(tmpFunnel).then(function() { | |
return tmpFunnel | |
}) | |
}) | |
}, | |
duplicateFunnelDialog = function(funnel) { | |
return _nameDialog(funnel.name, !0).then(function(name) { | |
var tmpFunnel = angular.copy(funnel); | |
return tmpFunnel.name = name, tmpFunnel.id = null, tmpFunnel.dateRanges && (tmpFunnel.dateRanges = tmpFunnel.dateRanges.map(function(dr) { | |
return { | |
start: dr.start, | |
end: dr.end, | |
id: 0 | |
} | |
})), gaUtilsTracking.trackEvent({ | |
category: "funnels", | |
action: "create", | |
label: "duplicate" | |
}), saveFunnel(tmpFunnel).then(function(f) { | |
return f | |
}) | |
}) | |
}, | |
deleteFunnelDialog = function(funnel) { | |
return gaUiModal.confirm("Are you sure you want to delete this funnel? All processed data will be lost!", "Delete funnel").then(function() { | |
return gaApiUserDbAuthenticatedFunnel.deleteFunnel(funnel.id).then(function() { | |
var trackingLabel = "not-processed"; | |
return funnel.status && "processed" === funnel.status.id && (trackingLabel = "processed"), gaUtilsTracking.trackEvent({ | |
category: "funnels", | |
action: "delete", | |
label: trackingLabel | |
}), _loadFunnels($state.params.gameId) | |
}) | |
}).catch(function() { | |
return $q.reject({ | |
action: "closed" | |
}) | |
}) | |
}, | |
dateRangesDialog = function(funnel, process, failed) { | |
return gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/game/funnel/dialogs/list-date-ranges.html", | |
controller: "gaPagesFunnelListDateRangesController", | |
width: 800, | |
parameters: { | |
funnel: funnel, | |
failedOnly: failed || !1, | |
process: process | |
} | |
}) | |
}, | |
editPromptDialog = function(funnel) { | |
gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/game/funnel/dialogs/edit-prompt.html", | |
controller: "gaPagesFunnelEditPromptController", | |
width: 800, | |
parameters: { | |
funnel: funnel | |
} | |
}).then(function(result) { | |
result && ("duplicate" === result.action ? duplicateFunnelDialog(funnel).then(function(newFunnel) { | |
newFunnel && newFunnel.id && (setNotification("Funnel duplicated!"), $state.go("game.funnel.edit", { | |
funnelId: newFunnel.id, | |
gameId: $state.params.gameId | |
})) | |
}) : "edit" === result.action && (gaUtilsTracking.trackEvent({ | |
category: "funnels", | |
action: "create", | |
label: "edit-existing" | |
}), editFunnel(funnel.id))) | |
}) | |
}, | |
editFunnel = function(funnelId) { | |
getFunnel($state.params.gameId, funnelId).then(function(funnel) { | |
funnel.dateRanges && (funnel.dateRanges = funnel.dateRanges.map(function(dr) { | |
return dr.backendId = "", dr | |
})), saveFunnel(funnel).then(function() { | |
$state.go("game.funnel.edit", { | |
funnelId: $state.params.funnelId, | |
gameId: $state.params.gameId, | |
dateRangeId: $state.params.dateRangeId | |
}) | |
}) | |
}) | |
}, | |
getMetricShortName = function(event) { | |
if (event) { | |
var tmp = event.split(":").slice(-1)[0]; | |
return ".*" === tmp && (tmp = event.split(":").slice(-2)[0] + tmp), tmp.charAt(0).toUpperCase() + tmp.slice(1) | |
} | |
}, | |
getMetricFormatted = function(event, category) { | |
var name = getMetricShortName(event), | |
arrEvent = event.replace(/ /gi, " ").split(":"); | |
".*" === arrEvent[arrEvent.length - 1] ? arrEvent.splice(-2, 2) : arrEvent.splice(-1, 1); | |
var fpath = (category ? category + " > " : "") + (arrEvent.length ? arrEvent.join(" > ") + " > " : ""); | |
fpath = fpath.charAt(0).toUpperCase() + fpath.slice(1); | |
var fpathclean = fpath.replace(/ /g, " ").replace(/>/g, ">"); | |
return { | |
name: name, | |
path: fpath, | |
cleanPath: fpathclean + name | |
} | |
}, | |
getMetricFormattedName = function(metric) { | |
return { | |
path: metric.event, | |
name: metric.event.split(":").slice(-1)[0] | |
} | |
}, | |
getNewDateRange = function(range, dateRanges) { | |
if (range.start && range.end) { | |
if (!dateRanges) return !1; | |
var existing = dateRanges.filter(function(r) { | |
return r.start === range.start && r.end === range.end | |
}); | |
return 1 === existing.length && existing[0].delete ? (delete existing[0].delete, existing[0]) : { | |
id: 0, | |
createdBy: gaServicesUser.details.name, | |
status: { | |
title: "Just added - not processed", | |
css: "grey" | |
}, | |
start: range.start, | |
end: range.end, | |
dateRangeFormatted: gaUtilsDate.getIntervalTitle({ | |
start: range.start, | |
end: range.end | |
}), | |
"delete": !1 | |
} | |
} | |
return !1 | |
}, | |
summaryDialog = function(funnel) { | |
return gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/game/funnel/dialogs/process-funnel.html", | |
controller: "gaPagesFunnelProcessController", | |
width: 800, | |
parameters: { | |
funnel: funnel, | |
readOnly: !0 | |
} | |
}) | |
}, | |
hasFunnels = function() { | |
return !!_data.parsedFunnels.length | |
}, | |
getNotification = function() { | |
var tn = angular.copy(_notification); | |
return _notification = null, tn || null | |
}, | |
setNotification = function(message, type) { | |
_notification = { | |
message: message || "", | |
type: type || "default" | |
} | |
}, | |
_getDemoFunnelDateRange = function(funnel, dateRangeId) { | |
return funnel.overview = 1 === parseInt(dateRangeId, 10) ? { | |
avgTime: 65.21, | |
conversionRate: .596807172, | |
conversions: 15175, | |
dropoffs: 10254, | |
total: 25432 | |
} : { | |
avgTime: 64.71, | |
conversionRate: .6027, | |
conversions: 15175, | |
dropoffs: 9954, | |
total: 24932 | |
}, funnel | |
}, | |
_getDemoFunnels = function() { | |
var demoFunnels = [{ | |
id: 1, | |
createdBy: "GameAnalytics", | |
dateRange: 14041728e5, | |
dateRangeFormatted: "1. Jun - 30. Jun 2014", | |
dateRangeListFormatted: "1. May - 31. May 2014", | |
dateRanges: [{ | |
backendId: "backendDemo1", | |
createdBy: "GameAnalytics", | |
dateRangeFormatted: "1. Jun - 30. Jun 2014", | |
end: 14041728e5, | |
id: 1, | |
owner: !0, | |
start: 14015808e5, | |
status: { | |
css: "green ga-icon-check", | |
id: "processed", | |
title: "Processed", | |
hasData: !0 | |
} | |
}, { | |
backendId: "backendDemo2", | |
createdBy: "GameAnalytics", | |
dateRangeFormatted: "1. May - 31. May 2014", | |
end: 14041728e5, | |
id: 2, | |
owner: !0, | |
start: 14015808e5, | |
status: { | |
css: "green ga-icon-check", | |
id: "processed", | |
title: "Processed", | |
hasData: !0 | |
} | |
}], | |
defaultDateRange: 1, | |
excludes: [{ | |
dimension: "Devices", | |
meta: { | |
hidden: !1, | |
name: "device", | |
title: "Devices", | |
type: "dimension", | |
unit: "device" | |
}, | |
values: ["i1", "i2"], | |
formattedValues: ["iPhone 4", "iPhone 4S"] | |
}], | |
filters: [{ | |
dimension: "build", | |
meta: { | |
hidden: !1, | |
name: "build", | |
title: "Build", | |
type: "dimension", | |
unit: "build" | |
}, | |
values: ["1.0", "1.1", "1.2"], | |
formattedValues: ["1.0", "1.1", "1.2"] | |
}, { | |
dimension: "country", | |
meta: { | |
hidden: !1, | |
name: "country", | |
title: "Country", | |
type: "dimension", | |
unit: "country" | |
}, | |
values: ["US", "DK", "CA"], | |
formattedValues: ["United States", "Denmark", "Canada"] | |
}], | |
lastEdited: 1405338586, | |
metrics: [{ | |
category: "design", | |
event: "Level 1:EnterArea1", | |
shortName: "EnterArea1", | |
formatted: { | |
cleanPath: "Design > Level 1 > EnterArea1", | |
name: "EnterArea1", | |
path: "Design > Level 1 >EnterArea1 >" | |
} | |
}, { | |
category: "design", | |
event: "Level 1:CompleteArea1", | |
shortName: "CompleteArea1", | |
formatted: { | |
cleanPath: "Design > Level 1 > CompleteArea1", | |
name: "CompleteArea1", | |
path: "Design > Level 1 >CompleteArea1 >" | |
} | |
}, { | |
category: "design", | |
event: "Level 1:Levelup1", | |
shortName: "Levelup1", | |
formatted: { | |
cleanPath: "Design > Level 1 > Levelup1", | |
name: "Levelup1", | |
path: "Design > Level 1 >Levelup1 >" | |
} | |
}, { | |
category: "design", | |
event: "Level 2:EnterArea2", | |
shortName: "EnterArea2", | |
formatted: { | |
cleanPath: "Design > Level 2 > EnterArea2", | |
name: "EnterArea2", | |
path: "Design > Level 2 >EnterArea2 >" | |
} | |
}, { | |
category: "design", | |
event: "Level 2:CompleteArea2", | |
shortName: "CompleteArea2", | |
formatted: { | |
cleanPath: "Design > Level 2 > CompleteArea2", | |
name: "CompleteArea2", | |
path: "Design > Level 2 >CompleteArea2 >" | |
} | |
}, { | |
category: "design", | |
event: "Level 2:Levelup2", | |
shortName: "Levelup2", | |
formatted: { | |
cleanPath: "Design > Level 2 > Levelup2", | |
name: "Levelup2", | |
path: "Design > Level 2 >Levelup2 >" | |
} | |
}], | |
name: "Player progressions", | |
owner: !0, | |
range: { | |
main: { | |
start: 14015808e5, | |
end: 14015808e5 | |
} | |
}, | |
status: { | |
css: "green ga-icon-check", | |
id: "processed", | |
title: "Processed", | |
hasData: !0 | |
}, | |
overview: { | |
avgTime: 65.21, | |
conversionRate: .596807172, | |
conversions: 15175, | |
dropoffs: 10254, | |
total: 25432 | |
}, | |
query: { | |
left: { | |
activeDimensionIndex: 0, | |
aggregation: "sum", | |
aggregation_aggregated: "sum", | |
compare: !1, | |
data: { | |
timeseries: [{ | |
data: [{ | |
dimension: "1.0", | |
data: [{ | |
value: .1, | |
extraValues: { | |
count: 2543 | |
} | |
}, { | |
value: .091675841, | |
extraValues: { | |
count: 2331, | |
avgTime: 15, | |
dropoff: 212 | |
} | |
}, { | |
value: .084543095, | |
extraValues: { | |
count: 2150, | |
avgTime: 28, | |
dropoff: 181 | |
} | |
}, { | |
value: .076757628, | |
extraValues: { | |
count: 1952, | |
avgTime: 10, | |
dropoff: 198 | |
} | |
}, { | |
value: .068854199, | |
extraValues: { | |
count: 1751, | |
avgTime: 85, | |
dropoff: 201 | |
} | |
}, { | |
value: .059680717, | |
extraValues: { | |
count: 1518, | |
avgTime: 72, | |
dropoff: 233 | |
} | |
}] | |
}, { | |
dimension: "1.1", | |
data: [{ | |
value: .4, | |
extraValues: { | |
count: 10173 | |
} | |
}, { | |
value: .366703366, | |
extraValues: { | |
count: 9326, | |
avgTime: 13, | |
dropoff: 847 | |
} | |
}, { | |
value: .338172381, | |
extraValues: { | |
count: 8600, | |
avgTime: 28, | |
dropoff: 726 | |
} | |
}, { | |
value: .307030513, | |
extraValues: { | |
count: 7808, | |
avgTime: 57, | |
dropoff: 792 | |
} | |
}, { | |
value: .275416798, | |
extraValues: { | |
count: 7004, | |
avgTime: 74, | |
dropoff: 804 | |
} | |
}, { | |
value: .238722869, | |
extraValues: { | |
count: 6071, | |
avgTime: 69, | |
dropoff: 93 | |
} | |
}] | |
}, { | |
dimension: "1.2", | |
data: [{ | |
value: .5, | |
extraValues: { | |
count: 12716 | |
} | |
}, { | |
value: .458379207, | |
extraValues: { | |
count: 11658, | |
avgTime: 12, | |
dropoff: 1059 | |
} | |
}, { | |
value: .422715477, | |
extraValues: { | |
count: 10751, | |
avgTime: 78, | |
dropoff: 907 | |
} | |
}, { | |
value: .383788141, | |
extraValues: { | |
count: 9761, | |
avgTime: 54, | |
dropoff: 990 | |
} | |
}, { | |
value: .344270997, | |
extraValues: { | |
count: 8756, | |
avgTime: 24, | |
dropoff: 1005 | |
} | |
}, { | |
value: .298403586, | |
extraValues: { | |
count: 7589, | |
avgTime: 41, | |
dropoff: 1167 | |
} | |
}] | |
}], | |
meta: { | |
hidden: !1, | |
name: "build", | |
title: "Build", | |
type: "dimension", | |
unit: "build" | |
}, | |
total: 0 | |
}, { | |
data: [{ | |
dimension: "CA", | |
data: [{ | |
value: .05, | |
extraValues: { | |
count: 1271 | |
} | |
}, { | |
value: .045837921, | |
extraValues: { | |
count: 1166, | |
avgTime: 52, | |
dropoff: 105 | |
} | |
}, { | |
value: .042271548, | |
extraValues: { | |
count: 1075, | |
avgTime: 42, | |
dropoff: 91 | |
} | |
}, { | |
value: .038378814, | |
extraValues: { | |
count: 976, | |
avgTime: 94, | |
dropoff: 99 | |
} | |
}, { | |
value: .0344271, | |
extraValues: { | |
count: 876, | |
avgTime: 85, | |
dropoff: 100 | |
} | |
}, { | |
value: .029840359, | |
extraValues: { | |
count: 758, | |
avgTime: 19, | |
dropoff: 118 | |
} | |
}] | |
}, { | |
dimension: "DK", | |
data: [{ | |
value: .35, | |
extraValues: { | |
count: 8901 | |
} | |
}, { | |
value: .320865445, | |
extraValues: { | |
count: 8160, | |
avgTime: 57, | |
dropoff: 741 | |
} | |
}, { | |
value: .295900834, | |
extraValues: { | |
count: 7525, | |
avgTime: 67, | |
dropoff: 635 | |
} | |
}, { | |
value: .268651699, | |
extraValues: { | |
count: 6832, | |
avgTime: 25, | |
dropoff: 693 | |
} | |
}, { | |
value: .240989698, | |
extraValues: { | |
count: 6129, | |
avgTime: 11, | |
dropoff: 703 | |
} | |
}, { | |
value: .20888251, | |
extraValues: { | |
count: 5312, | |
avgTime: 55, | |
dropoff: 817 | |
} | |
}] | |
}, { | |
dimension: "US", | |
data: [{ | |
value: .6, | |
extraValues: { | |
count: 12716 | |
} | |
}, { | |
value: .550055049, | |
extraValues: { | |
count: 13989, | |
avgTime: 24, | |
dropoff: 1270 | |
} | |
}, { | |
value: .507258572, | |
extraValues: { | |
count: 12901, | |
avgTime: 41, | |
dropoff: 1088 | |
} | |
}, { | |
value: .460545769, | |
extraValues: { | |
count: 11713, | |
avgTime: 95, | |
dropoff: 1188 | |
} | |
}, { | |
value: .413125197, | |
extraValues: { | |
count: 10507, | |
avgTime: 35, | |
dropoff: 1206 | |
} | |
}, { | |
value: .358084303, | |
extraValues: { | |
count: 9107, | |
avgTime: 25, | |
dropoff: 1400 | |
} | |
}] | |
}], | |
meta: { | |
hidden: !1, | |
name: "country", | |
title: "Country", | |
type: "dimension", | |
unit: "country" | |
}, | |
total: 0 | |
}] | |
}, | |
dimensionMeta: [{ | |
hidden: !1, | |
name: "build", | |
title: "Build", | |
type: "dimension", | |
unit: "build" | |
}, { | |
hidden: !1, | |
name: "country", | |
title: "Country", | |
type: "dimension", | |
unit: "country" | |
}], | |
dimensions: [{ | |
dimension: "build", | |
formattedValues: ["1.0", "1.1", "1.2"], | |
meta: { | |
hidden: !1, | |
name: "build", | |
title: "Build", | |
type: "dimension", | |
unit: "build" | |
}, | |
values: ["1.0", "1.1", "1.2"] | |
}, { | |
dimension: "country", | |
formattedValues: ["United States", "Denmark", "Canada"], | |
meta: { | |
hidden: !1, | |
name: "country", | |
title: "Country", | |
type: "dimension", | |
unit: "country" | |
}, | |
values: ["US", "DK", "CA"] | |
}], | |
filter: [{ | |
dimension: "build", | |
values: ["1.0", "1.1", "1.2"] | |
}, { | |
dimension: "country", | |
values: ["US", "DK", "CA"] | |
}], | |
group: "metric", | |
interval: { | |
start: 14015808e5, | |
end: 14015808e5 | |
}, | |
intervalDisplay: "1. Jun - 30. Jun 2014", | |
meta: { | |
subTitle: "", | |
title: "Player progressions", | |
type: "string", | |
unit: "none" | |
}, | |
type: "bar", | |
xValues: [{ | |
title: "EnterArea1", | |
meta: { | |
category: "design", | |
event: "Level 1:EnterArea1", | |
inactive: !1, | |
keyUnit: void 0, | |
subEvent: void 0, | |
title: "EnterArea1", | |
type: "number", | |
unit: "none" | |
}, | |
values: { | |
diff: 1, | |
sum: 25432 | |
} | |
}, { | |
title: "CompleteArea1", | |
meta: { | |
category: "design", | |
event: "Level 1:CompleteArea1", | |
inactive: !1, | |
keyUnit: void 0, | |
subEvent: void 0, | |
title: "CompleteArea1", | |
type: "number", | |
unit: "none" | |
}, | |
values: { | |
diff: .916758415, | |
sum: 23315 | |
} | |
}, { | |
title: "Levelup1", | |
meta: { | |
category: "design", | |
event: "Level 1:Levelup1", | |
inactive: !1, | |
keyUnit: void 0, | |
subEvent: void 0, | |
title: "Levelup1", | |
type: "number", | |
unit: "none" | |
}, | |
values: { | |
diff: .845430953, | |
sum: 21501 | |
} | |
}, { | |
title: "EnterArea2", | |
meta: { | |
category: "design", | |
event: "Level 2:EnterArea2", | |
inactive: !1, | |
keyUnit: void 0, | |
subEvent: void 0, | |
title: "EnterArea2", | |
type: "number", | |
unit: "none" | |
}, | |
values: { | |
diff: .767576282, | |
sum: 19521 | |
} | |
}, { | |
title: "CompleteArea2", | |
meta: { | |
category: "design", | |
event: "Level 2:CompleteArea2", | |
inactive: !1, | |
keyUnit: void 0, | |
subEvent: void 0, | |
title: "CompleteArea2", | |
type: "number", | |
unit: "none" | |
}, | |
values: { | |
diff: .688541994, | |
sum: 17511 | |
} | |
}, { | |
title: " Levelup2", | |
meta: { | |
category: "design", | |
event: "Level 2: Levelup2", | |
inactive: !1, | |
keyUnit: void 0, | |
subEvent: void 0, | |
title: " Levelup2", | |
type: "number", | |
unit: "none" | |
}, | |
values: { | |
diff: .596807172, | |
sum: 15178 | |
} | |
}], | |
yMeta: { | |
type: "percent", | |
unit: "percent" | |
} | |
} | |
}, | |
statusStates: {} | |
}]; | |
return demoFunnels | |
}; | |
return { | |
getFunnelList: getFunnelList, | |
getFunnelWithData: getFunnelWithData, | |
getFunnel: getFunnel, | |
getCreatedFunnel: getCreatedFunnel, | |
createFunnelDialog: createFunnelDialog, | |
renameFunnelDialog: renameFunnelDialog, | |
duplicateFunnelDialog: duplicateFunnelDialog, | |
dateRangesDialog: dateRangesDialog, | |
editPromptDialog: editPromptDialog, | |
editFunnel: editFunnel, | |
deleteFunnelDialog: deleteFunnelDialog, | |
getMetricShortName: getMetricShortName, | |
getMetricFormattedName: getMetricFormattedName, | |
getMetricFormatted: getMetricFormatted, | |
getFunnelAndDateRangeFromBackendId: getFunnelAndDateRangeFromBackendId, | |
getNewDateRange: getNewDateRange, | |
hasFunnels: hasFunnels, | |
saveFunnel: saveFunnel, | |
processFunnel: processFunnel, | |
reProcessFunnel: reProcessFunnel, | |
saveAndProcessFunnel: saveAndProcessFunnel, | |
getNotification: getNotification, | |
setNotification: setNotification, | |
importFunnels: importFunnels, | |
importedDialog: importedDialog, | |
summaryDialog: summaryDialog | |
} | |
}), angular.module("ga.pages.game.funnel.list", ["ga.pages.game.funnel.controller", "ga.api.meta", "ga.api.data.funnel", "ga.api.userDb.authenticated.game", "ga.ui.modal", "ga.ui.sortable", "ga.services.dialogs", "ga.utils.date", "ga.utils.tracking", "ga.services.user", "ga.components.moment", "ga.pages.game.funnel.view", "ga.ui.notify"]).controller("gaPagesFunnelListController", function($scope, $rootScope, $state, $q, $filter, $interval, gaUiNotify, moment, gaUtilsDate, gaUiModal, gaApiMeta, gaDialogs, gaApiDataFunnel, gaApiUserDbAuthenticatedGame, gaServicesUser, gaFunnelController, gaUtilsTracking) { | |
$scope.loading = !1, $scope.error = !1, $scope.funnels = [], $scope.hasFunnels = !1, $scope.listFilters = { | |
status: { | |
processed: !0, | |
processing: !0, | |
failed: !0, | |
notQueued: !0 | |
}, | |
onlyOwned: !1, | |
sort: null | |
}; | |
var game = gaServicesUser.game(parseInt($state.params.gameId, 10)); | |
$scope.isDemo = game.demo, $scope.importing = !1; | |
var _loadFunnelList = function(reload) { | |
if ($scope.loading = !0, reload = reload || !1, game && void 0 !== game.old_funnels_imported && !game.old_funnels_imported) { | |
$scope.importing = !0; | |
var importStatus = {}; | |
gaFunnelController.importFunnels($state.params.gameId).then(function(status) { | |
importStatus = status, gaFunnelController.getFunnelList($state.params.gameId, $scope.listFilters, !0).then(function(list) { | |
$scope.funnels = list, $scope.loading = !1, $scope.importing = !1, $scope.hasFunnels = gaFunnelController.hasFunnels(), importStatus.existingFunnels && gaFunnelController.importedDialog(importStatus), $scope.hasFunnels && _startAutoUpdater() | |
}) | |
}).catch(function() { | |
gaFunnelController.getFunnelList($state.params.gameId, $scope.listFilters, reload).then(function(list) { | |
$scope.funnels = list, $scope.loading = !1, $scope.hasFunnels = gaFunnelController.hasFunnels(), $scope.hasFunnels && _startAutoUpdater() | |
}) | |
}) | |
} else gaFunnelController.getFunnelList($state.params.gameId, $scope.listFilters, reload).then(function(list) { | |
$scope.funnels = list, $scope.loading = !1, $scope.hasFunnels = gaFunnelController.hasFunnels(), $scope.hasFunnels && _startAutoUpdater() | |
}).catch(function() { | |
$scope.error = !0 | |
}) | |
}, | |
_nbOfStatusFilters = function() { | |
var nb = 0; | |
return angular.forEach($scope.listFilters.status, function(stat) { | |
nb += stat ? 1 : 0 | |
}), nb | |
}; | |
$scope.filterFunnelList = function(category, value) { | |
category && ("status" === category ? $scope.listFilters.status[value] = $scope.listFilters.status[value] && _nbOfStatusFilters() > 1 ? !1 : !0 : "onlyOwned" === category && ($scope.listFilters.onlyOwned = !$scope.listFilters.onlyOwned)), _loadFunnelList() | |
}, $scope.sortFunnelList = function(value) { | |
$scope.listFilters.sort || ($scope.listFilters.sort = { | |
name: value, | |
desc: !1 | |
}), angular.isArray(value) || ($scope.listFilters.sort.name === value ? $scope.listFilters.sort.desc ? $scope.listFilters.sort = null : $scope.listFilters.sort.desc = !0 : ($scope.listFilters.sort.name = value, $scope.listFilters.sort.desc = !1)), _loadFunnelList() | |
}, $scope.createFunnel = function() { | |
gaFunnelController.createFunnelDialog().then(function(funnel) { | |
gaFunnelController.setNotification("Funnel created!"), $scope.editFunnel(funnel.id) | |
}) | |
}, $scope.editFunnel = function(funnelId) { | |
$state.go("game.funnel.edit", { | |
funnelId: funnelId, | |
gameId: $state.params.gameId | |
}) | |
}, $scope.showFunnel = function(funnel) { | |
"processed" === funnel.status.id ? (gaUtilsTracking.trackEvent({ | |
category: "funnels", | |
action: "view", | |
label: "processed" | |
}), $state.go("game.funnel.view", { | |
funnelId: funnel.id, | |
dateRangeId: funnel.defaultDateRange, | |
gameId: $state.params.gameId | |
})) : "processing" !== funnel.status.id ? (gaUtilsTracking.trackEvent({ | |
category: "funnels", | |
action: "view", | |
label: "not-processed" | |
}), $state.go("game.funnel.edit", { | |
funnelId: funnel.id, | |
gameId: $state.params.gameId | |
})) : (gaUtilsTracking.trackEvent({ | |
category: "funnels", | |
action: "view", | |
label: "queued" | |
}), gaFunnelController.summaryDialog(funnel)) | |
}; | |
var _autoLoader, _startAutoUpdater = function() { | |
angular.isDefined(_autoLoader) || (_autoLoader = $interval(function() { | |
_loadFunnelList(!0) | |
}, 6e4)) | |
}, | |
_stopAutoUpdater = function() { | |
angular.isDefined(_autoLoader) && ($interval.cancel(_autoLoader), _autoLoader = void 0) | |
}; | |
_loadFunnelList($state.params.reload); | |
var noti = gaFunnelController.getNotification(); | |
noti && gaUiNotify.show(noti.message, 4e3, noti.type), $scope.$on("$destroy", function() { | |
_stopAutoUpdater() | |
}) | |
}), angular.module("ga.pages.game.funnel.view", ["ga.ui.json", "ga.visualizations.chartCanvas", "ga.visualizations.expandableTable", "ga.utils.transform.chart", "ga.utils.transform.grid", "ga.utils.tracking", "ga.pages.game.funnel.controller", "ga.ui.notify", "ga.ui.tour", "ga.services.user"]).controller("gaPagesFunnelViewController", function($scope, $rootScope, $state, $q, $filter, $timeout, $cookies, gaUiTour, gaServicesUser, gaUtilsTracking, gaUiNotify, gaFunnelController, gaUtilsChartTransform, gaUtilsGridTransform) { | |
$scope.loading = !1, $scope.error = !1, $scope.backendError = !1, $scope.noData = !1, $scope.activeFunnel = null, $scope.activeDateRange = null, $scope.settings = { | |
activeDimension: 0, | |
tableGrouping: "metric" | |
}, $scope.processStates = { | |
errors: null, | |
processing: null | |
}, $scope.showFilters = !1, $scope.chart = { | |
settings: {} | |
}, $scope.table = { | |
settings: { | |
maxRows: 15, | |
maxCols: 50, | |
pager: !0, | |
colPager: !1, | |
sortable: !0, | |
more: !1, | |
totals: !1, | |
compare: !1, | |
compareHidden: !0, | |
tooltipEnabled: !0, | |
tooltipType: "metric" | |
}, | |
tableView: "list", | |
datasets: null | |
}, $scope.isDemo = gaServicesUser.game(parseInt($state.params.gameId, 10)).demo; | |
var _loadFunnel = function(funnelId, dateRangeId) { | |
$scope.loading = !0, isNaN(funnelId) ? gaFunnelController.getFunnelAndDateRangeFromBackendId(funnelId).then(function(result) { | |
result && result.funnelId && result.dateRangeId ? $state.go("game.funnel.view", { | |
funnelId: result.funnelId, | |
dateRangeId: result.rangeId, | |
gameId: $state.params.gameId | |
}) : ($scope.loading = !1, $scope.backendError = !0, $scope.error = !0) | |
}).catch(function() { | |
$scope.loading = !1, $scope.backendError = !0, $scope.error = !0 | |
}) : dateRangeId ? gaFunnelController.getFunnelWithData($state.params.gameId, funnelId, dateRangeId).then(function(funnel) { | |
dateRangeId = parseInt(dateRangeId, 10), funnel.dateRanges && funnel.dateRanges.length && funnel.dateRanges.forEach(function(dr) { | |
dr.id === dateRangeId && ($scope.activeDateRange = dr) | |
}), $scope.activeFunnel = funnel, _processStatus(), funnel.query ? ($scope.chart.settings = gaUtilsChartTransform.canvasChartSettings(funnel.query, "funnel", !0), $scope.switchTableDimension(0), $scope.error = !1, $timeout(function() { | |
angular.element(".axis.x-axis span b").each(function(index, element) { | |
element.offsetWidth < element.scrollWidth && angular.element(element).addClass("pre-text-overflow") | |
}) | |
}, 100), $scope.isDemo || $timeout(function() { | |
gaServicesUser.onboarding.funnels && gaServicesUser.onboarding.funnels.view_tour || (gaServicesUser.onboarding.set("funnels", "view_tour", !0), gaServicesUser.onboarding.save(), runTour()) | |
}, 10)) : ($scope.error = !0, $scope.activeFunnel.status && "processed" === $scope.activeFunnel.status.id && !$scope.activeFunnel.status.hasData && ($scope.noData = !0)), $scope.loading = !1 | |
}).catch(function(errFunnel) { | |
errFunnel && ($scope.activeFunnel = errFunnel), $scope.loading = !1, $scope.error = !0 | |
}) : gaFunnelController.getFunnel($state.params.gameId, funnelId).then(function(funnel) { | |
var rangeId = null; | |
return funnel.dateRanges && funnel.dateRanges.some(function(dr) { | |
return dr.status && "processed" === dr.status.id ? (rangeId = dr.id, !0) : void 0 | |
}), rangeId ? void $state.go("game.funnel.view", { | |
funnelId: funnelId, | |
dateRangeId: rangeId, | |
gameId: $state.params.gameId | |
}) : !1 | |
}).catch(function(errFunnel) { | |
errFunnel && ($scope.activeFunnel = errFunnel), $scope.loading = !1, $scope.error = !0 | |
}) | |
}, | |
_init = function() { | |
$state.params.funnelId && _loadFunnel($state.params.funnelId, $state.params.dateRangeId) | |
}, | |
_processStatus = function() { | |
var errors = [], | |
processing = [], | |
processed = []; | |
$scope.activeFunnel.dateRanges ? ($scope.activeFunnel.dateRanges.forEach(function(dr) { | |
dr.status && "failed" === dr.status.id && errors.push(dr.dateRangeFormatted), dr.status && "processing" === dr.status.id && processing.push(dr.dateRangeFormatted), dr.status && "processed" === dr.status.id && processed.push(dr.dateRangeFormatted) | |
}), $scope.processStates.errors = errors.join(", "), $scope.processStates.processing = processing.join(", "), $scope.processStates.processed = processed.join(", ")) : ($scope.processStates.errors = null, $scope.processStates.processing = null, $scope.processStates.processed = null) | |
}, | |
_reloadTable = function() { | |
$scope.table.datasets = gaUtilsGridTransform.parse($scope.activeFunnel.query.left), $scope.table.dataChanged = { | |
dataChange: !0 | |
} | |
}, | |
_sanitizeCsvStr = function(string) { | |
return string.replace(/\*/g, "all").replace(/[^a-z0-9]/gi, "_").replace(/_{2,}/g, "_").toLowerCase() | |
}, | |
_getCsvDataForFilter = function(filterIndex, byDimension) { | |
byDimension = byDimension || !1; | |
var dataQuery = angular.copy($scope.activeFunnel.query.left); | |
dataQuery.activeDimensionIndex = filterIndex; | |
var totals = !1; | |
byDimension ? (dataQuery.group = "metric-dimension", totals = !0) : dataQuery.group = "metric"; | |
var dataset = gaUtilsGridTransform.parse(dataQuery), | |
csv = _getCsvData(dataset, totals); | |
return csv | |
}, | |
_getCsvData = function(dataset, totals) { | |
var csv = [], | |
header = [dataset.header.axis.value]; | |
if (angular.forEach(dataset.header.values, function(value) { | |
header.push(value.value) | |
}), csv.push(header), angular.forEach(dataset.rows, function(row) { | |
var tmpRow = []; | |
tmpRow.push("date" === dataset.meta.axis.type ? $filter("formatUnitType")(row.axis.value, "rawdate") : row.axis.fullValue ? row.axis.fullValue.replace(/,/g, "") : row.axis.value), angular.forEach(row.values, function(value) { | |
tmpRow.push(value.value) | |
}), csv.push(tmpRow) | |
}), totals) { | |
var footer = [dataset.footer.axis.value]; | |
angular.forEach(dataset.footer.values, function(value) { | |
footer.push(value.value) | |
}), csv.push(footer) | |
} | |
return csv = csv.map(function(row) { | |
return row.join(";") | |
}), csv = csv.join("\n") | |
}; | |
_init(), $scope.switchTableGrouping = function(newView) { | |
newView !== $scope.settings.tableGrouping && ($scope.settings.tableGrouping = newView, "dimension" === $scope.settings.tableGrouping ? ($scope.activeFunnel.query.left.group = "metric-dimension", $scope.table.settings.totals = !0) : ($scope.activeFunnel.query.left.group = "metric", $scope.table.settings.totals = !1), _reloadTable()) | |
}, $scope.switchTableDimension = function(dimensionIndex) { | |
$scope.settings.activeDimension = dimensionIndex, $scope.activeFunnel.query.left.activeDimensionIndex = dimensionIndex, _reloadTable() | |
}, $scope.showFunnelList = function() { | |
$state.go("game.funnel.list", { | |
gameId: $state.params.gameId | |
}) | |
}, $scope.selectDateRange = function(dateRange) { | |
dateRange.status && "processed" === dateRange.status.id && $state.go("game.funnel.view", { | |
funnelId: $state.params.funnelId, | |
dateRangeId: dateRange.id, | |
gameId: $state.params.gameId | |
}) | |
}, $scope.createFunnel = function() { | |
$scope.isDemo || gaFunnelController.createFunnelDialog().then(function(funnel) { | |
gaFunnelController.setNotification("Funnel created!"), $state.go("game.funnel.edit", { | |
funnelId: funnel.id, | |
gameId: $state.params.gameId | |
}) | |
}) | |
}, $scope.editErrorFunnel = function() { | |
$scope.isDemo || gaFunnelController.editFunnel($state.params.funnelId) | |
}, $scope.editFunnel = function() { | |
$scope.isDemo || gaFunnelController.editPromptDialog($scope.activeFunnel) | |
}, $scope.duplicate = function() { | |
$scope.isDemo || gaFunnelController.duplicateFunnelDialog($scope.activeFunnel).then(function(funnel) { | |
funnel && funnel.id && (gaFunnelController.setNotification("Funnel duplicated!"), $state.go("game.funnel.edit", { | |
funnelId: funnel.id, | |
gameId: $state.params.gameId | |
})) | |
}) | |
}, $scope.rename = function() { | |
$scope.isDemo || gaFunnelController.renameFunnelDialog($scope.activeFunnel).then(function(funnel) { | |
$scope.activeFunnel.name = funnel.name, gaUiNotify.show("Funnel renamed", 4e3, "default") | |
}) | |
}, $scope.delete = function() { | |
$scope.isDemo || gaFunnelController.deleteFunnelDialog($scope.activeFunnel).then(function() { | |
gaFunnelController.setNotification("Funnel deleted!"), $scope.showFunnelList() | |
}).catch(function(error) { | |
error && "closed" === error.action || gaUiNotify.show("Error deleting funnel", 4e3, "warning") | |
}) | |
}, $scope.export = function() { | |
if (!$scope.loading && !$scope.isDemo) { | |
var data_json = {}, | |
name = "funnel_" + $scope.activeFunnel.name + "_" + $scope.activeDateRange.dateRangeFormatted; | |
$scope.activeFunnel.filters && $scope.activeFunnel.filters.length ? $scope.activeFunnel.filters.forEach(function(filter, index) { | |
data_json[_sanitizeCsvStr(filter.meta.title) + "_by_step.csv"] = _getCsvDataForFilter(index), data_json[_sanitizeCsvStr(filter.meta.title) + "_by_dimension.csv"] = _getCsvDataForFilter(index, !0) | |
}) : data_json[_sanitizeCsvStr(name) + ".csv"] = _getCsvData($scope.table.datasets), name = _sanitizeCsvStr(name) + ".zip"; | |
var csv_data_json = JSON.stringify(data_json), | |
form = angular.element("#funnel-export-csv-form"); | |
form.find("[name=X-Authorization]").val(gaServicesUser.token), form.find("[name=zip_name]").val(name), form.find("[name=csv_data_json]").val(csv_data_json), form.submit(), gaUtilsTracking.trackPageRaw("/game/export/funnel") | |
} | |
}, $scope.editDateRanges = function() { | |
$scope.isDemo || gaFunnelController.dateRangesDialog($scope.activeFunnel, !0).then(function(result) { | |
var funnel = result.funnel; | |
if (funnel) | |
if (funnel.dateRanges && funnel.dateRanges.length > 0) { | |
var found = !1; | |
if (funnel.dateRanges.some(function(dr) { | |
return dr.id === parseInt($state.params.dateRangeId, 10) ? (found = !0, !0) : void 0 | |
}), $scope.activeFunnel.dateRanges = funnel.dateRanges, _processStatus(), found) "empty" === result.status && result.dateRange && result.dateRange.id !== parseInt($state.params.dateRangeId, 10) && (gaFunnelController.setNotification("Your funnel was processed!"), $state.go("game.funnel.view", { | |
funnelId: $state.params.funnelId, | |
gameId: $state.params.gameId, | |
dateRangeId: result.dateRange.id | |
})); | |
else { | |
var newDateRange = null; | |
if (funnel.dateRanges.some(function(dr) { | |
if (dr.status && "processed" === dr.status.id) { | |
if (dr.status.hasData) return newDateRange = dr, !0; | |
newDateRange || (newDateRange = dr) | |
} | |
}), newDateRange) $state.go("game.funnel.view", { | |
funnelId: $state.params.funnelId, | |
gameId: $state.params.gameId, | |
dateRangeId: newDateRange.id | |
}); | |
else { | |
var processing = funnel.dateRanges.filter(function(dr) { | |
return dr.status && "processing" === dr.status.id | |
}).length; | |
processing === funnel.dateRanges.length && $scope.showFunnelList(); | |
var failed = funnel.dateRanges.filter(function(dr) { | |
return dr.status && "failed" === dr.status.id | |
}).length; | |
failed === funnel.dateRanges.length && $scope.editErrorFunnel() | |
} | |
} | |
} else $scope.editErrorFunnel() | |
}) | |
}, $scope.editFailedDateRanges = function() { | |
$scope.isDemo || gaFunnelController.dateRangesDialog($scope.activeFunnel, !0, !0).then(function(result) { | |
result.funnel && ($scope.activeFunnel.dateRanges = result.funnel.dateRanges, _processStatus()) | |
}) | |
}, $scope.toggleFilters = function() { | |
$scope.showFilters = !$scope.showFilters | |
}; | |
var runTour = function() { | |
gaUiTour.reset(), gaUiTour.addStep({ | |
title: "Add new date ranges", | |
text: "You can add new date ranges to your funnel and manage existing ones.", | |
element: ".popdown.ga-icon-calendar", | |
watcher: {}, | |
arrow: "top-left", | |
anchor: "bottom-center", | |
position: "fixed", | |
zindex: 1200, | |
skippable: !0 | |
}), gaUiTour.addStep({ | |
title: "Conversion", | |
text: "This is a summary of the players that converted through all steps of your funnel.", | |
element: ".overview-container", | |
watcher: {}, | |
arrow: "top-center", | |
anchor: "top-center", | |
zindex: 1200, | |
skippable: !0 | |
}), gaUiTour.addStep({ | |
title: "Want to make changes?", | |
text: "You can at any time make changes to the steps or filters, however be aware that existing date ranges will need to be re-processed.", | |
element: ".ga-btn.blue.small", | |
watcher: {}, | |
arrow: "top-right", | |
anchor: "bottom-right-center", | |
zindex: 1200, | |
position: "fixed", | |
skippable: !0 | |
}), gaUiTour.setOptions({ | |
navigation: !1 | |
}), gaUiTour.start() | |
}, | |
noti = gaFunnelController.getNotification(); | |
noti && gaUiNotify.show(noti.message, 4e3, noti.type) | |
}), angular.module("ga.pages.game.funnel.edit", ["ga.api.meta", "ga.pages.game.funnel.controller", "ga.pages.game.funnel.dialogs.process", "ga.pages.game.funnel.view", "ga.ui.modal", "ga.ui.sortable", "ga.ui.notify", "ga.ui.tour", "ga.services.dialogs", "ga.components.moment", "ga.services.user"]).controller("gaPagesFunnelEditController", function($scope, $rootScope, $state, $q, $filter, $timeout, moment, gaServicesUser, gaUiNotify, gaUiTour, gaUiModal, gaApiMeta, gaDialogs, gaFunnelController) { | |
$scope.loading = !1, $scope.creation = !1, $scope.activeFunnel = null; | |
var _processingRequest = !1; | |
$scope.uiValues = { | |
filterBlacklist: [], | |
addLastMetricStr: "" | |
}; | |
var ignoreSaveState = !1, | |
orgFunnel = null; | |
$scope.addMetric = function() { | |
var blacklisted = $scope.activeFunnel.metrics.map(function(m) { | |
return m.category + ":" + m.event | |
}); | |
gaDialogs.metricPicker(null, null, { | |
categories: ["design", "business"], | |
disableStarEvents: !0, | |
blacklisted: blacklisted | |
}).then(function(metric) { | |
metric && (metric.formatted = gaFunnelController.getMetricFormatted(metric.event, metric.category), metric.shortName = metric.formatted.name, metric.added = !0, $scope.activeFunnel.metrics.push(metric), _checkMetricStatus(), $timeout(function() { | |
angular.element(".steps").scrollLeft(1e7) | |
}, 1)) | |
}).catch(function() {}) | |
}, $scope.editMetric = function(index) { | |
var currentMetric = $scope.activeFunnel.metrics[index], | |
blacklisted = $scope.activeFunnel.metrics.filter(function(m, mindex) { | |
return mindex !== index | |
}).map(function(m) { | |
return m.category + ":" + m.event | |
}); | |
gaDialogs.metricPicker(currentMetric.event, currentMetric.category, { | |
categories: ["design", "business"], | |
disableStarEvents: !0, | |
blacklisted: blacklisted | |
}).then(function(metric) { | |
metric && (metric.formatted = gaFunnelController.getMetricFormatted(metric.event, metric.category), metric.shortName = metric.formatted.name, $scope.activeFunnel.metrics[index] = metric) | |
}).catch(function() {}) | |
}, $scope.removeMetric = function(index) { | |
$scope.activeFunnel.metrics.forEach(function(m) { | |
void 0 !== m.added && delete m.added | |
}), $timeout(function() { | |
$scope.activeFunnel.metrics.splice(index, 1), _checkMetricStatus() | |
}, 1) | |
}, $scope.removeFilter = function(filter) { | |
var foundIndex = _getFilterIndex(filter); | |
foundIndex > -1 && ($scope.activeFunnel.filters.splice(foundIndex, 1), _updateFilterBlacklist(), _setUiValues()) | |
}, $scope.removeExclude = function(exclude) { | |
var foundIndex = _getExcludeIndex(exclude); | |
foundIndex > -1 && ($scope.activeFunnel.excludes.splice(foundIndex, 1), _updateFilterBlacklist(), _setUiValues()) | |
}, $scope.removeFilterValue = function(filter, valueIndex) { | |
var filterIndex = _getFilterIndex(filter); | |
$scope.activeFunnel.filters[filterIndex] && ($scope.activeFunnel.filters[filterIndex].values.splice(valueIndex, 1), $scope.activeFunnel.filters[filterIndex].formattedValues.splice(valueIndex, 1), $scope.activeFunnel.filters[filterIndex].values.length || $scope.activeFunnel.filters.splice(filterIndex, 1)), _updateFilterBlacklist(), _setUiValues() | |
}, $scope.removeExcludeValue = function(exclude, valueIndex) { | |
var excludeIndex = _getExcludeIndex(exclude); | |
$scope.activeFunnel.excludes[excludeIndex] && ($scope.activeFunnel.excludes[excludeIndex].values.splice(valueIndex, 1), $scope.activeFunnel.excludes[excludeIndex].formattedValues.splice(valueIndex, 1), $scope.activeFunnel.excludes[excludeIndex].values.length || $scope.activeFunnel.excludes.splice(excludeIndex, 1)), _updateFilterBlacklist(), _setUiValues() | |
}, $scope.createFunnel = function() { | |
gaFunnelController.createFunnelDialog().then(function(funnel) { | |
gaFunnelController.setNotification("Funnel created!"), $scope.editFunnel(funnel.id) | |
}) | |
}, $scope.editFunnel = function(funnelId) { | |
$state.go("game.funnel.edit", { | |
funnelId: funnelId, | |
gameId: $state.params.gameId | |
}) | |
}; | |
var _editFunnel = function(funnelId) { | |
$scope.loading = !0, 0 === funnelId && ($scope.creation = !0); | |
var prom = 0 === funnelId ? gaFunnelController.getCreatedFunnel() : gaFunnelController.getFunnel($state.params.gameId, funnelId); | |
$q.all(prom).then(function(funnel) { | |
funnel.status && "processed" === funnel.status.id ? $scope.showFunnelList() : (orgFunnel = angular.copy(funnel), $scope.activeFunnel = funnel, $scope.loading = !1, _updateFilterBlacklist(), _checkMetricStatus(), _setUiValues(), $timeout(function() { | |
gaServicesUser.onboarding.funnels && gaServicesUser.onboarding.funnels.edit_tour || (gaServicesUser.onboarding.set("funnels", "edit_tour", !0), gaServicesUser.onboarding.save(), runTour()) | |
}, 10)) | |
}).catch(function() { | |
$scope.showFunnelList() | |
}) | |
}, | |
_updateFilterBlacklist = function() { | |
var blacklist = []; | |
$scope.activeFunnel.filters && (blacklist = $scope.activeFunnel.filters.map(function(filter) { | |
return filter.dimension | |
})), $scope.uiValues.excludeBlacklist = blacklist; | |
var eblacklist = []; | |
$scope.activeFunnel.excludes && $scope.activeFunnel.excludes.some(function(filter) { | |
-1 === eblacklist.indexOf(filter.dimension) && eblacklist.push(filter.dimension) | |
}), $scope.uiValues.filterBlacklist = eblacklist | |
}, | |
_setUiValues = function() { | |
$scope.uiValues.filter = $scope.activeFunnel.filters ? $scope.activeFunnel.filters.map(function(filter) { | |
return { | |
dimension: filter.dimension, | |
values: filter.values | |
} | |
}) : [], $scope.uiValues.exclude = $scope.activeFunnel.excludes ? $scope.activeFunnel.excludes.map(function(filter) { | |
return { | |
dimension: filter.dimension, | |
values: filter.values | |
} | |
}) : [] | |
}; | |
$scope.saveFunnel = function() { | |
0 !== $scope.activeFunnel.metrics.length && _saveDialog().then(function(result) { | |
result && result.processed ? (ignoreSaveState = !0, result.status && "failed" === result.status ? (gaUiNotify.show("Error saving and processing funnel", 4e3, "warning"), orgFunnel = angular.copy(result.funnel), $scope.activeFunnel = result.funnel) : result.status && "empty" === result.status && result.dateRange ? (gaFunnelController.setNotification("Your funnel was processed!"), $state.go("game.funnel.view", { | |
funnelId: result.funnel.id, | |
dateRangeId: result.funnel.dateRange.id, | |
gameId: $state.params.gameId | |
})) : (gaFunnelController.setNotification("Your funnel is processing! We'll notify you by email when it's done."), $scope.showFunnelList(!0))) : result ? 0 === orgFunnel.id && 0 !== result.funnel.id ? (ignoreSaveState = !0, gaFunnelController.setNotification("Funnel saved!"), $state.go("game.funnel.edit", { | |
funnelId: result.funnel.id, | |
gameId: $state.params.gameId | |
})) : (orgFunnel = angular.copy(result.funnel), $scope.activeFunnel = result.funnel, gaUiNotify.show("Funnel saved!", 4e3, "default")) : gaUiNotify.show("Error saving funnel", 4e3, "warning") | |
}).catch(function(error) { | |
error && gaUiNotify.show("Error saving funnel", 4e3, "warning") | |
}) | |
}; | |
var _saveDialog = function() { | |
return gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/game/funnel/dialogs/process-funnel.html", | |
controller: "gaPagesFunnelProcessController", | |
width: 800, | |
parameters: { | |
funnel: $scope.activeFunnel | |
} | |
}) | |
}; | |
$scope.showFunnelList = function(reload) { | |
reload ? $state.go("game.funnel.list", { | |
gameId: $state.params.gameId | |
}) : $state.go("game.funnel.list", { | |
gameId: $state.params.gameId | |
}) | |
}, $scope.save = function(state) { | |
_processingRequest || (_processingRequest = !0, gaFunnelController.saveFunnel($scope.activeFunnel).then(function(funnel) { | |
$scope.creation ? (ignoreSaveState = !0, gaUiNotify.show("Funnel saved", 4e3, "default"), $state.go("game.funnel.edit", { | |
funnelId: funnel.id, | |
gameId: $state.params.gameId | |
})) : (orgFunnel = angular.copy(funnel), $scope.activeFunnel = funnel, gaUiNotify.show("Funnel saved", 4e3, "default"), state && $state.go(state.state, state.params)), _processingRequest = !1 | |
}).catch(function() { | |
gaUiNotify.show("Error saving funnel", 4e3, "warning") | |
})) | |
}, $scope.duplicate = function() { | |
_processingRequest || (_processingRequest = !0, gaFunnelController.duplicateFunnelDialog($scope.activeFunnel).then(function(funnel) { | |
funnel && funnel.id ? (gaFunnelController.setNotification("Funnel duplicated!"), $state.go("game.funnel.edit", { | |
funnelId: funnel.id, | |
gameId: $state.params.gameId | |
})) : _processingRequest = !1 | |
}).catch(function() { | |
_processingRequest = !1 | |
})) | |
}, $scope.rename = function() { | |
_processingRequest || (_processingRequest = !0, gaFunnelController.renameFunnelDialog($scope.activeFunnel).then(function(funnel) { | |
orgFunnel = angular.copy(funnel), $scope.activeFunnel = funnel, gaUiNotify.show("Funnel renamed", 4e3, "default"), _processingRequest = !1 | |
}).catch(function() { | |
_processingRequest = !1 | |
})) | |
}, $scope.delete = function() { | |
_processingRequest || gaFunnelController.deleteFunnelDialog($scope.activeFunnel).then(function() { | |
gaFunnelController.setNotification("Funnel deleted!"), $scope.showFunnelList() | |
}).catch(function(error) { | |
error && "closed" === error.action || gaUiNotify.show("Error deleting funnel", 4e3, "warning"), _processingRequest = !1 | |
}) | |
}, $scope.editDateRanges = function() { | |
_processingRequest || gaFunnelController.dateRangesDialog($scope.activeFunnel, !1).then(function(result) { | |
result.funnel && (orgFunnel = angular.copy(result.funnel), $scope.activeFunnel = result.funnel), _processingRequest = !1 | |
}) | |
}; | |
var _getFilterIndex = function(filter) { | |
var foundIndex = null; | |
return $scope.activeFunnel.filters.some(function(f, index) { | |
return f.dimension === filter.dimension ? (foundIndex = index, !0) : void 0 | |
}), foundIndex | |
}, | |
_getExcludeIndex = function(exclude) { | |
var foundIndex = null; | |
return $scope.activeFunnel.excludes.some(function(f, index) { | |
return f.dimension === exclude.dimension ? (foundIndex = index, !0) : void 0 | |
}), foundIndex | |
}, | |
_init = function() { | |
_editFunnel(parseInt($state.params.funnelId, 10)); | |
var noti = gaFunnelController.getNotification(); | |
noti && gaUiNotify.show(noti.message, 4e3, noti.type) | |
}, | |
_checkMetricStatus = function() { | |
$scope.uiValues.addLastMetricStr = 1 === $scope.activeFunnel.metrics.length ? "You need min. 2 steps to start processing the funnel" : "" | |
}; | |
$scope.$on("$stateChangeStart", function(event, toState, toParams) { | |
angular.equals(orgFunnel, $scope.activeFunnel) || ignoreSaveState || (event.preventDefault(), gaUiNotify.loading(!1), gaUiModal.show({ | |
scope: $scope, | |
width: 500, | |
header: "Unsaved changes", | |
content: "Do you want to save the changes you made or discard the changes and leave the page?", | |
buttons: [{ | |
title: "Save", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "save" | |
}, { | |
title: "Discard changes", | |
"class": "ga-btn-text right", | |
keyCode: 27, | |
action: "go" | |
}], | |
actions: { | |
go: function() { | |
ignoreSaveState = !0, $state.go(toState, toParams) | |
}, | |
save: function() { | |
ignoreSaveState = !0, $scope.save({ | |
state: toState, | |
params: toParams | |
}) | |
} | |
} | |
})) | |
}); | |
var runTour = function() { | |
gaUiTour.reset(), $scope.activeFunnel.metrics && 0 !== $scope.activeFunnel.metrics.length || gaUiTour.addStep({ | |
title: "Start building", | |
text: "Funnels can be built using only your custom design or business events. Please choose first event to start building.", | |
element: "#first-step-creation", | |
watcher: {}, | |
arrow: "right-top", | |
anchor: "left-center", | |
zindex: 1200, | |
skippable: !0, | |
doneFn: function() { | |
var deferred = $q.defer(); | |
return this.watcher = $scope.$watch("activeFunnel.metrics", function(newVal, oldVal) { | |
newVal !== oldVal && deferred.resolve() | |
}, !0), deferred.promise | |
}, | |
hideFn: function() { | |
var deferred = $q.defer(); | |
return angular.element(this.element).on("mousedown.tour", function() { | |
deferred.resolve() | |
}), deferred.promise | |
}, | |
destroyFn: function() { | |
angular.element(this.element).off("mousedown.tour"), this.watcher() | |
} | |
}), gaUiTour.addStep({ | |
title: "Create segments", | |
text: "You can choose to process your funnel based on players from certain dimensions by either including or excluding these values.", | |
element: ".popdown.ga-icon-filter ", | |
clickElement: ".popdown.ga-icon-filter > span", | |
watcher: {}, | |
arrow: "top-left", | |
anchor: "bottom-center", | |
position: "fixed", | |
zindex: 1200, | |
skippable: !0, | |
doneDefered: null, | |
doneFn: function() { | |
return this.doneDefered = $q.defer(), this.watcher = $scope.$watch("activeFunnel.filters", function(newVal, oldVal) { | |
newVal !== oldVal && this.doneDefered.resolve() | |
}.bind(this), !0), this.doneDefered.promise | |
}, | |
hideDoneFn: function() { | |
angular.element(this.clickElement).on("mousedown.tour", function() { | |
this.doneDefered.resolve() | |
}.bind(this)) | |
}, | |
hideFn: function() { | |
var deferred = $q.defer(); | |
return angular.element(this.clickElement).on("mousedown.tour", function() { | |
deferred.resolve(), angular.element(this.clickElement).off("mousedown.tour"), this.hideDoneFn() | |
}.bind(this)), deferred.promise | |
}, | |
destroyFn: function() { | |
angular.element(this.clickElement).off("mousedown.tour"), this.watcher() | |
} | |
}), gaUiTour.addStep({ | |
title: "Processing", | |
text: "To get results from your funnel, you need to select a date range to process from. As soon as it's done , we'll notify you by email.", | |
element: "#start-processing", | |
watcher: {}, | |
arrow: "top-right", | |
anchor: "bottom-right-center", | |
zindex: 1200, | |
position: "fixed", | |
skippable: !0, | |
hideFn: function() { | |
var deferred = $q.defer(); | |
return angular.element(this.element).on("mousedown.tour", function() { | |
deferred.resolve() | |
}), deferred.promise | |
}, | |
destroyFn: function() { | |
angular.element(this.element).off("mousedown.tour") | |
} | |
}), gaUiTour.setOptions({ | |
navigation: !1 | |
}), gaUiTour.start() | |
}, | |
game = gaServicesUser.game(parseInt($state.params.gameId, 10)); | |
game.demo ? $scope.showFunnelList() : _init(), $scope.$watch("uiValues.filter", function(newVal) { | |
newVal && newVal.length && ($scope.activeFunnel.filters = [], angular.forEach(newVal, function(filter) { | |
var tmpFilter = angular.copy(filter); | |
tmpFilter.meta = gaApiMeta.getDimension(filter.dimension) || { | |
type: "" | |
}, tmpFilter.formattedValues = tmpFilter.values.map(function(value) { | |
return "*" === value ? "All" : $filter("formatUnitType")(gaApiMeta.getDimension(value).title, tmpFilter.meta.type) | |
}), $scope.activeFunnel.filters.push(tmpFilter) | |
}), _updateFilterBlacklist()) | |
}), $scope.$watch("uiValues.exclude", function(newVal) { | |
newVal && newVal.length && ($scope.activeFunnel.excludes = [], angular.forEach(newVal, function(filter) { | |
var tmpFilter = angular.copy(filter); | |
tmpFilter.meta = gaApiMeta.getDimension(filter.dimension) || { | |
type: "" | |
}, tmpFilter.formattedValues = tmpFilter.values.map(function(value) { | |
return "*" === value ? "All" : $filter("formatUnitType")(gaApiMeta.getDimension(value).title, tmpFilter.meta.type) | |
}), $scope.activeFunnel.excludes.push(tmpFilter) | |
}), _updateFilterBlacklist()) | |
}) | |
}), angular.module("ga.pages.game.funnel.dialogs.process", ["ga.pages.game.funnel.controller", "ga.ui.notify", "ga.ui.datepicker", "ga.utils.date"]).controller("gaPagesFunnelProcessController", function($scope, $state, $timeout, gaUtilsDate, gaFunnelController, gaUiNotify) { | |
$scope.tmpFunnel = angular.copy($scope.funnel), $scope.saving = !1; | |
var _restrictDate = { | |
start: 13963104e5, | |
end: 1e3 * gaUtilsDate.moment.utc().add(-48, "hours").unix() | |
}; | |
$scope.uiValues = { | |
dateRange: { | |
main: {}, | |
restrictInterval: _restrictDate | |
}, | |
dateRanges: angular.copy($scope.tmpFunnel.dateRanges), | |
filters: [], | |
excludes: [], | |
metrics: [], | |
metricsStr: [], | |
processAllowed: !1 | |
}, $scope.uiValues.metrics = $scope.tmpFunnel.metrics.map(function(metric) { | |
return $scope.uiValues.metricsStr.push(metric.shortName), { | |
shortName: metric.shortName, | |
cleanPath: metric.formatted ? metric.formatted.cleanPath : "" | |
} | |
}), $scope.uiValues.metricStr = $scope.uiValues.metricsStr.join(" > "), $scope.tmpFunnel.filters && ($scope.uiValues.filters = $scope.tmpFunnel.filters.map(function(filter) { | |
return { | |
name: filter.meta.parent ? filter.meta.parent.title + " > " + filter.meta.title : filter.meta.title, | |
strValue: filter.formattedValues.splice(0, 6).join(", "), | |
strValueAll: filter.formattedValues.join(", "), | |
count: filter.values.length - 6 | |
} | |
})), $scope.tmpFunnel.excludes && ($scope.uiValues.excludes = $scope.tmpFunnel.excludes.map(function(filter) { | |
return { | |
name: filter.meta.parent ? filter.meta.parent.title + " > " + filter.meta.title : filter.meta.title, | |
strValue: filter.formattedValues.splice(0, 6).join(", "), | |
strValueAll: filter.formattedValues.join(", "), | |
count: filter.values.length - 6 | |
} | |
})), $scope.creation = 0 === $scope.tmpFunnel.id, $scope.saveBtnTitle = "Save funnel", $scope.saveAndQueueBtnTitle = "Start processing"; | |
var _addRange = function() { | |
if ($scope.uiValues.dateRange.main && $scope.uiValues.dateRange.main.start && $scope.uiValues.dateRange.main.end) { | |
var tmpRanges = []; | |
$scope.uiValues.dateRanges && $scope.uiValues.dateRanges.length && $scope.uiValues.dateRanges.forEach(function(dr) { | |
tmpRanges.push(dr) | |
}); | |
var tmpRange = gaFunnelController.getNewDateRange($scope.uiValues.dateRange.main, tmpRanges); | |
tmpRange && 0 === tmpRange.id && $scope.uiValues.dateRanges.unshift(tmpRange), $scope.uiValues.dateRange = { | |
main: {}, | |
restrictInterval: _restrictDate | |
} | |
} | |
_checkProcessingState() | |
}; | |
$scope.removeRange = function(index) { | |
$scope.uiValues.dateRanges[index] && $scope.uiValues.dateRanges[index].id > 0 ? $scope.uiValues.dateRanges[index].delete = !0 : $scope.uiValues.dateRanges.splice(index, 1), _checkProcessingState() | |
}, $scope.save = function(queueIt) { | |
if (!$scope.saving) { | |
$scope.saving = !0; | |
var saveTmpFunnel = angular.copy($scope.tmpFunnel); | |
saveTmpFunnel.dateRanges = [], $scope.uiValues.dateRanges && $scope.uiValues.dateRanges.forEach(function(dr) { | |
saveTmpFunnel.dateRanges.push(dr) | |
}), $timeout(function() { | |
_doSave(saveTmpFunnel, queueIt) | |
}, 1) | |
} | |
}; | |
var _doSave = function(saveTmpFunnel, queueIt) { | |
return $scope.readOnly ? void 0 : queueIt ? gaFunnelController.saveAndProcessFunnel(saveTmpFunnel).then(function(results) { | |
$scope._resolve({ | |
funnel: results.funnel, | |
processed: !0, | |
status: results.status, | |
dateRange: results.dateRange | |
}) | |
}).catch(function(error) { | |
error ? (gaUiNotify.show("Error saving and processing funnel", 4e3, "warning"), $scope.saving = !1) : $scope._reject() | |
}) : gaFunnelController.saveFunnel(saveTmpFunnel).then(function(results) { | |
$scope._resolve({ | |
funnel: results, | |
processed: !1 | |
}) | |
}).catch(function(error) { | |
error ? (gaUiNotify.show("Error saving funnel", 4e3, "warning"), $scope.saving = !1) : $scope._reject() | |
}) | |
}, | |
_checkProcessingState = function() { | |
$scope.uiValues.processAllowed = !1, $scope.uiValues.dateRanges && $scope.uiValues.dateRanges.length && $scope.uiValues.dateRanges.some(function(dr) { | |
return dr.delete ? void 0 : void($scope.uiValues.processAllowed = !0) | |
}) | |
}; | |
_checkProcessingState(), $scope.$watch("uiValues.dateRange", function(newVal, oldVal) { | |
newVal && newVal !== oldVal && !angular.equals({}, newVal) && newVal.main && newVal.main.start && _addRange() | |
}) | |
}), angular.module("ga.pages.game.funnel.dialogs.list-date-ranges", ["ga.ui.datepicker", "ga.services.user", "ga.utils.date", "ga.pages.game.funnel.controller"]).controller("gaPagesFunnelListDateRangesController", function($scope, $state, $timeout, gaServicesUser, gaUtilsDate, gaFunnelController) { | |
var _tmpFunnel = angular.copy($scope.funnel); | |
$scope.saving = !1, $scope.tmpDateRanges = [], _tmpFunnel.dateRanges && _tmpFunnel.dateRanges.length && ($scope.tmpDateRanges = $scope.failedOnly ? _tmpFunnel.dateRanges.filter(function(dr) { | |
return dr.status && "failed" === dr.status.id | |
}).map(function(dr) { | |
return dr.delete = !1, dr | |
}) : _tmpFunnel.dateRanges.map(function(dr) { | |
return dr.delete = !1, dr | |
})); | |
var _restrictDate = { | |
start: 13963104e5, | |
end: 1e3 * gaUtilsDate.moment.utc().add(-48, "hours").unix() | |
}; | |
$scope.uiValues = { | |
dateRange: { | |
main: {}, | |
restrictInterval: _restrictDate | |
}, | |
dateRanges: [], | |
changes: !1 | |
}, $scope.saveBtnTitle = "Save funnel", $scope.saveAndQueueBtnTitle = "Save changes"; | |
var _addRange = function() { | |
if ($scope.tmpDateRanges && $scope.uiValues.dateRange.main && $scope.uiValues.dateRange.main.start && $scope.uiValues.dateRange.main.end) { | |
var tmpRange = gaFunnelController.getNewDateRange($scope.uiValues.dateRange.main, $scope.tmpDateRanges); | |
tmpRange && $scope.tmpDateRanges.unshift(tmpRange), $scope.uiValues.dateRange = { | |
main: {}, | |
restrictInterval: _restrictDate | |
}, _checkState() | |
} | |
}, | |
_checkState = function() { | |
var added = $scope.tmpDateRanges.filter(function(f) { | |
return 0 === f.id || f.status && "notQueued" === f.status.id | |
}).length, | |
deleted = $scope.tmpDateRanges.filter(function(f) { | |
return f.delete | |
}).length, | |
failed = $scope.tmpDateRanges.filter(function(f) { | |
return !f.delete && f.status && "failed" === f.status.id | |
}).length; | |
$scope.process && !$scope.failedOnly ? added && deleted ? ($scope.uiValues.changes = !0, $scope.saveAndQueueBtnTitle = "Start processing") : added || failed ? ($scope.uiValues.changes = !0, $scope.saveAndQueueBtnTitle = "Start processing") : deleted ? ($scope.uiValues.changes = !0, $scope.saveAndQueueBtnTitle = "Save changes") : ($scope.saveAndQueueBtnTitle = "Save changes", $scope.uiValues.changes = !1) : $scope.failedOnly ? deleted === $scope.tmpDateRanges.length ? ($scope.uiValues.changes = !0, $scope.saveAndQueueBtnTitle = "Save changes") : ($scope.uiValues.changes = !0, $scope.saveAndQueueBtnTitle = "Start processing") : added || deleted ? ($scope.uiValues.changes = !0, $scope.saveAndQueueBtnTitle = "Save changes") : ($scope.uiValues.changes = !1, $scope.saveAndQueueBtnTitle = "Save changes") | |
}; | |
$scope.removeRange = function(index) { | |
0 === $scope.tmpDateRanges[index].id ? $scope.tmpDateRanges.splice(index, 1) : $scope.tmpDateRanges[index].delete = !0, _checkState() | |
}, $scope.save = function() { | |
$scope.saving || ($scope.saving = !0, $timeout(function() { | |
_doSave() | |
}, 1)) | |
}; | |
var _doSave = function() { | |
_tmpFunnel.dateRanges = $scope.tmpDateRanges.filter(function(dr) { | |
return dr.delete || 0 === dr.id || $scope.process && dr.status && "failed" === dr.status.id | |
}).map(function(dr) { | |
return { | |
id: dr.id, | |
"delete": dr.delete, | |
backendId: "", | |
start: dr.start, | |
end: dr.end | |
} | |
}), gaFunnelController.saveFunnel(_tmpFunnel, !1).then(function(savedFunnel) { | |
$scope.process && savedFunnel.dateRanges && savedFunnel.dateRanges.length > 0 ? gaFunnelController.reProcessFunnel(savedFunnel).then(function(processResults) { | |
$scope._resolve(processResults) | |
}) : $scope._resolve({ | |
funnel: savedFunnel, | |
status: "not_processed" | |
}) | |
}).catch(function() { | |
$scope._reject() | |
}) | |
}; | |
$scope.$watch("uiValues.dateRange", function(newVal, oldVal) { | |
newVal && newVal !== oldVal && !angular.equals({}, newVal) && _addRange() | |
}), _checkState() | |
}), angular.module("ga.pages.game.funnel.dialogs.edit-prompt", ["ga.pages.game.funnel.controller"]).controller("gaPagesFunnelEditPromptController", function($scope) { | |
$scope.edit = function() { | |
$scope._resolve({ | |
action: "edit" | |
}) | |
}, $scope.duplicate = function() { | |
$scope._resolve({ | |
action: "duplicate" | |
}) | |
} | |
}), angular.module("ga.pages.heatmap", ["ga.api.data", "ga.ui.tour", "ga.ui.popdown", "ga.ui.select", "ga.utils.mailman", "ga.ui.unityplayer", "ga.api.userDb.authenticated.heatmap", "ga.ui.tooltip", "ga.ui.modal", "ga.components.rollbar", "ga.visualizations.histogram", "ga.ui.slider"]).filter("getByUid", function() { | |
return function(input, id) { | |
for (var i = 0, len = input.length; len > i; i++) | |
if (input[i].uid === id) return input[i]; | |
return null | |
} | |
}).filter("getIndexByUid", function() { | |
return function(input, id) { | |
for (var i = 0, len = input.length; len > i; i++) | |
if (input[i].uid === id) return i; | |
return null | |
} | |
}).filter("getById", function() { | |
return function(input, id) { | |
for (var i = 0, len = input.length; len > i; i++) | |
if (input[i].id === id) return input[i]; | |
return null | |
} | |
}).controller("gaPagesHeatmapNodataController", function() {}).controller("gaPagesHeatmapFirstTimeController", function($scope, $state) { | |
$scope.gotoHeatmap = function() { | |
$state.go("game.heatmap", { | |
gameId: $state.params.gameId | |
}) | |
} | |
}).controller("gaPagesHeatmapController", function(resolveHeatmap, $rootScope, $scope, $filter, $q, $timeout, gaApiData, gaUtilsMailman, moment, gaUiTour, gaApiUserDbAuthenticatedHeatmap, gaUiModal, gaComponentsRollbar) { | |
$scope.state = "loading", $scope.settings = null, $scope.selectOptions = {}, $scope.selectOptions.colors = [{ | |
start: "F6C300", | |
end: "DC0000", | |
name: '<span class="pokemon"></span>Red/Yellow', | |
id: "1", | |
classname: "redyellow" | |
}, { | |
start: "68B4FF", | |
end: "0F4A85", | |
name: '<span class="pokemon bluenavy"></span>Blue/Navy', | |
id: "2", | |
classname: "bluenavy" | |
}, { | |
start: "00B122", | |
end: "FD9927", | |
name: '<span class="pokemon greenorange"></span>Green/Orange', | |
id: "3", | |
classname: "greenorange" | |
}, { | |
start: "43B8A2", | |
end: "AA49C0", | |
name: '<span class="pokemon tealpurple"></span>Teal/Purple', | |
id: "4", | |
classname: "tealpurple" | |
}, { | |
start: "ABAC3E", | |
end: "A83A47", | |
name: '<span class="pokemon yellowbrown"></span>Yellow/Brown', | |
id: "5", | |
classname: "yellowbrown" | |
}], $scope.selectOptions.renders = [{ | |
name: "Transparent", | |
id: "0" | |
}, { | |
name: "Transparent overlay", | |
id: "1" | |
}], $scope.selectOptions.eventTypes = [{ | |
value: "add", | |
name: "ADD" | |
}, { | |
value: "sub", | |
name: "SUB" | |
}], $scope.areas = [], $scope.meshes = [], $scope.loadPlayer = !1, $scope.showPlayer = !1, $scope.selectedValues = { | |
set: null | |
}, $scope.currentHeatmap = {}, $scope.showSettings = !1, $scope.addingHeatmap = !1; | |
var runTour = !1, | |
firstRun = !1; | |
$scope.initializing = !0; | |
var loadSettings = function() { | |
void 0 !== resolveHeatmap && void 0 !== resolveHeatmap.sets && resolveHeatmap.sets.length > 0 ? parseSettings(resolveHeatmap) : (runTour = !0, parseSettings(resolveHeatmap, !0)) | |
}, | |
parseSettings = function(rsettings, emptySettings) { | |
emptySettings ? ($scope.settings = { | |
sets: [{ | |
id: 0, | |
name: "Untitled heatmap set", | |
selectedHeatmap: 0, | |
area: null, | |
mesh: null, | |
heatmaps: [] | |
}], | |
selectedSet: 0 | |
}, $scope.settings.gameId = rsettings.gameId, $scope.settings.keys = rsettings.keys, $scope.selectedValues.set = $scope.settings.sets[0], firstRun = !0, $scope.loadPlayer = !0) : ($scope.settings = rsettings, $scope.settings.sets.length > 0 && (angular.forEach($scope.settings.sets, function(obj, key) { | |
if (obj.heatmaps.length > 0) { | |
var cFound, rFound; | |
angular.forEach(obj.heatmaps, function(heatmap) { | |
cFound = $filter("getById")($scope.selectOptions.colors, heatmap.selectedColor.id || heatmap.selectedColor), heatmap.selectedColor = cFound || $scope.selectOptions.colors[0], rFound = $filter("getById")($scope.selectOptions.renders, heatmap.selectedRender.id || heatmap.selectedRender), heatmap.selectedRender = rFound || $scope.selectOptions.renders[0], heatmap.selectedEvents && angular.forEach(heatmap.selectedEvents, function(event) { | |
event.type = event && event.type && "sub" === event.type ? $scope.selectOptions.eventTypes[1] : $scope.selectOptions.eventTypes[0] | |
}) | |
}) | |
} | |
key === $scope.settings.selectedSet && ($scope.selectedValues.set = obj) | |
}), $scope.loadPlayer = !0, $scope.showPlayer = !0, $scope.showSettings = !0), switchTab($scope.selectedValues.set.selectedHeatmap, !0)) | |
}, | |
saveSettings = function(saveRemote) { | |
if ($scope.settings) { | |
var cleanedSettings = angular.copy($scope.settings); | |
cleanedSettings.gameId && delete cleanedSettings.gameId, cleanedSettings.keys && delete cleanedSettings.keys, angular.forEach(cleanedSettings.sets, function(obj) { | |
void 0 !== obj.changed && delete obj.changed, void 0 !== obj.className && delete obj.className, void 0 === obj.mesh && (obj.mesh = null), angular.forEach(obj.heatmaps, function(heatmap) { | |
void 0 !== heatmap.builds && delete heatmap.builds, void 0 !== heatmap.events && delete heatmap.events, void 0 !== heatmap.histogramData && delete heatmap.histogramData, void 0 !== heatmap.className && delete heatmap.className, void 0 !== heatmap.tooltip && delete heatmap.tooltip, heatmap.selectedColor && heatmap.selectedColor.id && (heatmap.selectedColor = heatmap.selectedColor.id), heatmap.selectedRender && heatmap.selectedRender.id && (heatmap.selectedRender = heatmap.selectedRender.id), heatmap.dateRange && void 0 !== heatmap.dateRange.compare && delete heatmap.dateRange.compare, heatmap.dateRange && heatmap.dateRange.cal1 && (heatmap.dateRange.main = heatmap.dateRange.cal1, delete heatmap.dateRange.cal1), heatmap.dateRange && heatmap.dateRange.cal2 && delete heatmap.dateRange.cal2, heatmap.selectedEvents && angular.forEach(heatmap.selectedEvents, function(evt) { | |
evt.fullName && delete evt.fullName, evt.category || (evt.category = ""), evt.type = evt.type && evt.type.value && "sub" === evt.type.value ? "sub" : "add" | |
}) | |
}) | |
}), saveRemote && putSettings(cleanedSettings) | |
} | |
}, | |
putSettings = function(csettings) { | |
gaApiUserDbAuthenticatedHeatmap.putSettings($scope.settings.gameId, csettings).then(function() {}, function() { | |
gaComponentsRollbar.putCustom({ | |
level: "critical", | |
msg: "Could not save heatmap settings.", | |
point: { | |
error: "Unknown server error", | |
data: JSON.stringify(csettings) | |
} | |
}) | |
}) | |
}, | |
toggleSettings = function() { | |
$scope.showSettings ? ($scope.showSettings = !1, $scope.currentHeatmap.settingsExpanded = !1) : $scope.currentHeatmap.selectedEvents.length > 0 && "" !== $scope.currentHeatmap.selectedEvents[0].name && ($scope.showSettings = !0, $scope.currentHeatmap.settingsExpanded = !0) | |
}, | |
addEvent = function() { | |
$scope.currentHeatmap.selectedEvents[$scope.currentHeatmap.selectedEvents.length - 1].name && $scope.currentHeatmap.selectedEvents.push({ | |
name: null, | |
category: null, | |
type: $scope.selectOptions.eventTypes[0] | |
}) | |
}, | |
deleteEvent = function(id) { | |
$scope.currentHeatmap.selectedEvents[id] && $scope.currentHeatmap.selectedEvents.splice(id, 1) | |
}, | |
updateHeatmap = function(newData) { | |
var redrawOptions = {}; | |
if (newData) { | |
var builds; | |
builds = null === $scope.currentHeatmap.selectedBuild ? "" : $scope.currentHeatmap.selectedBuild, redrawOptions = { | |
uid: $scope.currentHeatmap.uid, | |
events: [], | |
build: builds | |
}; | |
for (var index in $scope.currentHeatmap.selectedEvents) void 0 !== $scope.currentHeatmap.selectedEvents[index].type && "" !== $scope.currentHeatmap.selectedEvents[index].type && void 0 !== $scope.currentHeatmap.selectedEvents[index].name && "" !== $scope.currentHeatmap.selectedEvents[index].name && redrawOptions.events.push({ | |
name: $scope.currentHeatmap.selectedEvents[index].name, | |
type: $scope.currentHeatmap.selectedEvents[index].type.value | |
}); | |
var dateRange = timestampToTs($scope.currentHeatmap.dateRange); | |
null !== dateRange && (redrawOptions.dateRange = dateRange), gaUtilsMailman.publish("global:unity:UpdateHeatmapData", redrawOptions), updateMetaData() | |
} else redrawOptions = { | |
uid: $scope.currentHeatmap.uid, | |
radius: $scope.currentHeatmap.radius, | |
rangeMin: $scope.currentHeatmap.range.min, | |
rangeMax: $scope.currentHeatmap.range.max, | |
renderModel: $scope.currentHeatmap.selectedRender.id, | |
showHeatmap: $scope.currentHeatmap.visible, | |
colour: $scope.currentHeatmap.selectedColor, | |
showValues: $scope.currentHeatmap.showValues ? 1 : 0 | |
}, gaUtilsMailman.publish("global:unity:UpdateHeatmapView", redrawOptions) | |
}, | |
resetHeatmaps = function() { | |
if (void 0 !== $scope.selectedValues.set && void 0 !== $scope.selectedValues.set.heatmaps && $scope.selectedValues.set.heatmaps.length > 0) | |
for (var i = 0, ln = $scope.selectedValues.set.heatmaps.length; ln > i; i++) gaUtilsMailman.publish("global:unity:DeleteHeatmap", $scope.selectedValues.set.heatmaps[i].uid); | |
$scope.addingHeatmap = !1 | |
}, | |
loadSetup = function() { | |
var area = $scope.selectedValues.set.area; | |
area && $scope.areas && $scope.areas.length && -1 === $scope.areas.indexOf(area) && (area = $scope.areas[0], $scope.updateSilentArea = !0, $scope.selectedValues.set.area = area); | |
var hm, events, dateRange, tmpObj, build, tooltip, options = { | |
mesh: $scope.selectedValues.set.mesh || null, | |
area: area || null, | |
heatmaps: [] | |
}; | |
options.mesh && ($scope.meshLoading = !0, $scope.meshLoadProgress = 0); | |
for (var index in $scope.selectedValues.set.heatmaps) { | |
hm = $scope.selectedValues.set.heatmaps[index], events = [], tooltip = ""; | |
for (var eIndex in hm.selectedEvents) null !== hm.selectedEvents[eIndex].name && events.push({ | |
name: hm.selectedEvents[eIndex].name, | |
type: hm.selectedEvents[eIndex].type.value | |
}); | |
build = null === hm.selectedBuild ? "" : hm.selectedBuild, tmpObj = { | |
uid: hm.uid, | |
events: events, | |
build: build, | |
radius: hm.radius, | |
rangeMin: hm.range.min, | |
rangeMax: hm.range.max, | |
renderModel: hm.selectedRender.id, | |
showHeatmap: hm.visible, | |
colour: hm.selectedColor, | |
showValues: hm.showValues ? 1 : 0 | |
}, dateRange = timestampToTs(hm.dateRange), null !== dateRange && (tmpObj.dateRange = dateRange), options.heatmaps.push(tmpObj) | |
} | |
updateMetaData(), gaUtilsMailman.publish("global:unity:LoadSetup", options), runTour && setTimeout(function() { | |
runTour = !1, setupTour() | |
}, 100), $scope.state = "", $timeout(function() { | |
$scope.initializing = !1 | |
}) | |
}, | |
addHeatmapSet = function() { | |
$scope.settings.sets.push({ | |
id: $scope.settings.sets.length, | |
name: "Untitled heatmap set", | |
selectedHeatmap: 0, | |
area: null, | |
mesh: null, | |
heatmaps: [] | |
}), $scope.showSettings = !1, $scope.initializing = !0, resetHeatmaps(), $scope.selectedValues.set = $scope.settings.sets[$scope.settings.sets.length - 1], $scope.settings.selectedSet = $scope.settings.sets.length - 1, $scope.currentHeatmap = null, $scope.showPlayer = !1, $scope.firstRun = !0, setupSetTour(), saveSettings(!0), gaUtilsMailman.publish("global:unity:LoadSetup", {}), loadSetup() | |
}, | |
addHeatmap = function() { | |
if (!$scope.addingHeatmap) | |
if ($scope.selectedValues.set.heatmaps.length > 8) { | |
var buttons = [{ | |
title: "Ok", | |
"class": "ga-btn orange right", | |
action: "confirm", | |
keyCode: 27 | |
}], | |
$newScope = $rootScope.$new(); | |
gaUiModal.show({ | |
scope: $newScope, | |
iframe: !0, | |
header: "Max number of heatmaps", | |
content: "You are only allowed to add 10 heatmap pr. set", | |
width: 500, | |
actions: { | |
confirm: function() {} | |
}, | |
always: function() { | |
$newScope.$destroy() | |
}, | |
buttons: buttons | |
}) | |
} else $scope.addingHeatmap = !0, gaUtilsMailman.publish("global:unity:AddHeatmap") | |
}, | |
switchTab = function(id, ignoreSave) { | |
void 0 !== $scope.selectedValues.set.heatmaps[id] && ($scope.initializing = !0, $scope.selectedValues.set.selectedHeatmap = id, $scope.currentHeatmap = $scope.selectedValues.set.heatmaps[id], $scope.showSettings = 0 === $scope.currentHeatmap.selectedEvents.length || "" === $scope.currentHeatmap.selectedEvents[0].name ? !1 : $scope.currentHeatmap.settingsExpanded, ignoreSave || saveSettings(!0), $timeout(function() { | |
$scope.initializing = !1 | |
})) | |
}, | |
toggleHeatmap = function(id) { | |
void 0 !== $scope.selectedValues.set.heatmaps[id] && $scope.selectedValues.set.selectedHeatmap === id && ($scope.selectedValues.set.heatmaps[id].visible = $scope.selectedValues.set.heatmaps[id].visible ? 0 : 1, updateHeatmap(!1), saveSettings(!0)) | |
}, | |
deleteHeatmap = function(id) { | |
if (void 0 !== $scope.selectedValues.set.heatmaps[id] && $scope.selectedValues.set.heatmaps.length > 1) { | |
var uid = $scope.selectedValues.set.heatmaps[id].uid; | |
$scope.selectedValues.set.selectedHeatmap === id && (angular.element(".heatmap-content .tabs li:eq(" + id + ")").hide(), $scope.selectedValues.set.heatmaps.splice(id, 1), gaUtilsMailman.publish("global:unity:DeleteHeatmap", uid), $scope.selectedValues.set.selectedHeatmap = 0, $scope.switchTab($scope.selectedValues.set.selectedHeatmap), saveSettings(!0)) | |
} | |
}, | |
updateMetaData = function() { | |
angular.forEach($scope.selectedValues.set.heatmaps, function(obj) { | |
var events = obj.selectedEvents.map(function(d) { | |
return d.name ? d.name.split(":").join(" > ") : "" | |
}); | |
if (obj.tooltip = events.join("<br />"), "" === obj.tooltip) obj.tooltip = "No events selected"; | |
else if (void 0 !== obj.dateRange && obj.dateRange.main && null !== obj.dateRange.main.start && null !== obj.dateRange.main.end) { | |
var startDate = moment(obj.dateRange.main.start).format("D. MMM YYYY"), | |
endDate = moment(obj.dateRange.main.end).format("D. MMM YYYY"); | |
obj.tooltip += "<br />" + startDate + " - " + endDate | |
} | |
}) | |
}, | |
showHeatmapSettings = function(index) { | |
$scope.selectedValues.set.heatmaps[index] === $scope.currentHeatmap && showHeatmapSettingsModal(index).then(function(heatmap) { | |
heatmap && heatmap.name !== $scope.currentHeatmap.name && ($scope.currentHeatmap.name = heatmap.name, saveSettings(!0)) | |
}) | |
}, | |
showHeatmapSettingsModal = function(index) { | |
var deferred = $q.defer(), | |
$newScope = $rootScope.$new(); | |
$newScope.heatmap = angular.copy($scope.currentHeatmap); | |
var settingsTemplate = '<div class=ga-form heatmap-settings"><label for="name">Name</label><input class="ga-input widget-name-input" name="name" ng-model="heatmap.name" /></div>', | |
buttons = [{ | |
title: "Save", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "confirm", | |
disabled: "!heatmap.name" | |
}]; | |
return $scope.selectedValues.set.heatmaps.length > 1 && buttons.push({ | |
title: "Delete heatmap", | |
"class": "ga-btn-text light red ga-icon-trash vertical-none left", | |
action: "delete" | |
}), buttons.push({ | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
action: "cancel", | |
keyCode: 27 | |
}), gaUiModal.show({ | |
scope: $newScope, | |
header: "Heatmap settings", | |
content: settingsTemplate, | |
width: 500, | |
iframe: !0, | |
actions: { | |
"delete": function() { | |
confirmHeatmapDeletion(index).then(function() { | |
deferred.resolve(null) | |
}, function() { | |
deferred.reject() | |
}) | |
}, | |
cancel: function() { | |
deferred.reject($newScope.heatmap) | |
}, | |
confirm: function() { | |
deferred.resolve($newScope.heatmap) | |
} | |
}, | |
always: function() { | |
$newScope.$destroy() | |
}, | |
buttons: buttons | |
}), deferred.promise | |
}, | |
confirmHeatmapDeletion = function(index) { | |
var deferred = $q.defer(), | |
$newScope = $rootScope.$new(); | |
$newScope.name = $scope.currentHeatmap.name; | |
var doDelete = function() { | |
deleteHeatmap(index), deferred.resolve() | |
}; | |
return gaUiModal.show({ | |
scope: $newScope, | |
width: 500, | |
iframe: !0, | |
header: "Delete heatmap", | |
content: 'Are you sure you want to delete the heatmap <strong ng-bind="name"></strong>?', | |
buttons: [{ | |
title: "Delete", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "doDelete" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
doDelete: function() { | |
doDelete() | |
} | |
} | |
}, "confirmHeatmapDelete"), deferred.promise | |
}, | |
changeSet = function(id) { | |
void 0 !== $scope.settings.sets[id] && ($scope.initializing = !0, $scope.selectedValues.set = $scope.settings.sets[id], void 0 !== $scope.selectedValues.set.selectedHeatmap && null !== $scope.selectedValues.set.selectedHeatmap && $scope.selectedValues.set.heatmaps && $scope.selectedValues.set.heatmaps[$scope.selectedValues.set.selectedHeatmap] ? $scope.switchTab($scope.selectedValues.set.selectedHeatmap) : $scope.currentHeatmap = null, $scope.showSettings = !0, $scope.showPlayer = !0, $scope.settings.selectedSet = id, saveSettings(!0), resetHeatmaps(), gaUtilsMailman.publish("global:unity:LoadSetup", {}), loadSetup()) | |
}, | |
doDeleteSet = function(id) { | |
if (void 0 !== $scope.settings.sets[id] && $scope.settings.sets.length > 1) { | |
var delViewed = !1; | |
$scope.selectedValues.set.id === id && (delViewed = !0, resetHeatmaps($scope.settings.sets[id]), gaUtilsMailman.publish("global:unity:LoadSetup", {})), $scope.settings.sets.splice(id, 1), angular.forEach($scope.settings.sets, function(obj, key) { | |
obj.id = key | |
}), delViewed ? ($scope.selectedValues.set = $scope.settings.sets[0], $scope.settings.selectedSet = $scope.selectedValues.set.id) : $scope.settings.selectedSet = $scope.selectedValues.set.id, saveSettings(!0) | |
} | |
}, | |
showSetSettings = function(index) { | |
$scope.settings.sets[index] && showSetSettingsModal($scope.settings.sets[index]).then(function(set) { | |
set && set.name !== $scope.settings.sets[index].name && ($scope.settings.sets[index].name = set.name, saveSettings(!0)) | |
}) | |
}, | |
showSetSettingsModal = function(set) { | |
var deferred = $q.defer(), | |
$newScope = $rootScope.$new(); | |
$newScope.set = angular.copy(set); | |
var settingsTemplate = '<div class=ga-form heatmap-settings"><label for="name">Name</label><input class="ga-input widget-name-input" name="name" ng-model="set.name" /></div>', | |
buttons = [{ | |
title: "Save", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "confirm", | |
disabled: "!set.name" | |
}]; | |
return $scope.settings.sets.length > 1 && buttons.push({ | |
title: "Delete heatmap set", | |
"class": "ga-btn-text light red ga-icon-trash vertical-none left", | |
action: "delete" | |
}), buttons.push({ | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
action: "cancel", | |
keyCode: 27 | |
}), gaUiModal.show({ | |
scope: $newScope, | |
header: "Heatmap set settings", | |
iframe: !0, | |
content: settingsTemplate, | |
width: 500, | |
actions: { | |
"delete": function() { | |
confirmHeatmapSetDeletion($newScope.set).then(function() { | |
deferred.resolve(null) | |
}, function() { | |
deferred.reject() | |
}) | |
}, | |
cancel: function() { | |
deferred.reject($newScope.set) | |
}, | |
confirm: function() { | |
deferred.resolve($newScope.set) | |
} | |
}, | |
always: function() { | |
$newScope.$destroy() | |
}, | |
buttons: buttons | |
}), deferred.promise | |
}, | |
confirmHeatmapSetDeletion = function(set) { | |
var deferred = $q.defer(), | |
$newScope = $rootScope.$new(); | |
$newScope.name = set.name; | |
var doDelete = function() { | |
doDeleteSet(set.id), deferred.resolve() | |
}; | |
return gaUiModal.show({ | |
scope: $newScope, | |
iframe: !0, | |
width: 500, | |
header: "Delete heatmap set", | |
content: 'Are you sure you want to delete the heatmap set <strong ng-bind="name"></strong> and <strong>all</strong> heatmaps contained within?', | |
buttons: [{ | |
title: "Delete", | |
"class": "ga-btn-alt orange right", | |
keyCode: 13, | |
action: "doDelete" | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
keyCode: 27 | |
}], | |
actions: { | |
doDelete: function() { | |
doDelete($scope.set) | |
} | |
} | |
}, "confirmHeatmapDelete"), deferred.promise | |
}, | |
changeMetric = function(id, metric) { | |
$scope.currentHeatmap.selectedEvents[id] && ($scope.currentHeatmap.selectedEvents[id].name = metric.event, $scope.currentHeatmap.selectedEvents[id].category = metric.category) | |
}, | |
useMetricPicker = function(id) { | |
if ($scope.currentHeatmap.selectedEvents[id]) { | |
var $tmpScope = $rootScope.$new(!0); | |
$scope.currentHeatmap.selectedEvents[id].category && $scope.currentHeatmap.selectedEvents[id].name && ($tmpScope.tmpMetric = { | |
event: $scope.currentHeatmap.selectedEvents[id].name, | |
category: $scope.currentHeatmap.selectedEvents[id].category | |
}); | |
var tmpListener = $tmpScope.$watch("tmpMetric", function(newVal, oldVal) { | |
newVal !== oldVal && ($timeout(function() { | |
gaUiModal.hide("subModal") | |
}), $scope.initializing = !1, changeMetric(id, $tmpScope.tmpMetric)) | |
}); | |
$tmpScope.filter = { | |
disableStarEvents: !0, | |
customEventList: $scope.currentHeatmap.events | |
}, gaUiModal.show({ | |
header: "Select a metric", | |
scope: $tmpScope, | |
iframe: !0, | |
newScope: !1, | |
width: 720, | |
customClass: "secondary", | |
content: '<ga-ui-metricpicker metric="tmpMetric" filter="filter"></ga-ui-metricpicker>', | |
buttons: [{ | |
title: "Cancel", | |
"class": "ga-btn-alt", | |
keyCode: 27 | |
}], | |
always: function() { | |
tmpListener(), $tmpScope.$destroy() | |
} | |
}, "subModal") | |
} | |
}, | |
resetBuilds = function() { | |
$scope.currentHeatmap.selectedBuild = null | |
}, | |
timestampToTs = function(dateRange) { | |
var startDate, endDate, range; | |
return void 0 !== dateRange && dateRange.main && null !== dateRange.main.start && null !== dateRange.main.end ? (startDate = moment(dateRange.main.start).format("YYYY:MM:DD"), endDate = moment(dateRange.main.end).format("YYYY:MM:DD"), range = { | |
from: startDate, | |
to: endDate | |
}) : range = null, range | |
}; | |
gaUtilsMailman.subscribe("global:unity:update", function(e, data) { | |
$scope.$apply(function() { | |
angular.isArray(data.areas) && ($scope.areas = data.areas), angular.isArray(data.meshes) && ($scope.meshes = data.meshes), loadSetup() | |
}) | |
}, "heatmap"), gaUtilsMailman.subscribe("global:unity:addedHeatmap", function(e, data) { | |
$scope.$apply(function() { | |
$scope.addingHeatmap = !1; | |
var found = $filter("getByUid")($scope.selectedValues.set.heatmaps, data.uid); | |
if (null === found) { | |
var color = $scope.selectOptions.colors[$scope.selectedValues.set.heatmaps.length]; | |
void 0 === color && (color = $scope.selectOptions.colors[0]); | |
var render = $scope.selectOptions.renders[0]; | |
$scope.selectedValues.set.heatmaps.push({ | |
uid: data.uid, | |
name: "Heatmap", | |
radius: 10, | |
range: { | |
min: 0, | |
max: 100 | |
}, | |
visible: 1, | |
builds: data.builds, | |
selectedBuild: null, | |
events: data.events, | |
selectedEvents: [{ | |
type: $scope.selectOptions.eventTypes[0], | |
name: "", | |
category: "" | |
}], | |
selectedColor: color, | |
selectedRender: render, | |
settingsExpanded: !0, | |
dateRange: { | |
main: { | |
start: null, | |
end: null | |
} | |
} | |
}), $scope.switchTab($scope.selectedValues.set.heatmaps.length - 1), $scope.state = "" | |
} else found.builds = data.builds, found.events = data.events | |
}) | |
}, "heatmap"), gaUtilsMailman.subscribe("global:unity:updatedHistogramData", function(e, data) { | |
$scope.$apply(function() { | |
var foundIndex = $filter("getIndexByUid")($scope.selectedValues.set.heatmaps, data.uid); | |
null !== foundIndex && ($scope.selectedValues.set.heatmaps[foundIndex].histogramData = { | |
data: data.rows, | |
min: data.min, | |
max: data.max, | |
count: data.count | |
}) | |
}) | |
}, "heatmap"), gaUtilsMailman.subscribe("global:unity:Initialized", function() { | |
gaUtilsMailman.publish("global:unity:SetKeys", $scope.settings.keys) | |
}, "heatmap"), gaUtilsMailman.subscribe("global:unity:playerBroken", function() { | |
var buttons = [{ | |
title: "Ok", | |
"class": "ga-btn blue right", | |
action: "confirm", | |
keyCode: 27 | |
}], | |
$newScope = $rootScope.$new(); | |
gaUiModal.show({ | |
scope: $newScope, | |
iframe: !0, | |
header: "Unity Web Player", | |
content: 'Your Unity Web Player seems broken. Try and reinstall it by clicking <a href="http://webplayer.unity3d.com/download_webplayer_beta/webplayer-i386.dmg">here</a> ', | |
width: 500, | |
actions: { | |
confirm: function() {} | |
}, | |
always: function() { | |
$newScope.$destroy() | |
}, | |
buttons: buttons | |
}) | |
}, "heatmap"), gaUtilsMailman.subscribe("global:unity:playerMissing", function() { | |
var buttons = [{ | |
title: "Install", | |
"class": "ga-btn orange right", | |
action: "confirm", | |
keyCode: 13 | |
}, { | |
title: "Cancel", | |
"class": "ga-btn-text right", | |
action: "cancel", | |
keyCode: 27 | |
}], | |
$newScope = $rootScope.$new(); | |
gaUiModal.show({ | |
scope: $newScope, | |
iframe: !0, | |
header: "Unity Web Player", | |
content: "You are missing the Unity Web Player. You need it in order to use the Heatmap feature.", | |
width: 500, | |
actions: { | |
confirm: function() { | |
window.open("http://unity3d.com/webplayer", "_blank") | |
}, | |
cancel: function() {} | |
}, | |
always: function() { | |
$newScope.$destroy() | |
}, | |
buttons: buttons | |
}) | |
}, "heatmap"), gaUtilsMailman.subscribe("global:unity:meshLoaded", function() { | |
$scope.$apply(function() { | |
$scope.meshLoading = !1, $scope.meshLoadProgress = 0 | |
}) | |
}, "heatmap"), gaUtilsMailman.subscribe("global:unity:meshLoadProgress", function(e, data) { | |
$scope.$apply(function() { | |
$scope.meshLoadProgress = Math.round(100 * data.progress) | |
}) | |
}, "heatmap"), $scope.$watch("selectedValues.set.area", function(newVal, oldVal) { | |
return $scope.updateSilentArea ? void($scope.updateSilentArea = !1) : void(oldVal !== newVal && newVal && !$scope.initializing && (saveSettings(!0), oldVal ? ($scope.currentHeatmap.histogramData = {}, $scope.currentHeatmap.range = { | |
min: 0, | |
max: 100 | |
}, changeSet($scope.selectedValues.set.id)) : (loadSetup(), addHeatmap(), $scope.state = "loading"))) | |
}), $scope.$watch("selectedValues.set.mesh", function(newVal, oldVal) { | |
oldVal !== newVal && newVal && !$scope.initializing && (gaUtilsMailman.publish("global:unity:UpdateMesh", $scope.selectedValues.set.mesh), saveSettings(!0), $scope.meshLoading = !0, $scope.meshLoadProgress = 0) | |
}), $scope.$watch("currentHeatmap.selectedEvents", function(newEvents, oldEvents) { | |
if (newEvents !== oldEvents && newEvents && newEvents.length && "" !== newEvents[0].name && !$scope.initializing) { | |
if (newEvents.length > oldEvents.length && !newEvents[newEvents.length - 1].name) return; | |
$scope.showPlayer || ($scope.showPlayer = !0), $scope.showSettings = !0, $scope.currentHeatmap.settingsExpanded = !0, $scope.currentHeatmap.histogramData = {}, $scope.currentHeatmap.range = { | |
min: 0, | |
max: 100 | |
}, updateHeatmap(!0), saveSettings(!0) | |
} else(newEvents !== oldEvents && newEvents && (0 === newEvents.length || "" === newEvents[0].name) || !newEvents) && ($scope.showSettings = !1, saveSettings(!0)) | |
}, !0), $scope.$watch("currentHeatmap.selectedBuild", function(newBuild, oldBuild) { | |
newBuild !== oldBuild && (newBuild || !newBuild && oldBuild) && !$scope.initializing && (updateHeatmap(!0), saveSettings(!0)) | |
}, !0), $scope.$watch("currentHeatmap.selectedRender", function(newRender, oldRender) { | |
newRender !== oldRender && newRender && !$scope.initializing && (updateHeatmap(!0), saveSettings(!0)) | |
}, !0), $scope.$watch("currentHeatmap.selectedColor", function(newColor, oldColor) { | |
newColor !== oldColor && newColor && !$scope.initializing && (updateHeatmap(!1), saveSettings(!0)) | |
}, !0), $scope.$watch("currentHeatmap.radius", function(newRadius, oldRadius) { | |
newRadius !== oldRadius && newRadius && !$scope.initializing && (updateHeatmap(!1), saveSettings(!1)) | |
}, !0), $scope.$watch("currentHeatmap.range", function(newRange, oldRange) { | |
newRange !== oldRange && newRange && !$scope.initializing && (updateHeatmap(!1), saveSettings(!1)) | |
}, !0), $scope.$watch("currentHeatmap.dateRange", function(newRange, oldRange) { | |
newRange !== oldRange && newRange && !$scope.initializing && (updateHeatmap(!0), saveSettings(!0)) | |
}, !0); | |
var setupTour = window.setupTour = function() { | |
gaUiTour.addStep({ | |
title: "Choose area", | |
text: "Choose from which area of your game you want to load data from and show in your heatmap", | |
element: ".areaselect", | |
watcher: {}, | |
arrow: "top-left", | |
anchor: "bottom-left-center", | |
position: "fixed", | |
skippable: !1, | |
doneFn: function() { | |
var deferred = $q.defer(); | |
return this.watcher = $scope.$watch("selectedValues.set.area", function(newVal, oldVal) { | |
newVal !== oldVal && deferred.resolve() | |
}, !0), deferred.promise | |
}, | |
hideFn: function() { | |
var deferred = $q.defer(); | |
return angular.element(this.element).on("mousedown.tour", "button", function() { | |
deferred.resolve() | |
}), deferred.promise | |
}, | |
destroyFn: function() { | |
angular.element(this.element).off("mousedown.tour"), this.watcher() | |
} | |
}), gaUiTour.addStep({ | |
title: "Upload Mesh", | |
text: 'To use a game mesh, you need to upload your mesh through our Unity SDK plug-in. Choose "Export Mesh AssetBundle" in the GameAnalytics menu.', | |
btnText: "OK, I’m ready", | |
element: ".meshselect", | |
arrow: "top-left", | |
anchor: "bottom-left-center", | |
position: "fixed", | |
skippable: !0, | |
watcher: function() {}, | |
doneFn: function() { | |
var deferred = $q.defer(); | |
return this.watcher = $scope.$watch("selectedValues.set.mesh", function(newVal, oldVal) { | |
newVal !== oldVal && deferred.resolve() | |
}, !0), deferred.promise | |
}, | |
hideFn: function() { | |
var deferred = $q.defer(); | |
return angular.element(this.element).on("mousedown.tour", "button", function() { | |
deferred.resolve() | |
}), deferred.promise | |
}, | |
destroyFn: function() { | |
angular.element(this.element).off("mousedown.tour"), this.watcher() | |
} | |
}), gaUiTour.addStep({ | |
title: "Choose event", | |
text: "Use the event picker to choose the event you want to see visualized in your heatmap.", | |
element: ".eventselect:first", | |
arrow: "top-left", | |
anchor: "bottom-left-center", | |
skippable: !0, | |
watcher: function() {}, | |
showWatcher: function() {}, | |
showFn: function() { | |
var deferred = $q.defer(); | |
return this.showWatcher = $scope.$watch("selectedValues.set.heatmaps", function(newVal) { | |
newVal.length > 0 && (angular.element(".eventselect").length > 0 ? deferred.resolve() : $timeout(function() { | |
angular.element(".eventselect").length > 0 && deferred.resolve() | |
}, 1e3)) | |
}, !0), deferred.promise | |
}, | |
hideFn: function() { | |
var deferred = $q.defer(); | |
return angular.element(this.element).on("mousedown.tour", "button", function() { | |
deferred.resolve() | |
}), deferred.promise | |
}, | |
doneFn: function() { | |
var deferred = $q.defer(); | |
return this.watcher = $scope.$watch("selectedValues.set.heatmaps", function(newVal) { | |
"" !== newVal[0].selectedEvents[0].name && deferred.resolve() | |
}, !0), deferred.promise | |
}, | |
destroyFn: function() { | |
angular.element(this.element).off("mousedown.tour"), this.watcher(), this.showWatcher() | |
} | |
}), gaUiTour.addStep({ | |
title: "Thats it!", | |
text: 'You’re now certified to begin heatmapping your data. If you have any further questions, you can find us in <a href="/Support">Support</a>.', | |
element: ".ga.bar.page.sub", | |
arrow: "hidden", | |
anchor: "top-center", | |
center: !0, | |
skippable: !0, | |
position: "fixed", | |
hideFn: function() { | |
var deferred = $q.defer(); | |
return angular.element(this.element).on("mousedown.tour", "button", function() { | |
deferred.resolve() | |
}), deferred.promise | |
}, | |
destroyFn: function() { | |
angular.element(this.element).off("mousedown.tour") | |
} | |
}), gaUiTour.start() | |
}, | |
closeSelects = function(event) { | |
$rootScope.$broadcast("closeOtherSelects", "all"), event.stopPropagation() | |
}; | |
$scope.$on("$destroy", function() { | |
gaUtilsMailman.unsubscribeAll("heatmap") | |
}), $scope.toggleHeatmap = toggleHeatmap, $scope.changeSet = changeSet, $scope.switchTab = switchTab, $scope.addHeatmap = addHeatmap, $scope.showHeatmapSettings = showHeatmapSettings, $scope.addHeatmapSet = addHeatmapSet, $scope.addEvent = addEvent, $scope.deleteEvent = deleteEvent, $scope.toggleSettings = toggleSettings, $scope.showSetSettings = showSetSettings, $scope.useMetricPicker = useMetricPicker, $scope.resetBuilds = resetBuilds, $scope.closeSelects = closeSelects, $timeout(function() { | |
loadSettings() | |
}) | |
}), angular.module("ga.pages.game.initialize", ["ui.router", "ga.api.meta", "ga.api.data", "ga.services.game", "ga.ui.progress", "ga.utils.date", "ga.utils.tracking", "ga.utils.cookie"]).controller("gaPagesGameInitializeController", function(resolveGameStatus, $scope, $timeout, $state, gaServicesGame, gaApiData, gaUtilsDate, gaUtilsTracking, gaUtilsCookie) { | |
var UID = Math.random().toString().replace(".", ""); | |
$scope.gameId = parseInt($state.params.gameId, 10), gaUtilsCookie.set("ga-game-guide-" + $scope.gameId, 1, 7), $scope.update = { | |
timer: null, | |
interval: 30, | |
update: 0 | |
}; | |
var _updateStatus = function(status) { | |
$scope.gameStatus = status, $scope.gameStatus.data ? ($scope.step = 5, gaUtilsTracking.trackEvent({ | |
category: "home", | |
action: "game", | |
label: "hasdata" | |
})) : $scope.step = $scope.gameStatus.initialized ? 4 : 4, $scope.update.update++, $scope.update.timer = $timeout(updateStatus, 1e3 * $scope.update.interval), updateRejectedEvents() | |
}, | |
updateStatus = function() { | |
$timeout.cancel($scope.update.timer), gaServicesGame.getStatus($scope.gameId, !0).then(_updateStatus) | |
}, | |
updateRejectedEvents = function() { | |
var options = { | |
realtime: !0, | |
levels: ["info"], | |
filter: "Event rejected: ", | |
interval: gaUtilsDate.getPeriodRange("last24hours") | |
}; | |
gaApiData.getQuality(options, UID).then(function(rejectedEvents) { | |
$scope.rejectedEvents = rejectedEvents.map(function(event) { | |
return event.name = event.name.replace("Event rejected: ", ""), event | |
}).sort(function(a, b) { | |
return a.eventCount === b.eventCount ? 0 : a.eventCount > b.eventCount ? -1 : 1 | |
}) | |
}).catch(function() { | |
$scope.rejectedEvents = [] | |
}) | |
}; | |
_updateStatus(resolveGameStatus), $scope.$on("$destroy", function() { | |
gaApiData.removeUID(UID), $timeout.cancel($scope.update.timer) | |
}) | |
}), angular.module("ga.pages.general.tabbed", ["ui.router"]).controller("gaPagesGeneralTabbedController", function($scope, $state) { | |
$scope.tabs = $state.$current.data.tabs || [], $scope.tabActive = null; | |
var setActiveTab = function() { | |
$scope.tabs.some(function(tab, index) { | |
return $state.current.name === tab.state ? ($scope.tabActive = index, !0) : void 0 | |
}) | |
}; | |
$scope.$on("$stateChangeSuccess", function() { | |
$state.current.name.split(".").length < 3 && selectTab(0, !0), setActiveTab() | |
}); | |
var selectTab = function(index, ignoreReplace) { | |
var loc = ignoreReplace ? { | |
location: "replace" | |
} : {}; | |
$state.go($scope.tabs[index].state, null, loc) | |
}; | |
$scope.selectTab = selectTab, setActiveTab() | |
}), angular.module("ga.pages.user.subscriptions", ["ui.router", "ga.config", "ga.api.userDb.authenticated.user", "ga.api.userDb.public.unsubscribe", "ga.ui.modal", "ga.ui.notify", "ga.ui.errors"]).controller("gaPagesUserSubscriptionsController", function(resolveSubscriptions, $timeout, $scope, $state, gaConfig, gaApiUserDbAuthenticatedUser, gaApiUserDbPublicUnsubscribe, gaUiModal, gaUiNotify) { | |
$scope.errors = [], $scope.noneSelected = !0; | |
var isPublic = $state.includes("public"), | |
updateSubscriptions = function() { | |
isPublic ? gaApiUserDbPublicUnsubscribe.getSubscriptions($state.params.email, $state.params.token).then(_updateSubscriptions).catch(function(errors) { | |
_updateSubscriptions({ | |
errors: errors | |
}) | |
}) : gaApiUserDbAuthenticatedUser.subscriptions().then(_updateSubscriptions).catch(function(errors) { | |
_updateSubscriptions({ | |
errors: errors | |
}) | |
}) | |
}, | |
_updateSubscriptions = function(results) { | |
return results.errors ? ($scope.subscriptions = [], void($scope.errors = results.errors)) : (results.forEach(function(studio) { | |
studio.games.forEach(function(game) { | |
game.imagePath = game.imageFile ? gaConfig.images.baseUrl + game.imageFile : "/static/ga-app/images/default-game-icon.png", game.subscriptions = { | |
daily: !1, | |
weekly: !1, | |
monthly: !1 | |
} | |
}) | |
}), void($scope.subscriptions = results)) | |
}; | |
_updateSubscriptions(resolveSubscriptions); | |
var selectAll = function() { | |
$scope.subscriptions.forEach(function(studio) { | |
studio.games.forEach(function(game) { | |
game.subscriptions.daily = game.daily ? !0 : !1, game.subscriptions.weekly = game.weekly ? !0 : !1, game.subscriptions.monthly = game.monthly ? !0 : !1 | |
}) | |
}), $scope.noneSelected = !1 | |
}, | |
change = function() { | |
$timeout(function() { | |
$scope.noneSelected = !$scope.subscriptions.some(function(studio) { | |
return studio.games.some(function(game) { | |
var tmp = null; | |
return game.subscriptions.daily && (tmp = tmp || { | |
id: game.id | |
}) && (tmp.daily = !1), game.subscriptions.weekly && (tmp = tmp || { | |
id: game.id | |
}) && (tmp.weekly = !1), game.subscriptions.monthly && (tmp = tmp || { | |
id: game.id | |
}) && (tmp.monthly = !1), tmp ? !0 : void 0 | |
}) | |
}) | |
}) | |
}, | |
save = function() { | |
gaUiModal.confirm("Are you sure you want to unsubscribe from the selected email reports?", "Unsubscribe").then(function() { | |
var data = { | |
reports_unsubscribe: [] | |
}; | |
$scope.processing = !0, $scope.subscriptions.forEach(function(studio) { | |
studio.games.forEach(function(game) { | |
var tmp = null; | |
game.subscriptions.daily && (tmp = tmp || { | |
id: game.id | |
}) && (tmp.daily = !1), game.subscriptions.weekly && (tmp = tmp || { | |
id: game.id | |
}) && (tmp.weekly = !1), game.subscriptions.monthly && (tmp = tmp || { | |
id: game.id | |
}) && (tmp.monthly = !1), tmp && data.reports_unsubscribe.push(tmp) | |
}) | |
}), isPublic ? gaApiUserDbPublicUnsubscribe.unsubscribe($state.params.email, $state.params.token, data).then(function() { | |
gaUiNotify.show("Successfully unsubscribed", 4e3, "default"), updateSubscriptions() | |
}).finally(function() { | |
$scope.processing = !1 | |
}) : gaApiUserDbAuthenticatedUser.unsubscribe(data).then(function() { | |
gaUiNotify.show("Successfully unsubscribed", 4e3, "default"), updateSubscriptions() | |
}).finally(function() { | |
$scope.processing = !1 | |
}) | |
}) | |
}; | |
$scope.change = change, $scope.selectAll = selectAll, $scope.save = save | |
}), angular.module("ga.pages.user.profile", ["ui.router", "ga.services.user", "ga.api.userDb.authenticated.user", "ga.ui.modal", "ga.ui.notify"]).controller("gaPagesUserProfileController", function($scope, $stateParams, $state, $timeout, $window, gaServicesUser, gaApiUserDbAuthenticatedUser, gaUiModal, gaUiNotify) { | |
$scope.errors = [], $scope.validationErrors = { | |
firstName: null, | |
lastName: null | |
}, $stateParams.link_token && gaApiUserDbAuthenticatedUser.link({ | |
token: $stateParams.link_token | |
}).then(function() { | |
setLink($stateParams.source), gaUiNotify.show("Account is now linked to " + $scope.linkedName, 4e3, "default"), gaServicesUser.linked = $scope.linked, $state.go("user.settings.profile", {}, { | |
inherit: !1, | |
notify: !1 | |
}) | |
}).catch(function(errors) { | |
$scope.linkError = errors[0].msg, $state.go("user.settings.profile", {}, { | |
inherit: !1, | |
notify: !1 | |
}) | |
}); | |
var setLink = function(linked) { | |
switch ($scope.linked = linked, $scope.linked) { | |
case "google": | |
$scope.linkedName = "Google"; | |
break; | |
case "github": | |
$scope.linkedName = "GitHub" | |
} | |
}, | |
setUserData = function(reload) { | |
reload ? gaServicesUser.getUserData().then(function() { | |
$scope.user = gaServicesUser.details.serialize(), $scope.user.demoGameEnabled = gaServicesUser.demoGameEnabled, setLink(gaServicesUser.linked) | |
}) : ($scope.user = gaServicesUser.details.serialize(), $scope.user.demoGameEnabled = gaServicesUser.demoGameEnabled, setLink(gaServicesUser.linked)) | |
}; | |
setUserData(), $scope.save = function() { | |
return $scope.errors = [], $scope.processing = !0, $scope.validationErrors.firstName = $scope.user.hasOwnProperty("firstName") && !$scope.user.firstName ? "First name cannot be empty." : null, $scope.validationErrors.lastName = $scope.user.hasOwnProperty("lastName") && !$scope.user.lastName ? "Last name cannot be empty." : null, $scope.validationErrors.firstName || $scope.validationErrors.lastName ? void($scope.processing = !1) : void gaServicesUser.details.save($scope.user).then(function() { | |
gaUiNotify.show("User profile saved", 4e3, "default") | |
}).catch(function(errors) { | |
$scope.errors = errors | |
}).finally(function() { | |
$scope.processing = !1 | |
}) | |
}, $scope.link = function(linkType) { | |
$window.location.href = "/oauth2/" + linkType + "?action=link" | |
}, $scope.unlink = function() { | |
gaUiModal.confirm("Are you sure you want to unlink your account? You can still use your email and password to login.", "Unlink account").then(function() { | |
gaApiUserDbAuthenticatedUser.unlink().then(function() { | |
setLink(null), gaUiNotify.show("Account is now unlinked", 4e3, "default"), gaServicesUser.linked = null | |
}) | |
}) | |
}, $scope.changePassword = function() { | |
gaServicesUser.dialogPasswordChange() | |
}, $scope.countries = [{ | |
title: "Afghanistan", | |
value: "Afghanistan" | |
}, { | |
title: "Albania", | |
value: "Albania" | |
}, { | |
title: "Algeria", | |
value: "Algeria" | |
}, { | |
title: "Andorra", | |
value: "Andorra" | |
}, { | |
title: "Angola", | |
value: "Angola" | |
}, { | |
title: "Antarctica", | |
value: "Antarctica" | |
}, { | |
title: "Antigua and Barbuda", | |
value: "Antigua and Barbuda" | |
}, { | |
title: "Argentina", | |
value: "Argentina" | |
}, { | |
title: "Armenia", | |
value: "Armenia" | |
}, { | |
title: "Australia", | |
value: "Australia" | |
}, { | |
title: "Austria", | |
value: "Austria" | |
}, { | |
title: "Azerbaijan", | |
value: "Azerbaijan" | |
}, { | |
title: "Bahamas", | |
value: "Bahamas" | |
}, { | |
title: "Bahrain", | |
value: "Bahrain" | |
}, { | |
title: "Bangladesh", | |
value: "Bangladesh" | |
}, { | |
title: "Barbados", | |
value: "Barbados" | |
}, { | |
title: "Belarus", | |
value: "Belarus" | |
}, { | |
title: "Belgium", | |
value: "Belgium" | |
}, { | |
title: "Belize", | |
value: "Belize" | |
}, { | |
title: "Benin", | |
value: "Benin" | |
}, { | |
title: "Bermuda", | |
value: "Bermuda" | |
}, { | |
title: "Bhutan", | |
value: "Bhutan" | |
}, { | |
title: "Bolivia", | |
value: "Bolivia" | |
}, { | |
title: "Bosnia and Herzegovina", | |
value: "Bosnia and Herzegovina" | |
}, { | |
title: "Botswana", | |
value: "Botswana" | |
}, { | |
title: "Brazil", | |
value: "Brazil" | |
}, { | |
title: "Brunei", | |
value: "Brunei" | |
}, { | |
title: "Bulgaria", | |
value: "Bulgaria" | |
}, { | |
title: "Burkina Faso", | |
value: "Burkina Faso" | |
}, { | |
title: "Burma", | |
value: "Burma" | |
}, { | |
title: "Burundi", | |
value: "Burundi" | |
}, { | |
title: "Cambodia", | |
value: "Cambodia" | |
}, { | |
title: "Cameroon", | |
value: "Cameroon" | |
}, { | |
title: "Canada", | |
value: "Canada" | |
}, { | |
title: "Cape Verde", | |
value: "Cape Verde" | |
}, { | |
title: "Central African Republic", | |
value: "Central African Republic" | |
}, { | |
title: "Chad", | |
value: "Chad" | |
}, { | |
title: "Chile", | |
value: "Chile" | |
}, { | |
title: "China", | |
value: "China" | |
}, { | |
title: "Colombia", | |
value: "Colombia" | |
}, { | |
title: "Comoros", | |
value: "Comoros" | |
}, { | |
title: "Congo, Democratic Republic", | |
value: "Congo, Democratic Republic" | |
}, { | |
title: "Congo, Republic of the", | |
value: "Congo, Republic of the" | |
}, { | |
title: "Costa Rica", | |
value: "Costa Rica" | |
}, { | |
title: "Cote d'Ivoire", | |
value: "Cote d'Ivoire" | |
}, { | |
title: "Croatia", | |
value: "Croatia" | |
}, { | |
title: "Cuba", | |
value: "Cuba" | |
}, { | |
title: "Cyprus", | |
value: "Cyprus" | |
}, { | |
title: "Czech Republic", | |
value: "Czech Republic" | |
}, { | |
title: "Denmark", | |
value: "Denmark" | |
}, { | |
title: "Djibouti", | |
value: "Djibouti" | |
}, { | |
title: "Dominica", | |
value: "Dominica" | |
}, { | |
title: "Dominican Republic", | |
value: "Dominican Republic" | |
}, { | |
title: "East Timor", | |
value: "East Timor" | |
}, { | |
title: "Ecuador", | |
value: "Ecuador" | |
}, { | |
title: "Egypt", | |
value: "Egypt" | |
}, { | |
title: "El Salvador", | |
value: "El Salvador" | |
}, { | |
title: "Equatorial Guinea", | |
value: "Equatorial Guinea" | |
}, { | |
title: "Eritrea", | |
value: "Eritrea" | |
}, { | |
title: "Estonia", | |
value: "Estonia" | |
}, { | |
title: "Ethiopia", | |
value: "Ethiopia" | |
}, { | |
title: "Faroe Islands", | |
value: "Faroe Islands" | |
}, { | |
title: "Fiji", | |
value: "Fiji" | |
}, { | |
title: "Finland", | |
value: "Finland" | |
}, { | |
title: "France", | |
value: "France" | |
}, { | |
title: "Gabon", | |
value: "Gabon" | |
}, { | |
title: "Gambia", | |
value: "Gambia" | |
}, { | |
title: "Georgia", | |
value: "Georgia" | |
}, { | |
title: "Germany", | |
value: "Germany" | |
}, { | |
title: "Ghana", | |
value: "Ghana" | |
}, { | |
title: "Greece", | |
value: "Greece" | |
}, { | |
title: "Greenland", | |
value: "Greenland" | |
}, { | |
title: "Grenada", | |
value: "Grenada" | |
}, { | |
title: "Guatemala", | |
value: "Guatemala" | |
}, { | |
title: "Guinea", | |
value: "Guinea" | |
}, { | |
title: "Guinea-Bissau", | |
value: "Guinea-Bissau" | |
}, { | |
title: "Guyana", | |
value: "Guyana" | |
}, { | |
title: "Haiti", | |
value: "Haiti" | |
}, { | |
title: "Honduras", | |
value: "Honduras" | |
}, { | |
title: "Hong Kong", | |
value: "Hong Kong" | |
}, { | |
title: "Hungary", | |
value: "Hungary" | |
}, { | |
title: "Iceland", | |
value: "Iceland" | |
}, { | |
title: "India", | |
value: "India" | |
}, { | |
title: "Indonesia", | |
value: "Indonesia" | |
}, { | |
title: "Iran", | |
value: "Iran" | |
}, { | |
title: "Iraq", | |
value: "Iraq" | |
}, { | |
title: "Ireland", | |
value: "Ireland" | |
}, { | |
title: "Israel", | |
value: "Israel" | |
}, { | |
title: "Italy", | |
value: "Italy" | |
}, { | |
title: "Jamaica", | |
value: "Jamaica" | |
}, { | |
title: "Japan", | |
value: "Japan" | |
}, { | |
title: "Jordan", | |
value: "Jordan" | |
}, { | |
title: "Kazakhstan", | |
value: "Kazakhstan" | |
}, { | |
title: "Kenya", | |
value: "Kenya" | |
}, { | |
title: "Kiribati", | |
value: "Kiribati" | |
}, { | |
title: "Korea, North", | |
value: "Korea, North" | |
}, { | |
title: "Korea, South", | |
value: "Korea, South" | |
}, { | |
title: "Kuwait", | |
value: "Kuwait" | |
}, { | |
title: "Kyrgyzstan", | |
value: "Kyrgyzstan" | |
}, { | |
title: "Laos", | |
value: "Laos" | |
}, { | |
title: "Latvia", | |
value: "Latvia" | |
}, { | |
title: "Lebanon", | |
value: "Lebanon" | |
}, { | |
title: "Lesotho", | |
value: "Lesotho" | |
}, { | |
title: "Liberia", | |
value: "Liberia" | |
}, { | |
title: "Libya", | |
value: "Libya" | |
}, { | |
title: "Liechtenstein", | |
value: "Liechtenstein" | |
}, { | |
title: "Lithuania", | |
value: "Lithuania" | |
}, { | |
title: "Luxembourg", | |
value: "Luxembourg" | |
}, { | |
title: "Macedonia", | |
value: "Macedonia" | |
}, { | |
title: "Madagascar", | |
value: "Madagascar" | |
}, { | |
title: "Malawi", | |
value: "Malawi" | |
}, { | |
title: "Malaysia", | |
value: "Malaysia" | |
}, { | |
title: "Maldives", | |
value: "Maldives" | |
}, { | |
title: "Mali", | |
value: "Mali" | |
}, { | |
title: "Malta", | |
value: "Malta" | |
}, { | |
title: "Marshall Islands", | |
value: "Marshall Islands" | |
}, { | |
title: "Mauritania", | |
value: "Mauritania" | |
}, { | |
title: "Mauritius", | |
value: "Mauritius" | |
}, { | |
title: "Mexico", | |
value: "Mexico" | |
}, { | |
title: "Micronesia", | |
value: "Micronesia" | |
}, { | |
title: "Moldova", | |
value: "Moldova" | |
}, { | |
title: "Mongolia", | |
value: "Mongolia" | |
}, { | |
title: "Morocco", | |
value: "Morocco" | |
}, { | |
title: "Monaco", | |
value: "Monaco" | |
}, { | |
title: "Mozambique", | |
value: "Mozambique" | |
}, { | |
title: "Namibia", | |
value: "Namibia" | |
}, { | |
title: "Nauru", | |
value: "Nauru" | |
}, { | |
title: "Nepal", | |
value: "Nepal" | |
}, { | |
title: "Netherlands", | |
value: "Netherlands" | |
}, { | |
title: "New Zealand", | |
value: "New Zealand" | |
}, { | |
title: "Nicaragua", | |
value: "Nicaragua" | |
}, { | |
title: "Niger", | |
value: "Niger" | |
}, { | |
title: "Nigeria", | |
value: "Nigeria" | |
}, { | |
title: "Norway", | |
value: "Norway" | |
}, { | |
title: "Oman", | |
value: "Oman" | |
}, { | |
title: "Pakistan", | |
value: "Pakistan" | |
}, { | |
title: "Panama", | |
value: "Panama" | |
}, { | |
title: "Papua New Guinea", | |
value: "Papua New Guinea" | |
}, { | |
title: "Paraguay", | |
value: "Paraguay" | |
}, { | |
title: "Peru", | |
value: "Peru" | |
}, { | |
title: "Philippines", | |
value: "Philippines" | |
}, { | |
title: "Poland", | |
value: "Poland" | |
}, { | |
title: "Portugal", | |
value: "Portugal" | |
}, { | |
title: "Qatar", | |
value: "Qatar" | |
}, { | |
title: "Romania", | |
value: "Romania" | |
}, { | |
title: "Russia", | |
value: "Russia" | |
}, { | |
title: "Rwanda", | |
value: "Rwanda" | |
}, { | |
title: "Samoa", | |
value: "Samoa" | |
}, { | |
title: "San Marino", | |
value: "San Marino" | |
}, { | |
title: "Sao Tome", | |
value: "Sao Tome" | |
}, { | |
title: "Saudi Arabia", | |
value: "Saudi Arabia" | |
}, { | |
title: "Senegal", | |
value: "Senegal" | |
}, { | |
title: "Serbia and Montenegro", | |
value: "Serbia and Montenegro" | |
}, { | |
title: "Seychelles", | |
value: "Seychelles" | |
}, { | |
title: "Sierra Leone", | |
value: "Sierra Leone" | |
}, { | |
title: "Singapore", | |
value: "Singapore" | |
}, { | |
title: "Slovakia", | |
value: "Slovakia" | |
}, { | |
title: "Slovenia", | |
value: "Slovenia" | |
}, { | |
title: "Solomon Islands", | |
value: "Solomon Islands" | |
}, { | |
title: "Somalia", | |
value: "Somalia" | |
}, { | |
title: "South Africa", | |
value: "South Africa" | |
}, { | |
title: "Spain", | |
value: "Spain" | |
}, { | |
title: "Sri Lanka", | |
value: "Sri Lanka" | |
}, { | |
title: "Sudan", | |
value: "Sudan" | |
}, { | |
title: "Suriname", | |
value: "Suriname" | |
}, { | |
title: "Swaziland", | |
value: "Swaziland" | |
}, { | |
title: "Sweden", | |
value: "Sweden" | |
}, { | |
title: "Switzerland", | |
value: "Switzerland" | |
}, { | |
title: "Syria", | |
value: "Syria" | |
}, { | |
title: "Taiwan", | |
value: "Taiwan" | |
}, { | |
title: "Tajikistan", | |
value: "Tajikistan" | |
}, { | |
title: "Tanzania", | |
value: "Tanzania" | |
}, { | |
title: "Thailand", | |
value: "Thailand" | |
}, { | |
title: "Togo", | |
value: "Togo" | |
}, { | |
title: "Tonga", | |
value: "Tonga" | |
}, { | |
title: "Trinidad and Tobago", | |
value: "Trinidad and Tobago" | |
}, { | |
title: "Tunisia", | |
value: "Tunisia" | |
}, { | |
title: "Turkey", | |
value: "Turkey" | |
}, { | |
title: "Turkmenistan", | |
value: "Turkmenistan" | |
}, { | |
title: "Uganda", | |
value: "Uganda" | |
}, { | |
title: "Ukraine", | |
value: "Ukraine" | |
}, { | |
title: "United Arab Emirates", | |
value: "United Arab Emirates" | |
}, { | |
title: "United Kingdom", | |
value: "United Kingdom" | |
}, { | |
title: "United States", | |
value: "United States" | |
}, { | |
title: "Uruguay", | |
value: "Uruguay" | |
}, { | |
title: "Uzbekistan", | |
value: "Uzbekistan" | |
}, { | |
title: "Vanuatu", | |
value: "Vanuatu" | |
}, { | |
title: "Venezuela", | |
value: "Venezuela" | |
}, { | |
title: "Vietnam", | |
value: "Vietnam" | |
}, { | |
title: "Yemen", | |
value: "Yemen" | |
}, { | |
title: "Zambia", | |
value: "Zambia" | |
}, { | |
title: "Zimbabwe", | |
value: "Zimbabwe" | |
}] | |
}), angular.module("ga.pages.user.locale", ["ui.router", "pasvaz.bindonce", "ga.api.meta", "ga.services.user", "ga.utils.date", "ga.ui.notify", "ga.ui.select"]).controller("gaPagesUserLocaleController", function($scope, $timeout, gaApiMeta, gaServicesUser, gaUtilsDate, gaNumberFormatFilter, gaUiNotify) { | |
$scope.errors = [], $scope.settings = gaServicesUser.settings.serialize(); | |
var userTimeZoneData = gaUtilsDate.getTimeZoneData(gaServicesUser.settings.timeZone), | |
exampleNumber = 1234.56; | |
$scope.options = { | |
startOfWeek: ["Monday", "Sunday"], | |
timeFormat: [{ | |
value: "24hour", | |
title: gaUtilsDate.getCurrentTimeString("24hour", userTimeZoneData.displayName) | |
}, { | |
value: "12hour", | |
title: gaUtilsDate.getCurrentTimeString("12hour", userTimeZoneData.displayName) | |
}], | |
dateFormat: [{ | |
value: "MDY", | |
title: gaUtilsDate.getCurrentDateString("MDY", userTimeZoneData.displayName) | |
}, { | |
value: "DMY", | |
title: gaUtilsDate.getCurrentDateString("DMY", userTimeZoneData.displayName) | |
}, { | |
value: "YMD", | |
title: gaUtilsDate.getCurrentDateString("YMD", userTimeZoneData.displayName) | |
}], | |
numberFormat: [{ | |
value: "1", | |
title: gaNumberFormatFilter(exampleNumber, null, 1) | |
}, { | |
value: "2", | |
title: gaNumberFormatFilter(exampleNumber, null, 2) | |
}, { | |
value: "3", | |
title: gaNumberFormatFilter(exampleNumber, null, 3) | |
}, { | |
value: "4", | |
title: gaNumberFormatFilter(exampleNumber, null, 4) | |
}], | |
currencyDefault: gaApiMeta.getCurrencies(), | |
timeZone: gaUtilsDate.getTimeZonesAvailable().map(function(tz) { | |
return { | |
value: tz.displayName, | |
title: tz.displayNameOffset | |
} | |
}) | |
}, $scope.save = function() { | |
$scope.errors = [], $scope.processing = !0, gaServicesUser.settings.save($scope.settings).then(function() { | |
gaUiNotify.show("Locale settings saved", 4e3, "default") | |
}).catch(function(errors) { | |
$scope.errors = errors | |
}).finally(function() { | |
$scope.processing = !1 | |
}) | |
} | |
}), angular.module("ga.pages.user.home", ["ngSanitize", "ui.router", "ga.config", "ga.ui.modal", "ga.ui.widgetChart", "ga.ui.floatLabel", "ga.ui.upload", "ga.ui.notify", "ga.ui.tooltip", "ga.utils.helpers.focusElement", "ga.services.user", "ga.services.game", "ga.services.pardot", "ga.services.tracking", "ga.services.dialogs", "ga.pages.user.gameCreate", "ga.pages.user.studioCreate", "ga.api.userDb.authenticated.user", "ga.api.userDb.public.activate", "ga.utils.cookie", "ga.utils.date", "ga.utils.tracking", "ga.filters.titleCase"]).controller("gaPagesUserHomeController", function($rootScope, $scope, $timeout, $templateCache, $window, $state, gaConfig, gaServicesUser, gaServicesGame, gaServicesPardot, gaUiModal, gaApiUserDbAuthenticatedUser, gaUtilsCookie, gaUiNotify, gaUtilsDate, gaServicesTracking, gaUtilsTracking, gaApiUserDbPublicActivate, gaDialogs) { | |
$scope.homeState = { | |
state: null | |
}, $scope.archive = null !== $state.params.archive, $scope.previousPeriod = gaUtilsDate.moment.utc().startOf("day").add("days", -7).format("MMM Do"), $scope.imageBaseUrl = gaConfig.images.baseUrl; | |
var setState = function() { | |
$scope.inviteCount = gaServicesUser.invites.length, $scope.latestInvite = $scope.inviteCount ? gaServicesUser.invites[0] : null, $scope.homeState = { | |
state: null | |
}; | |
var studioList = gaServicesUser.studios.filter(function(studio) { | |
return !studio.demo | |
}); | |
if ($scope.inviteCount) $scope.homeState.state = "invites", gaServicesUser.onboarding.home.welcome || (gaServicesUser.onboarding.set("home", "welcome", !0), gaServicesUser.onboarding.save()); | |
else if (gaServicesUser.activated) | |
if (studioList.length) { | |
if (!gaServicesUser.onboarding.home.welcome && 1 === studioList.length && studioList[0].games.length < 2) { | |
var game = $scope.user.studios[0] && $scope.user.studios[0].games && $scope.user.studios[0].games[0] || null; | |
game ? gaServicesGame.getStatus(game.id).then(function(status) { | |
return status.eventCount - status.rejectedEvents > 0 ? (gaServicesUser.onboarding.set("home", "welcome", !0), void gaServicesUser.onboarding.save()) : void($scope.homeState = { | |
state: "welcome", | |
onboarding: { | |
category: "home", | |
key: "welcome" | |
}, | |
step: 2 | |
}) | |
}) : $scope.homeState = { | |
state: "welcome", | |
onboarding: { | |
category: "home", | |
key: "welcome" | |
}, | |
step: 1 | |
} | |
} else if (gaUtilsCookie.get("ga_share_the_love")) return | |
} else $scope.homeState = { | |
state: "empty" | |
}; | |
else $scope.homeState = { | |
state: "welcomeNonActive" | |
} | |
}, | |
dismissState = function() { | |
$scope.homeState.cookieName && gaUtilsCookie.set($scope.homeState.cookieName, "1", 28), $scope.homeState.onboarding && (gaServicesUser.onboarding.set($scope.homeState.onboarding.category, $scope.homeState.onboarding.key, !0), gaServicesUser.onboarding.save()), gaUtilsTracking.trackEvent({ | |
category: "home", | |
action: "hero", | |
label: "dismiss" | |
}), $scope.homeState = { | |
state: null | |
} | |
}; | |
$scope.archiveFilterStudio = function(studio) { | |
return $scope.archive && !studio.archived ? studio.games.some(function(game) { | |
return game.archived | |
}) : studio.archived === $scope.archive | |
}, $scope.archiveFilterGame = function(game) { | |
return $scope.archive && !game.archived ? gaServicesUser.studio(game.studioId).archived : game.archived === $scope.archive | |
}; | |
var populateData = function() { | |
$scope.user = { | |
studios: gaServicesUser.studios, | |
activated: gaServicesUser.activated, | |
firstName: gaServicesUser.details.firstName | |
}, $scope.showArchiveButton = gaServicesUser.studios.some(function(studio) { | |
return studio.admin || studio.games.some(function(game) { | |
return game.admin | |
}) | |
}), $scope.archivedCount = gaServicesUser.studios.reduce(function(count, studio) { | |
return studio.archived ? count += studio.games.length : studio.games.reduce(function(count, game) { | |
return count += game.archived ? 1 : 0 | |
}, count) | |
}, 0), $scope.user.studios.forEach(function(studio) { | |
studio.hide = !studio.viewer && !studio.games.some(function(game) { | |
return !game.archived | |
}), studio.games.forEach(function(game) { | |
game.loading = 2, game.link = "/game/" + game.id + "/dashboards", gaServicesGame.getNumbers(game.id).then(function(response) { | |
game.gameNumbers = response, game.loading-- | |
}), gaServicesGame.getStatus(game.id).then(function(status) { | |
game.gameStatus = status, status.error ? game.state = "error" : status.data24 ? game.state = "ok" : status.data ? game.state = "no-data-last24" : (game.state = "no-data", game.link = !game.admin || gaUtilsCookie.get("ga-game-guide-" + game.id) ? "/game/" + game.id + "/initialize" : "/game/" + game.id + "/content/sdk"), game.eventCount = status.eventCount, game.loading-- | |
}) | |
}) | |
}), setState() | |
}, | |
showInvites = function() { | |
gaServicesUser.dialogInvites() | |
}, | |
acceptInvite = function(invite) { | |
invite && invite.accept().then(function() { | |
gaUiNotify.show("Invite accepted", 4e3) | |
}) | |
}, | |
declineInvite = function(invite) { | |
invite && gaUiModal.confirm("Are you sure you want to decline this invitation?", "Decline invitation").then(function() { | |
invite.decline().then(function() { | |
gaUiNotify.show("Invite declined", 4e3) | |
}) | |
}) | |
}, | |
createStudio = function() { | |
var promise = gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/user/studio-create/studio-create.html", | |
controller: "gaPagesUserStudioCreateController" | |
}); | |
gaUtilsTracking.trackEvent({ | |
category: "home", | |
action: "studio", | |
label: "popupadd" | |
}), gaUtilsTracking.trackPageRaw("/studio/create"), promise.then(function() { | |
gaUiNotify.show("Studio successfully created", 4e3, "default"), gaUtilsTracking.trackEvent({ | |
category: "home", | |
action: "studio", | |
label: "created" | |
}) | |
}) | |
}, | |
createGame = function(studio) { | |
var promise = gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/user/game-create/game-create.html", | |
controller: "gaPagesUserGameCreateController", | |
parameters: { | |
studioId: studio.id, | |
step: 2 | |
} | |
}); | |
gaUtilsTracking.trackEvent({ | |
category: "home", | |
action: "game", | |
label: "popupadd" | |
}), gaUtilsTracking.trackPageRaw("/game/add"), promise.then(function(newGameId) { | |
gaUiNotify.show("Game successfully created", 4e3, "default"), $state.go("game.content.section", { | |
section: "sdk", | |
gameId: newGameId | |
}), gaUtilsTracking.trackEvent({ | |
category: "home", | |
action: "game", | |
label: "added" | |
}) | |
}) | |
}, | |
resendActivationEmail = function() { | |
$scope.resending = !0, gaApiUserDbPublicActivate.sendActivationEmail(gaServicesUser.details.email).then(function() { | |
gaUiNotify.show("Activation email resent", 4e3), $scope.activationResent = !0, $scope.resending = !1 | |
}).catch(function() { | |
$scope.resending = !1 | |
}) | |
}; | |
$scope.$on("userStudiosChange", function() { | |
populateData() | |
}), $scope.$on("userInvitesChange", function() { | |
$scope.inviteCount = gaServicesUser.invites.length, $scope.latestInvite = $scope.inviteCount ? gaServicesUser.invites[0] : null, setState() | |
}), $scope.$watch("newStudio.active", function(newVal, oldVal) { | |
newVal !== oldVal && newVal ? setTimeout(function() { | |
angular.element("#addStudioBox").on("click.addStudio", function(e) { | |
return "file" === angular.element(e.target).attr("type") ? !0 : !1 | |
}), angular.element("html").on("click.addStudio", $scope.$apply.bind($scope, function() { | |
$scope.newStudio.name || $scope.newStudio.imageFile || ($scope.newStudio.active = !1) | |
})) | |
}) : (angular.element("#addStudioBox").off(".addStudio"), angular.element("html").off(".addStudio")) | |
}), $scope.disableDemoGame = function() { | |
gaUtilsTracking.trackEvent({ | |
category: "home", | |
action: "studio", | |
label: "demohide" | |
}), gaUiNotify.show("You can enable the Demo Game from the user settings.", 4e3), gaServicesUser.details.save({ | |
demoGameEnabled: !1 | |
}) | |
}, $scope.archiving = function() { | |
gaDialogs.archive($scope.user.studios).then(function() { | |
gaUiNotify.show("Archive updated", 4e3, "default"), gaServicesUser.getUserData() | |
}) | |
}, $scope.$on("forcedUserDataChange", function() { | |
populateData() | |
}), $scope.dismissState = dismissState, $scope.showInvites = showInvites, $scope.acceptInvite = acceptInvite, $scope.declineInvite = declineInvite, $scope.createGame = createGame, $scope.createStudio = createStudio, $scope.resendActivationEmail = resendActivationEmail, populateData(), setState() | |
}), angular.module("ga.pages.user.gameCreate", ["ui.router", "ga.config", "ga.ui.tagInput", "ga.ui.upload", "ga.ui.errors", "ga.api.userDb.authenticated.studio", "ga.api.userDb.authenticated.genre", "ga.services.user", "ga.utils.helpers.focusElement"]).controller("gaPagesUserGameCreateController", function($scope, $timeout, $state, gaConfig, gaApiUserDbAuthenticatedStudio, gaApiUserDbAuthenticatedGenre, gaServicesUser) { | |
$scope.errors = [], $scope.studioName = (gaServicesUser.studio($scope.studioId) || {}).name || "", $scope.genres = [], gaApiUserDbAuthenticatedGenre.getGenres().then(function(results) { | |
$scope.genres = results.map(function(genre) { | |
return { | |
value: genre.id, | |
title: genre.name | |
} | |
}) | |
}), $scope.step = $scope.step || 2, $scope.defaultImage = "/static/ga-app/images/default-game-icon.png", $scope.imageBaseUrl = gaConfig.images.baseUrl, $scope.uploadFile = null, $scope.game = { | |
name: "", | |
tags: [], | |
storeLinks: [""] | |
}, $scope.checkStoreLinks = function(removeIndex) { | |
var newStoreLinks = angular.copy($scope.game.storeLinks); | |
removeIndex = void 0 === removeIndex ? !1 : removeIndex, removeIndex === !1 && newStoreLinks.some(function(link, index) { | |
return !link && index < newStoreLinks.length - 1 ? (removeIndex = index, !0) : void 0 | |
}), removeIndex !== !1 && newStoreLinks.splice(removeIndex, 1), (!newStoreLinks.length || newStoreLinks[newStoreLinks.length - 1]) && newStoreLinks.push(""), $scope.game.storeLinks = newStoreLinks | |
}, $scope.checkStoreLinks(), $scope.fetchGameInfo = function() { | |
$scope.fetchingGameInfo = !0, $timeout(function() { | |
$scope.fetchingGameInfo = !1, $scope.fetchError = "We could not find any game info" | |
}, 2e3) | |
}, $scope.prevStep = function() { | |
$scope.step-- | |
}, $scope.nextStep = function() { | |
$scope.step++ | |
}, $scope.save = function() { | |
var payload = { | |
gameTitle: $scope.game.gameTitle || "", | |
imageFile: $scope.game.imageFile || "", | |
genres: $scope.game.tags.map(function(genre) { | |
return genre.value | |
}) | |
}; | |
$scope.processing = !0, gaApiUserDbAuthenticatedStudio.createGame($scope.studioId, payload).then(function(results) { | |
results[0] && gaServicesUser.getUserData(!0).then(function() { | |
$scope._resolve && $scope._resolve(results[0].id) | |
}) | |
}).catch(function(errors) { | |
$scope.processing = !1, $scope.errors = errors | |
}) | |
}, $scope.cancel = function() { | |
$scope._reject && $scope._reject("cancel") | |
} | |
}), angular.module("ga.pages.user.studioCreate", ["ui.router", "ga.config", "ga.ui.upload", "ga.ui.errors", "ga.api.userDb.authenticated.user", "ga.services.user", "ga.utils.helpers.focusElement"]).controller("gaPagesUserStudioCreateController", function($scope, $timeout, $state, gaConfig, gaApiUserDbAuthenticatedUser, gaServicesUser) { | |
$scope.errors = [], $scope.defaultImage = "/static/ga-app/images/default-studio-icon.png", $scope.imageBaseUrl = gaConfig.images.baseUrl, $scope.uploadFile = null, $scope.studio = { | |
name: "" | |
}, $scope.save = function() { | |
var payload = { | |
studioName: $scope.studio.name || "", | |
imageFile: $scope.studio.imageFile || "" | |
}; | |
$scope.processing = !0, gaApiUserDbAuthenticatedUser.createStudio(payload).then(function() { | |
gaServicesUser.getUserData().then(function() { | |
$scope._resolve && $scope._resolve() | |
}) | |
}).catch(function(errors) { | |
$scope.processing = !1, $scope.errors = errors | |
}) | |
}, $scope.cancel = function() { | |
$scope._reject && $scope._reject("cancel") | |
} | |
}), angular.module("ga.pages.user.passwordChange", ["ga.services.user", "ga.api.userDb.authenticated.user", "ga.ui.errors", "ga.ui.floatLabel", "ga.ui.notify"]).controller("gaPagesUserPasswordChangeController", function($scope, $timeout, gaServicesUser, gaApiUserDbAuthenticatedUser, gaUiNotify) { | |
$scope.api = { | |
errors: [], | |
processing: !1, | |
success: !1 | |
}, $scope.passwordChangeSuccess = !1, $scope.data = { | |
passwordCurrent: "", | |
password: "", | |
passwordConfirm: "" | |
}, $scope.cancel = function() { | |
$scope._reject && $scope._reject() | |
}, $scope.passwordChange = function() { | |
$scope.api.processing = !0, gaApiUserDbAuthenticatedUser.passwordChange($scope.data).then(function() { | |
gaUiNotify.show("Password was changed", 4e3, "default"), $scope._resolve && $scope._resolve() | |
}).catch(function(errors) { | |
$scope.api.errors = errors, $scope.api.processing = !1 | |
}) | |
}, $scope.passwordForgot = function() { | |
$scope._reject && $scope._reject(), $timeout(function() { | |
gaServicesUser.dialogPasswordForgot() | |
}) | |
} | |
}), angular.module("ga.pages.user.invites", ["ga.config", "ga.services.user", "ga.ui.modal", "ga.ui.notify"]).controller("gaPagesUserInvitesController", function($scope, gaConfig, gaServicesUser, gaUiModal, gaUiNotify) { | |
$scope.imageBaseUrl = gaConfig.images.baseUrl, $scope.studioInvites = gaServicesUser.invites.filter(function(invite) { | |
return "studio" === invite.type | |
}), $scope.gameInvites = gaServicesUser.invites.filter(function(invite) { | |
return "game" === invite.type | |
}), $scope.$on("userInvitesChange", function() { | |
$scope.studioInvites = gaServicesUser.invites.filter(function(invite) { | |
return "studio" === invite.type | |
}), $scope.gameInvites = gaServicesUser.invites.filter(function(invite) { | |
return "game" === invite.type | |
}) | |
}), $scope.close = function() { | |
$scope._resolve && $scope._resolve() | |
}, $scope.declineInvite = function(invite) { | |
invite && gaUiModal.confirm("Are you sure you want to decline this invitation?", "Decline invitation").then(function() { | |
invite.decline().then(function() { | |
gaUiNotify.show("Invite declined", 4e3) | |
}) | |
}) | |
}, $scope.acceptInvite = function(invite) { | |
invite && invite.accept().then(function() { | |
gaUiNotify.show("Invite accepted", 4e3) | |
}) | |
} | |
}), angular.module("ga.pages.mock", ["ga.services.user", "ga.api.data", "ga.utils.date", "ga.ui.modal", "ga.ui.datepicker", "ga.ui.select"]).controller("gaPagesMockController", function() {}), angular.module("ga.pages.templates", ["ngSanitize"]).controller("gaPagesTemplatesController", function($scope, $http, $templateCache, $compile, $state, $sce) { | |
$scope.view = { | |
category: $state.params.category, | |
item: $state.params.item, | |
html: angular.element(), | |
parsed: [] | |
}; | |
var select = function(category, item) { | |
console.log(category, item), $state.go("templates.show", { | |
category: category, | |
item: item | |
}), $scope.view.category = category, $scope.view.item = item, loadTemplate() | |
}, | |
loadTemplate = function() { | |
$scope.view.parsed = {}; | |
var template = "/static/ga-app/modules/pages/templates/templates/" + $scope.view.category + "/" + $scope.view.item + ".html", | |
templateContent = $templateCache.get(template); | |
if (templateContent) return void parseTemplate(templateContent); | |
var promise = $http.get(template); | |
promise.then(function(response) { | |
$templateCache.put(template, response.data), parseTemplate(response.data) | |
}, function() { | |
$scope.view.parsed = { | |
title: "Template not found", | |
subTitle: template, | |
items: [] | |
} | |
}) | |
}, | |
parseTemplate = function(template) { | |
var parsed = { | |
items: [] | |
}; | |
$scope.view.parsed = []; | |
var $el = angular.element(template); | |
parsed.title = $el.find("h1").html(), parsed.subTitle = $el.find("h2").html(), parsed.description = $el.find(">p").html() || "", $el.find("dt").each(function(index, $item) { | |
$item = angular.element($item); | |
var item = {}; | |
item.title = $item.find("h3").html() || "", item.description = $item.find("p").html() || "", item.html = $item.next().html().trim().replace(/&/g, "&").replace(/\n\s{12}/g, "\n"), parsed.items.push(item) | |
}), $scope.view.parsed = parsed | |
}; | |
$scope.select = select, $scope.unsafeHTML = function(item) { | |
return $sce.trustAsHtml(item) | |
}, $scope.view.category && $scope.view.item && loadTemplate(), $scope.availableTemplates = [{ | |
name: "form", | |
title: "Form Element", | |
items: [{ | |
name: "input", | |
title: "Input" | |
}, { | |
name: "button", | |
title: "Button" | |
}, { | |
name: "select", | |
title: "Select" | |
}, { | |
name: "radiocheck", | |
title: "Radio / Checkbox" | |
}, { | |
name: "label", | |
title: "Label" | |
}] | |
}, { | |
name: "style", | |
title: "Style", | |
items: [{ | |
name: "box", | |
title: "Box" | |
}, { | |
name: "typography", | |
title: "Typography" | |
}, { | |
name: "list", | |
title: "List" | |
}, { | |
name: "diverse", | |
title: "Diverse" | |
}] | |
}, { | |
name: "layout", | |
title: "Layout", | |
items: [{ | |
name: "wrapper", | |
title: "Wrapper", | |
category: "layout" | |
}, { | |
name: "grid", | |
title: "Grid", | |
category: "layout" | |
}] | |
}] | |
}), angular.module("ga.pages.public.footer", []).directive("gaPagesPublicFooter", function() { | |
return { | |
restrict: "E", | |
replace: !0, | |
template: '<section class="ga fill light font-small text-center"><div class="ga grid"><a href="http://support.gameanalytics.com" target="_blank" class="grey">Support</a><a href="http://www.gameanalytics.com/terms.html" target="_blank" class="grey">Terms of service</a><a href="http://support.gameanalytics.com/hc/en-us/categories/200079956-For-Game-Developers" target="_blank" class="grey">Documentation</a></div></section>' | |
} | |
}), angular.module("ga.pages.public.login", ["ngRoute", "ga.pages.public.footer", "ga.services.user", "ga.ui.modal", "ga.ui.floatLabel", "ga.ui.errors", "ga.pages.public.passwordForgot", "ga.utils.cache", "ga.api.userDb.public.activate"]).controller("gaPagesPublicLoginController", function($window, $scope, $location, $state, $stateParams, gaServicesUser, gaUiModal, gaUtilsCache, gaApiUserDbPublicActivate) { | |
if ($scope.errors = [], $scope.support = !1, null !== $stateParams.support && ($scope.support = !0), null !== $stateParams.passwordreset && ($scope.passwordreset = !0, $state.go("public.login", {}, { | |
inherit: !1, | |
notify: !1 | |
})), null !== $stateParams.notverified && ($stateParams.source ? "github" === $stateParams.source && $scope.errors.push({ | |
id: "notverified", | |
msg: "Your GitHub account email address is not verified", | |
type: "queryString" | |
}) : $scope.notActivated = !0), null !== $stateParams.linkedother && $scope.errors.push({ | |
id: "linkedother", | |
msg: "Account linked to another provider", | |
type: "queryString" | |
}), null !== $stateParams.notfound && $stateParams.source) { | |
var sourceName = "github" === $stateParams.source ? "GitHub" : "Google"; | |
$scope.errors.push({ | |
id: "notfound", | |
title: "User account doesn't exist", | |
msg: "We couldn’t match your " + sourceName + " account to an existing GameAnalytics account. Please try again.", | |
type: "queryString" | |
}) | |
} | |
$scope.invite = null !== $stateParams.invite, $scope.login = { | |
email: "", | |
password: "", | |
remember: !1 | |
}, $stateParams.email && $stateParams.email.length > 0 && ($scope.login.email = $stateParams.email); | |
var doLogin = function() { | |
return $scope.login.email = angular.element("input[name=email]").val(), $scope.login.password = angular.element("input[name=password]").val(), $scope.processing ? !1 : ($scope.processing = !0, void gaServicesUser.login($scope.login.email, $scope.login.password, $scope.login.remember).then(function() { | |
if ($scope.errors = [], $scope.support) return void gaServicesUser.supportToken().then(function(token) { | |
var returnTo = $stateParams.return_to || "/home"; | |
$window.location.href = "http://support.gameanalytics.com/access/jwt?jwt=" + token.support_token + "&return_to=" + returnTo | |
}); | |
var goTo = $stateParams.goto || gaUtilsCache.get("goToOnNextLogin", "localStorage"); | |
goTo ? (gaUtilsCache.remove("goToOnNextLogin", "localStorage"), $location.url(goTo), $location.replace()) : $state.go("user.home") | |
}).catch(function(errors) { | |
$scope.processing = !1; | |
var notActivated = errors.some(function(error) { | |
return "user_account_not_activated" === error.id | |
}), | |
passwordFail = errors.some(function(error) { | |
return "password" === error.field | |
}); | |
notActivated ? ($scope.notActivated = !0, $scope.notActivatedEmail = $scope.login.email) : $scope.errors = errors, passwordFail && angular.element("input[name=password]").select() | |
})) | |
}, | |
loginDemoUser = function() { | |
gaServicesUser.token = { | |
token: "GameAnalytics", | |
exp: 1e13, | |
mock: $scope.login.email || "demo@gameanalytics.com", | |
readonly: !0 | |
}, $state.go("user.home", { | |
alert: "You are now browsing the tool as a demo user" | |
}, { | |
inherit: !1 | |
}) | |
}, | |
doLoginGoogle = function() { | |
if ($scope.support) { | |
var returnTo = $stateParams.return_to || "/home"; | |
return void($window.location.href = "/oauth2/google?action=login_support&return_to=" + returnTo) | |
} | |
$window.location.href = "/oauth2/google?action=login" | |
}, | |
doLoginGithub = function() { | |
if ($scope.support) { | |
var returnTo = $stateParams.return_to || "/home"; | |
return void($window.location.href = "/oauth2/github?action=login_support&return_to=" + returnTo) | |
} | |
$window.location.href = "/oauth2/github?action=login" | |
}, | |
resetPasswordDialog = function() { | |
gaServicesUser.dialogPasswordForgot($scope.login.email) | |
}; | |
null !== $stateParams.showreset && ($state.go("public.login", { | |
email: $stateParams.email | |
}, { | |
inherit: !1, | |
notify: !1 | |
}), resetPasswordDialog()); | |
var resendActivationEmail = function() { | |
return $scope.resending ? !1 : ($scope.resending = !0, void gaApiUserDbPublicActivate.sendActivationEmail($scope.notActivatedEmail).then(function() { | |
$scope.activationResent = !0, $scope.resending = !1 | |
}).catch(function() { | |
$scope.resending = !1 | |
})) | |
}; | |
return $scope.loginDemoUser = loginDemoUser, $scope.resetPasswordDialog = resetPasswordDialog, $scope.doLogin = doLogin, $scope.doLoginGoogle = doLoginGoogle, $scope.doLoginGithub = doLoginGithub, $scope.resendActivationEmail = resendActivationEmail, { | |
doLogin: doLogin, | |
doLoginGoogle: doLoginGoogle, | |
doLoginGithub: doLoginGithub | |
} | |
}), angular.module("ga.pages.public.signup", ["ga.pages.public.signup.refs", "ga.pages.public.footer", "ga.api.userDb.public.signup", "ga.api.userDb.public.activate", "ga.ui.errors", "ga.ui.floatLabel", "ga.services.user", "ga.utils.tracking", "ga.services.tracking", "ga.utils.cache", "ga.ui.notify"]).controller("gaPagesPublicSignupController", function($scope, $state, $stateParams, $window, gaServicesUser, gaApiUserDbPublicActivate, gaApiUserDbPublicSignup, gaServicesTracking, gaUtilsTracking, gaUtilsCache, gaUiNotify) { | |
$scope.errors = [], null !== $stateParams.linkeduserfound ? $scope.errors.push({ | |
id: "linkeduserfound", | |
msg: "An account already exists with this email", | |
type: "queryString" | |
}) : "github" === $stateParams.source && null !== $stateParams.notverified && $scope.errors.push({ | |
id: "notverified", | |
msg: "Your GitHub account email address is not verified", | |
type: "queryString" | |
}), $scope.refsActive = !0, $scope.signup = { | |
email: "", | |
ref: null | |
}, $scope.signup.ref = $stateParams.ref && $stateParams.ref.match(/(unity|default)/) ? $stateParams.ref : gaUtilsCache.get("ga_signup_ref", "localStorage") || "default", gaUtilsCache.put("ga_signup_ref", $scope.signup.ref, "localStorage", 18e5), $stateParams.email && $stateParams.email.length > 0 && ($scope.signup.email = $stateParams.email); | |
var doSignupBasic = function() { | |
if ($scope.processing) return !1; | |
$scope.processing = !0; | |
var payload = { | |
email: $scope.signup.email | |
}; | |
["unity", "corona"].indexOf($scope.signup.ref) > -1 && (payload.ref = $scope.signup.ref), gaApiUserDbPublicSignup.signupUser($scope.signup).then(function(result) { | |
return $scope.errors = [], gaUtilsTracking.trackPageRaw("/public/signup/email"), result.token ? (gaServicesUser.token = result, void($scope.signup.success = !0)) : void($scope.processing = !1) | |
}).catch(function(errors) { | |
$scope.errors = errors, $scope.processing = !1 | |
}) | |
}, | |
doSignupGoogle = function() { | |
gaUtilsTracking.trackPageRaw("/public/signup/google"), $window.location.href = "/oauth2/google?action=signup" | |
}, | |
doSignupGithub = function() { | |
gaUtilsTracking.trackPageRaw("/public/signup/github"), $window.location.href = "/oauth2/github?action=signup" | |
}, | |
startDemo = function() { | |
gaServicesUser.resolveUser().then(function() { | |
$state.go("user.home", {}, { | |
inherit: !1, | |
replace: !0 | |
}) | |
}).catch(function() { | |
$scope.signup.success = !1, $scope.processing = !1 | |
}) | |
}, | |
resendActivationEmail = function() { | |
return $scope.resending ? !1 : ($scope.resending = !0, void gaApiUserDbPublicActivate.sendActivationEmail($scope.signup.email).then(function() { | |
$scope.resending = !1, gaUiNotify.show("Verification email sent", 5e3, "default") | |
}).catch(function() { | |
$scope.resending = !1 | |
})) | |
}; | |
return $scope.startDemo = startDemo, $scope.doSignupBasic = doSignupBasic, $scope.doSignupGoogle = doSignupGoogle, $scope.doSignupGithub = doSignupGithub, $scope.resendActivationEmail = resendActivationEmail, { | |
doSignupBasic: doSignupBasic, | |
doSignupGoogle: doSignupGoogle, | |
doSignupGithub: doSignupGithub | |
} | |
}), angular.module("ga.pages.public.signup.refs", ["ui.router", "ga.utils.helpers"]).directive("gaPagesPublicSignupRefs", function($templateCache, gaHelpers, $stateParams) { | |
var nr = parseInt($stateParams.nr, 10) || !1, | |
template = '<aside class="ga slim dark ng-hide text-shadow" ng-show="ref" style="{{ templateStyle }}; width:393px"><section class="ga double" ng-include="templateUrl"></section></aside>', | |
linkingFunction = function($scope) { | |
if ($scope.ref.match(/(unity|default)/)) { | |
var templates = $templateCache.get("/static/ga-app/modules/pages/public/signup/refs/" + $scope.ref + ".html"); | |
if (templates) { | |
templates = angular.element(templates).find("> li"); | |
var number = nr === !1 ? gaHelpers.randomNumber(0, templates.length - 1) : nr - 1, | |
template = $templateCache.get("/static/ga-app/modules/pages/public/signup/refs/" + $scope.ref + "-" + number + ".html"); | |
template || (template = templates[number].innerHTML, $templateCache.put("/static/ga-app/modules/pages/public/signup/refs/" + $scope.ref + "-" + number + ".html", template)); | |
var templateStyle = templates[number].getAttribute("style"); | |
$scope.templateUrl = "/static/ga-app/modules/pages/public/signup/refs/" + $scope.ref + "-" + number + ".html", $scope.templateStyle = templateStyle | |
} | |
} else $scope.ref = "" | |
}; | |
return { | |
restrict: "E", | |
replace: !0, | |
template: template, | |
link: linkingFunction, | |
scope: { | |
ref: "=?ref" | |
} | |
} | |
}), angular.module("ga.pages.public.invite", ["ga.pages.public.footer", "ga.services.user", "ga.api.userDb.public.invite"]).controller("gaPagesPublicInviteController", function(inviteResolve, $scope, $timeout, $state, $window, $stateParams, gaApiUserDbPublicInvite, gaServicesUser) { | |
$scope.userLoggedInEmail = gaServicesUser.details.email, $scope.email = $stateParams.email, $scope.init = !0, $scope.inviteResolve = inviteResolve, $scope.login = function() { | |
gaServicesUser.token = null, $state.go("public.login", { | |
invite: "", | |
email: $scope.email | |
}, { | |
inherit: !1, | |
reload: !0 | |
}) | |
}, $scope.create = function() { | |
gaServicesUser.token = null, $state.go("public.create-account", { | |
invite: "", | |
email: $scope.email, | |
token: $scope.inviteResolve.createToken | |
}, { | |
inherit: !1, | |
reload: !0 | |
}) | |
}, gaApiUserDbPublicInvite.getInviteInfo($stateParams.email, $stateParams.resource, $stateParams.token).then(function(response) { | |
$scope.inviteExists = response.inviteFound, $scope.inviteEmailExists = response.userFound, $scope.init = !1 | |
}) | |
}), angular.module("ga.pages.public.activateAccount", ["ga.pages.public.footer", "ga.services.user", "ga.api.userDb.public.signup", "ga.ui.errors", "ga.ui.floatLabel", "ga.utils.tracking", "ga.services.tracking"]).controller("gaPagesPublicActivateAccountController", function($scope, $state, $window, $stateParams, gaServicesUser, gaApiUserDbPublicSignup, gaServicesTracking, gaUtilsTracking) { | |
$scope.emailOptIn = !0, $scope.data = { | |
email: $stateParams.email, | |
token: $stateParams.token, | |
firstName: "", | |
lastName: "", | |
studioName: "", | |
password: "", | |
passwordConfirm: "", | |
emailOptOut: 0 | |
}, $scope.errors = [], $scope.processing = !1; | |
var activateAccount = function() { | |
return $scope.processing ? !1 : ($scope.processing = !0, $scope.data.emailOptOut = $scope.emailOptIn ? 0 : 1, void gaApiUserDbPublicSignup.activateAccount($scope.data).then(function(result) { | |
gaUtilsTracking.trackPageRaw("/public/activated"), gaUtilsTracking.trackEvent({ | |
category: "signup", | |
action: "activated", | |
label: "email" | |
}), gaServicesUser.token = { | |
token: result.token, | |
exp: result.exp | |
}, $state.go("user.home", { | |
alert: "Account is now activated." | |
}, { | |
inherit: !1 | |
}) | |
}).catch(function(errors) { | |
$scope.errors = errors, $scope.processing = !1 | |
})) | |
}; | |
$scope.activateAccount = activateAccount | |
}), angular.module("ga.pages.public.createAccount", ["ga.pages.public.footer", "ga.services.user", "ga.api.userDb.public.signup", "ga.ui.errors", "ga.ui.floatLabel", "ga.utils.tracking", "ga.services.tracking"]).controller("gaPagesPublicCreateAccountController", function($scope, $state, $window, $stateParams, gaServicesUser, gaApiUserDbPublicSignup, gaServicesTracking, gaUtilsTracking) { | |
switch ($scope.emailOptIn = !0, $scope.data = { | |
email: $stateParams.email || "", | |
createToken: $stateParams.token || "", | |
firstName: $stateParams.firstname || "", | |
lastName: $stateParams.lastname || "", | |
password: "", | |
passwordConfirm: "", | |
emailOptOut: 0 | |
}, $scope.invite = null !== $stateParams.invite, $scope.source = $stateParams.source, $scope.sourceActive = $stateParams.notverified || $stateParams.emailmismatch || !$scope.source ? !1 : !0, $scope.invite || ($scope.data.studioName = ""), $scope.source) { | |
case "google": | |
$scope.sourceName = "Google"; | |
break; | |
case "github": | |
$scope.sourceName = "GitHub"; | |
break; | |
default: | |
$scope.sourceName = "" | |
} | |
$scope.errors = [], "true" === $stateParams.notverified && $scope.errors.push({ | |
id: "notverified", | |
title: $scope.sourceName + " account is not verified!", | |
msg: "Your " + $scope.sourceName + " email address has not yet been verified, which means we cannot create your account at this time. Please verify your " + $scope.sourceName + " account and try again.", | |
type: "queryString" | |
}), "true" === $stateParams.emailmismatch && $scope.errors.push({ | |
id: "emailmismatch", | |
title: $scope.sourceName + " account email mismatch!", | |
msg: "Your " + $scope.sourceName + " email address does not match the email on the invite.", | |
type: "queryString" | |
}), ($stateParams.notverified || $stateParams.emailmismatch) && $state.go("public.create-account", { | |
notverified: null, | |
emailmismatch: null, | |
source: null | |
}, { | |
notify: !1, | |
replace: !0 | |
}), "true" === $stateParams.notfound && $scope.errors.push({ | |
id: "notfound", | |
msg: "Account not found", | |
type: "queryString" | |
}); | |
var src = $scope.source ? $scope.source : "invite"; | |
gaUtilsTracking.trackPageRaw("/public/create-account/" + src), $scope.processing = !1; | |
var createAccount = function() { | |
return $scope.processing ? !1 : ($scope.processing = !0, $scope.data.emailOptOut = $scope.emailOptIn ? 0 : 1, void gaApiUserDbPublicSignup.createAccount($scope.data).then(function(result) { | |
gaUtilsTracking.trackEvent({ | |
category: "signup", | |
action: "create", | |
label: $scope.source | |
}), gaServicesUser.token = { | |
token: result.token, | |
exp: result.exp | |
}; | |
var src = $scope.source ? $scope.source : "invite"; | |
gaUtilsTracking.trackPageRaw("/public/create-account/" + src + "/finished"), $state.go("user.home", { | |
alert: "You have successfully created an account." | |
}, { | |
inherit: !1 | |
}) | |
}).catch(function(errors) { | |
$scope.errors = errors, $scope.processing = !1 | |
})) | |
}, | |
linkedSignup = function(type) { | |
var action = "signup"; | |
switch ($scope.invite && (action = "signup_invite"), type) { | |
case "google": | |
$window.location = "/oauth2/google?action=" + action + "&token=" + $scope.data.createToken; | |
break; | |
case "github": | |
$window.location = "/oauth2/github?action=" + action + "&token=" + $scope.data.createToken | |
} | |
}, | |
cancelLink = function() { | |
$scope.source = !1, $scope.sourceActive = !1, $scope.sourceName = "", $state.go("public.create-account", { | |
source: null | |
}, { | |
notify: !1, | |
replace: !0 | |
}) | |
}; | |
$scope.linkedSignup = linkedSignup, $scope.cancelLink = cancelLink, $scope.createAccount = createAccount | |
}), angular.module("ga.pages.public.linkAccount", ["ga.pages.public.footer", "ui.router", "ga.api.userDb.public.linkAccount", "ga.services.user", "ga.ui.errors", "ga.ui.floatLabel"]).controller("gaPagesPublicLinkAccountController", function($scope, $stateParams, $state, gaApiUserDbPublicLinkAccount, gaServicesUser) { | |
$scope.params = $stateParams, $scope.source = $stateParams.source, $scope.sourceName = "github" === $scope.source ? "GitHub" : "Google", $scope.errors = [], $scope.data = { | |
email: $stateParams.email, | |
token: $stateParams.token, | |
password: "" | |
}, $scope.resetPasswordDialog = function() { | |
gaServicesUser.dialogPasswordForgot($stateParams.email) | |
}, $scope.linkAccount = function() { | |
return $scope.processing ? !1 : ($scope.processing = !0, void gaApiUserDbPublicLinkAccount.link($scope.data).then(function(result) { | |
gaServicesUser.token = { | |
token: result.token, | |
exp: result.exp | |
}; | |
var linkedName = "Google"; | |
"github" === $scope.source && (linkedName = "GitHub"), $state.go("user.home", { | |
alert: "Account is now linked to " + linkedName + " account" | |
}, { | |
inherit: !1 | |
}) | |
}).catch(function(errors) { | |
$scope.processing = !1, $scope.errors = errors | |
})) | |
} | |
}), angular.module("ga.pages.public.passwordReset", ["ga.pages.public.footer", "ui.router", "ga.ui.errors", "ga.ui.floatLabel", "ga.api.userDb.public.passwordReset"]).controller("gaPagesPublicPasswordResetController", function(resolveValidToken, $scope, $stateParams, $state, gaApiUserDbPublicPasswordReset) { | |
$scope.validToken = resolveValidToken, $scope.errors = [], $scope.token = $stateParams.token, $scope.data = { | |
password: "", | |
passwordConfirm: "" | |
}, $scope.processing = !1; | |
var resetPassword = function() { | |
return $scope.processing ? !1 : ($scope.processing = !0, void gaApiUserDbPublicPasswordReset.reset($scope.data, $scope.token).then(function(data) { | |
var replyQueryStrings = { | |
passwordreset: "" | |
}; | |
data && data.email && (replyQueryStrings.email = data.email), $state.go("public.login", replyQueryStrings, { | |
inherit: !1, | |
reload: !0 | |
}) | |
}).catch(function(errors) { | |
$scope.errors = errors, $scope.processing = !1 | |
})) | |
}; | |
$scope.resetPassword = resetPassword | |
}), angular.module("ga.pages.public.passwordForgot", ["ga.ui.errors", "ga.ui.floatLabel", "ga.api.userDb.public.passwordReset"]).controller("gaPagesPublicPasswordForgotController", function($scope, gaApiUserDbPublicPasswordReset) { | |
$scope.errors = [], $scope.data = $scope.data || { | |
email: "" | |
}, $scope.processing = !1; | |
var requestResetEmail = function() { | |
return $scope.processing ? !1 : ($scope.processing = !0, void gaApiUserDbPublicPasswordReset.request($scope.data).then(function() { | |
$scope.emailSent = !0 | |
}).catch(function(errors) { | |
$scope.errors = errors, $scope.processing = !1 | |
})) | |
}; | |
$scope.requestResetEmail = requestResetEmail | |
}), angular.module("ga.pages.public.releaseNotes", []).controller("gaPagesPublicReleaseNotesController", function() {}), angular.module("ga.pages.content", ["ui.router", "ga.services.user", "ga.services.content"]).controller("gaPagesContentController", function($scope, $injector, $timeout, $stateParams, $state, gaServicesUser, gaServicesContent, gaApiUserDbAuthenticatedGame) { | |
$stateParams.gameId && ($scope.gameId = $stateParams.gameId, gaApiUserDbAuthenticatedGame.getGameData($stateParams.gameId).then(function(result) { | |
$scope.gameKey = result.key, $scope.secretKey = result.secret_key | |
})), $scope.$on("$stateChangeSuccess", function() { | |
$scope.section = $state.params.section, $scope.page = $state.params.page, $scope.currentStepIndex = parseInt($state.params.step || 1, 10) - 1, gaServicesContent.get($scope.section, $scope.page).then(function(response) { | |
$scope.content = response, $scope.currentStep = $scope.content.steps ? $scope.content.steps[$scope.currentStepIndex] : null, angular.element("body,html").scrollTop(0), $timeout(function() { | |
$scope.asideContainerEmpty = !angular.element(".ga-page-content aside .container").text().trim(), $scope.asideEmpty = !angular.element(".ga-page-content aside").text().trim() | |
}) | |
}) | |
}), $scope.goToStep = function(step) { | |
var params = angular.copy($state.params); | |
params.step = step, $scope.gameId ? $state.go("game.content.section", params) : $state.go("content.section", params) | |
}, $scope.getTemplate = function(key) { | |
return $scope.currentStep && $scope.currentStep[key] && !$scope.currentStep[key].empty ? $scope.currentStep[key].empty ? null : $scope.currentStep[key].template : $scope.content[key] ? $scope.content[key].empty ? null : $scope.content[key].template : null | |
} | |
}).directive("gaContentImage", function() { | |
var compile = function(element, attrs) { | |
element.replaceWith('<img class="ga-content-widget" src="/static/ga-app/content/_images/' + attrs.src + '" />') | |
}; | |
return { | |
restrict: "E", | |
compile: compile | |
} | |
}).directive("gaContentNote", function() { | |
var compile = function(element) { | |
var content = element.get(0).innerHTML; | |
element.replaceWith('<div class="ga-content-widget note">' + content + "</ul>") | |
}; | |
return { | |
restrict: "E", | |
compile: compile | |
} | |
}).directive("gaContentIcon", function() { | |
var compile = function(element, attrs) { | |
var addPadding = !!element.get(0).innerHTML; | |
element.addClass("ga-icon-" + attrs.gaContentIcon), attrs.size && element.addClass(attrs.size), addPadding && element.addClass("icon-padding") | |
}; | |
return { | |
restrict: "A", | |
replace: !1, | |
compile: compile | |
} | |
}).directive("gaContentCode", function() { | |
var compile = function(element, attrs) { | |
var example = void 0 !== attrs.example, | |
trimSpace = null, | |
lines = element.get(0).innerHTML.split("\n").filter(function(line) { | |
return line.trim() | |
}).map(function(line) { | |
return line = line.replace(/</g, "<").replace(/>/g, ">"), line = line.replace(/\t/g, " "), null === trimSpace && (trimSpace = (line.match(/^\s+/) || [""])[0].length), line = line.replace(new RegExp("^\\s{" + trimSpace + "}"), ""), line = line.replace(/\s/g, " "), "<li>" + line + "</li>" | |
}); | |
element.replaceWith('<ul class="ga-content-widget ga-content-code' + (example ? " example" : "") + '">' + lines.join("") + "</ul>") | |
}; | |
return { | |
restrict: "E", | |
compile: compile | |
} | |
}).directive("gaContentGameKeys", function() { | |
var template = '<div class="ga-content-widget" ng-if="gameId" ng-show="gameKey"><h3>Unique game keys</h3><label>Game key</label><input auto-select class="ga-input small regular" value="{{ gameKey }}" readonly="readonly" /><label>Secret key</label><input auto-select class="ga-input small regular" value="{{ secretKey }}" readonly="readonly" /></div>'; | |
return { | |
restrict: "E", | |
template: template, | |
replace: !0 | |
} | |
}).directive("gaContentGameProgress", function() { | |
var template = '<span ng-if="gameId"><div class="ga menu-filler small" style="height: 30px;"></div><div class="ga bar page white small"><ul class="ga stack progress-list"><li class="done">Create game</li><li class="inprogress">Setup SDK</li><li>Waiting for data</li><li>Done</li></ul></div></span>'; | |
return { | |
restrict: "E", | |
template: template, | |
replace: !0 | |
} | |
}).directive("autoSelect", function() { | |
return { | |
link: function($scope, $element) { | |
$element.on("mouseup", function() { | |
this.select() | |
}) | |
} | |
} | |
}), angular.module("ga.pages.admin.controller", ["ga.ui.modal", "ga.api.admin", "ga.pages.admin.ui.login", "ga.pages.admin.ui.changeUserEmail", "ga.pages.admin.ui.changeStudioOwner"]).service("gaPagesAdminController", function($rootScope, $state, $q, $filter, $timeout, gaUiModal, gaApiAdmin) { | |
var loginModal = function() { | |
return gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/admin/ui/login/login.html", | |
controller: "gaPagesAdminUiLoginController" | |
}) | |
}, | |
changeUserEmailModal = function(userId) { | |
return gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/admin/ui/change-user-email/change-user-email.html", | |
controller: "gaPagesAdminUiChangeUserEmailController", | |
parameters: { | |
userId: userId | |
} | |
}) | |
}, | |
adminChangeStudioOwnerModal = function(studioId) { | |
return gaUiModal.page({ | |
templateUrl: "/static/ga-app/modules/pages/admin/ui/change-studio-owner/change-studio-owner.html", | |
controller: "gaPagesAdminUiChangeStudioOwnerController", | |
width: 800, | |
parameters: { | |
studioId: studioId | |
} | |
}) | |
}, | |
resetImpersonate = function() { | |
return gaApiAdmin.adminResetImpersonate() | |
}, | |
logout = function() { | |
return gaApiAdmin.adminLogout() | |
}; | |
return { | |
loginModal: loginModal, | |
changeUserEmailModal: changeUserEmailModal, | |
adminChangeStudioOwnerModal: adminChangeStudioOwnerModal, | |
resetImpersonate: resetImpersonate, | |
logout: logout | |
} | |
}), angular.module("ga.pages.admin.layout.header", ["ga.ui.popdown", "ui.router", "ga.api.admin", "ga.services.user", "ga.ui.notify"]).controller("gaPagesAdminLayoutHeaderController", function($scope, $rootScope, $location, $state, $route, gaApiAdmin, gaServicesUser, gaUiNotify) { | |
$scope.menuVisible = !1, $scope.dashboardsActive = $state.includes("game.dashboards.show"), $scope.menu = function(show) { | |
show = "boolean" == typeof show ? show : !$scope.menuVisible, $scope.menuVisible = show, show && $rootScope.$broadcast("popdown:open", { | |
id: "mainMenu" | |
}) | |
}, $scope.goTo = function() { | |
$state.go("game.dashboards.dashboard", { | |
action: "show", | |
dashboardId: 1 | |
}), $route.reload() | |
}, $scope.adminLogout = function() { | |
gaApiAdmin.adminLogout().then(function() { | |
gaServicesUser.getUserData(!0, !0).then(function() { | |
gaUiNotify.show("admin logged out!", 4e3, "default"), $state.go("user.home") | |
}) | |
}) | |
} | |
}), angular.module("ga.pages.admin.ui.searchStudios", ["ga.config", "ga.api.data", "ga.api.meta", "ui.router", "ga.api.admin", "ga.ui.popdown"]).controller("gaPagesAdminUiSearchStudiosController", function($scope, $http, gaApiData, gaApiMeta, $timeout, $window, $state, $filter, gaApiAdmin) { | |
var labels = { | |
order_by: "Order By", | |
order: "Order", | |
name: "Name", | |
created_date: "Created Date", | |
asc: "Ascending", | |
desc: "Descending", | |
id: "Id" | |
}; | |
$scope.gaStudios = [], $scope.searchUi = { | |
search_string: null, | |
order_by: "name", | |
order: "asc", | |
pagination: 0 | |
}; | |
var tempSearchSettings = { | |
search_string: null, | |
order_by: "name", | |
order: "asc", | |
pagination: 0 | |
}; | |
$scope.initSearchSettings && ($scope.initSearchSettings.search_string && (tempSearchSettings.search_string = $scope.initSearchSettings.search_string), $scope.initSearchSettings.order_by && (tempSearchSettings.order_by = $scope.initSearchSettings.order_by), $scope.initSearchSettings.order && (tempSearchSettings.order = $scope.initSearchSettings.order), $scope.focusOnInit = $scope.initSearchSettings.focusOnInit ? !0 : !1), $scope.searchSettings = tempSearchSettings, $scope.isLoading = !1, $scope.renderLocalList = !1, $scope.studiosFound || ($scope.renderLocalList = !0); | |
var init = function() { | |
loadSearchQuery() | |
}, | |
loadSearchQuery = function() { | |
$scope.isLoading === !1 && ($scope.isLoading = !0, gaApiAdmin.getStudiosBySearch($scope.searchSettings).then(function(result) { | |
$scope.isLoading = !1, !$scope.renderLocalList && $scope.studiosFound ? $scope.studiosFound = result : $scope.gaStudios = result, applySearchUiValues() | |
}).catch(function() { | |
$scope.isLoading = !1 | |
})) | |
}; | |
$scope.searchKeyUp = function(e) { | |
e.keyCode && 13 === e.keyCode && applySearchUiValues() | |
}; | |
var timerPromise; | |
$scope.$watch("searchUi.search_string", function(newVal, oldVal) { | |
newVal !== oldVal && ($timeout.cancel(timerPromise), timerPromise = $timeout(function() { | |
applySearchUiValues() | |
}, 700)) | |
}), $scope.selectStudio = function(studio) { | |
$scope.studioSelected = studio | |
}; | |
var applySearchUiValues = function() { | |
angular.equals($scope.searchSettings, $scope.searchUi) || $scope.isLoading === !0 || ($scope.searchSettings = angular.copy($scope.searchUi), loadSearchQuery()) | |
}; | |
return $scope.changeOrderBy = function(order_by_new_value) { | |
$scope.searchUi.order_by = order_by_new_value, applySearchUiValues() | |
}, $scope.changeOrder = function(order_new_value) { | |
$scope.searchUi.order = order_new_value, applySearchUiValues() | |
}, $scope.getLabel = function(labelId) { | |
return labels && labels[labelId] ? labels[labelId] : "label not found" | |
}, $scope.getClassForOrder = function() { | |
return $scope.searchUi && $scope.searchUi.order && "asc" === $scope.searchUi.order ? "ga-icon-barchart" : "ga-icon-barchart-inverse" | |
}, $scope.updateFocusState = function(state) { | |
if ($scope.searchInFocus) { | |
var tempFocusDict = { | |
focus: !1 | |
}; | |
state && (tempFocusDict.focus = !0), $scope.searchInFocus = tempFocusDict | |
} | |
}, { | |
init: init | |
} | |
}).directive("gaPagesAdminUiSearchStudios", function() { | |
var linkingFunction = function($scope, $element, $attrs, $controller) { | |
$controller.init() | |
}; | |
return { | |
restrict: "E", | |
replace: !0, | |
scope: { | |
studioSelected: "=?", | |
studiosFound: "=?", | |
initSearchSettings: "=?", | |
searchInFocus: "=?" | |
}, | |
controller: "gaPagesAdminUiSearchStudiosController", | |
link: linkingFunction, | |
templateUrl: "/static/ga-app/modules/pages/admin/ui/search-studios/search-studios.html" | |
} | |
}), angular.module("ga.pages.admin.ui.searchGames", ["ga.config", "ga.api.data", "ga.api.meta", "ui.router", "ga.api.admin", "ga.ui.popdown"]).controller("gaPagesAdminUiSearchGamesController", function($scope, $http, gaApiData, gaApiMeta, $timeout, $window, $state, $filter, gaApiAdmin) { | |
var labels = { | |
order_by: "Order By", | |
order: "Order", | |
title: "Title", | |
created_date: "Created Date", | |
asc: "Ascending", | |
desc: "Descending", | |
id: "Id" | |
}; | |
$scope.gaGames = []; | |
var tempSearchSettings = { | |
search_string: null, | |
order_by: "title", | |
order: "asc", | |
pagination: 0, | |
only_with_store_apps_defined: !1 | |
}; | |
$scope.initSearchSettings && ($scope.initSearchSettings.search_string && (tempSearchSettings.search_string = $scope.initSearchSettings.search_string), $scope.initSearchSettings.order_by && (tempSearchSettings.order_by = $scope.initSearchSettings.order_by), $scope.initSearchSettings.order && (tempSearchSettings.order = $scope.initSearchSettings.order), $scope.initSearchSettings.only_with_store_apps_defined && (tempSearchSettings.only_with_store_apps_defined = $scope.initSearchSettings.only_with_store_apps_defined), $scope.focusOnInit = $scope.initSearchSettings.focusOnInit ? !0 : !1), $scope.searchUi = angular.copy(tempSearchSettings), $scope.searchSettings = tempSearchSettings, $scope.isLoading = !1, $scope.renderLocalList = !1, $scope.gamesFound || ($scope.renderLocalList = !0); | |
var init = function() { | |
loadSearchQuery() | |
}, | |
loadSearchQuery = function() { | |
$scope.isLoading === !1 && ($scope.isLoading = !0, gaApiAdmin.getGamesBySearch($scope.searchSettings).then(function(result) { | |
$scope.isLoading = !1, !$scope.renderLocalList && $scope.gamesFound ? $scope.gamesFound = result : $scope.gaGames = result, applySearchUiValues() | |
}).catch(function() { | |
$scope.isLoading = !1 | |
})) | |
}; | |
$scope.searchKeyUp = function(e) { | |
e.keyCode && 13 === e.keyCode && applySearchUiValues() | |
}; | |
var timerPromise; | |
$scope.$watch("searchUi.search_string", function(newVal, oldVal) { | |
newVal !== oldVal && ($timeout.cancel(timerPromise), timerPromise = $timeout(function() { | |
applySearchUiValues() | |
}, 700)) | |
}), $scope.selectGame = function(game) { | |
$scope.gameSelected && ($scope.gameSelected = game) | |
}; | |
var applySearchUiValues = function() { | |
angular.equals($scope.searchSettings, $scope.searchUi) || $scope.isLoading === !0 || ($scope.searchSettings = angular.copy($scope.searchUi), loadSearchQuery()) | |
}; | |
return $scope.changeOrderBy = function(order_by_new_value) { | |
$scope.searchUi.order_by = order_by_new_value, applySearchUiValues() | |
}, $scope.changeOrder = function(order_new_value) { | |
$scope.searchUi.order = order_new_value, applySearchUiValues() | |
}, $scope.getLabel = function(labelId) { | |
return labels && labels[labelId] ? labels[labelId] : "label not found" | |
}, $scope.getClassForOrder = function() { | |
return $scope.searchUi && $scope.searchUi.order && "asc" === $scope.searchUi.order ? "ga-icon-barchart" : "ga-icon-barchart-inverse" | |
}, $scope.updateFocusState = function(state) { | |
if ($scope.searchInFocus) { | |
var tempFocusDict = { | |
focus: !1 | |
}; | |
state && (tempFocusDict.focus = !0), $scope.searchInFocus = tempFocusDict | |
} | |
}, { | |
init: init | |
} | |
}).directive("gaPagesAdminUiSearchGames", function() { | |
var linkingFunction = function($scope, $element, $attrs, $controller) { | |
$controller.init() | |
}; | |
return { | |
restrict: "E", | |
replace: !0, | |
scope: { | |
gameSelected: "=?", | |
gamesFound: "=?", | |
initSearchSettings: "=?", | |
searchInFocus: "=?" | |
}, | |
controller: "gaPagesAdminUiSearchGamesController", | |
link: linkingFunction, | |
templateUrl: "/static/ga-app/modules/pages/admin/ui/search-games/search-games.html" | |
} | |
}), angular.module("ga.pages.admin.ui.searchUsers", ["ga.config", "ga.api.data", "ga.api.meta", "ui.router", "ga.api.admin", "ga.ui.popdown"]).controller("gaPagesAdminUiSearchUsersController", function($scope, $http, gaApiData, gaApiMeta, $timeout, $window, $state, $filter, gaApiAdmin) { | |
var labels = { | |
order_by: "Order By", | |
order: "Order", | |
full_name: "Fullname", | |
email: "Email", | |
created_date: "Created Date", | |
last_login_date: "Last Login Date", | |
asc: "Ascending", | |
desc: "Descending", | |
id: "Id" | |
}; | |
$scope.gaUsers = [], $scope.searchUi = { | |
search_string: null, | |
order_by: "last_login_date", | |
order: "desc", | |
pagination: 0 | |
}; | |
var tempSearchSettings = { | |
search_string: null, | |
order_by: "last_login_date", | |
order: "desc", | |
pagination: 0 | |
}; | |
$scope.initSearchSettings && ($scope.initSearchSettings.search_string && (tempSearchSettings.search_string = $scope.initSearchSettings.search_string), $scope.initSearchSettings.order_by && (tempSearchSettings.order_by = $scope.initSearchSettings.order_by), $scope.initSearchSettings.order && (tempSearchSettings.order = $scope.initSearchSettings.order), $scope.focusOnInit = $scope.initSearchSettings.focusOnInit ? !0 : !1), $scope.searchSettings = tempSearchSettings, $scope.isLoading = !1, $scope.renderLocalList = !1, $scope.usersFound || ($scope.renderLocalList = !0); | |
var init = function() { | |
loadSearchQuery() | |
}, | |
loadSearchQuery = function() { | |
$scope.isLoading === !1 && ($scope.isLoading = !0, gaApiAdmin.getUsersBySearch($scope.searchSettings).then(function(result) { | |
$scope.isLoading = !1, !$scope.renderLocalList && $scope.usersFound ? $scope.usersFound = result : $scope.gaUsers = result, applySearchUiValues() | |
}).catch(function() { | |
$scope.isLoading = !1 | |
})) | |
}; | |
$scope.searchKeyUp = function(e) { | |
e.keyCode && 13 === e.keyCode && applySearchUiValues() | |
}; | |
var timerPromise; | |
$scope.$watch("searchUi.search_string", function(newVal, oldVal) { | |
newVal !== oldVal && ($timeout.cancel(timerPromise), timerPromise = $timeout(function() { | |
applySearchUiValues() | |
}, 700)) | |
}), $scope.selectUser = function(user) { | |
$scope.userSelected = user | |
}; | |
var applySearchUiValues = function() { | |
angular.equals($scope.searchSettings, $scope.searchUi) || $scope.isLoading === !0 || ($scope.searchSettings = angular.copy($scope.searchUi), loadSearchQuery()) | |
}; | |
return $scope.changeOrderBy = function(order_by_new_value) { | |
$scope.searchUi.order_by = order_by_new_value, applySearchUiValues() | |
}, $scope.changeOrder = function(order_new_value) { | |
$scope.searchUi.order = order_new_value, applySearchUiValues() | |
}, $scope.getLabel = function(labelId) { | |
return labels && labels[labelId] ? labels[labelId] : "label not found" | |
}, $scope.getClassForOrder = function() { | |
return $scope.searchUi && $scope.searchUi.order && "asc" === $scope.searchUi.order ? "ga-icon-barchart" : "ga-icon-barchart-inverse" | |
}, $scope.updateFocusState = function(state) { | |
if ($scope.searchInFocus) { | |
var tempFocusDict = { | |
focus: !1 | |
}; | |
state && (tempFocusDict.focus = !0), $scope.searchInFocus = tempFocusDict | |
} | |
}, { | |
init: init | |
} | |
}).directive("gaPagesAdminUiSearchUsers", function() { | |
var linkingFunction = function($scope, $element, $attrs, $controller) { | |
$controller.init() | |
}; | |
return { | |
restrict: "E", | |
replace: !0, | |
scope: { | |
userSelected: "=?", | |
usersFound: "=?", | |
initSearchSettings: "=?", | |
searchInFocus: "=?" | |
}, | |
controller: "gaPagesAdminUiSearchUsersController", | |
link: linkingFunction, | |
templateUrl: "/static/ga-app/modules/pages/admin/ui/search-users/search-users.html" | |
} | |
}), angular.module("ga.pages.admin.ui.login", ["ui.router", "ga.config", "ga.ui.tagInput", "ga.ui.upload", "ga.ui.errors", "ga.api.admin", "ga.services.user", "ga.utils.helpers.focusElement", "ga.services.user"]).controller("gaPagesAdminUiLoginController", function($scope, $state, gaServicesUser, gaApiAdmin) { | |
(!gaServicesUser.admin || gaServicesUser.adminLoggedIn) && $scope._reject && $scope._reject("cancel"), $scope.data = { | |
loginError: "", | |
authKey: null, | |
processing: !1 | |
}, $scope.cancel = function() { | |
$scope._reject && $scope._reject("cancel") | |
}, $scope.authcodeKeyUp = function(e) { | |
e.keyCode && 13 === e.keyCode && $scope.data.authKey && $scope.adminLogin() | |
}, $scope.adminLogin = function() { | |
$scope.data.processing = !0, gaApiAdmin.adminLogin($scope.data.authKey).then(function() { | |
gaServicesUser.getUserData(!0, !0).then(function() { | |
$scope.data.loginError = "", $scope._resolve && $scope._resolve() | |
}).catch(function() { | |
$scope.data.processing = !1, $scope._reject && $scope._reject("cancel") | |
}) | |
}).catch(function(errors) { | |
$scope.data.loginError = errors[0] && errors[0].msg ? errors[0].msg : "", $scope.data.processing = !1 | |
}) | |
} | |
}), angular.module("ga.pages.admin.ui.changeUserEmail", ["ui.router", "ga.config", "ga.ui.tagInput", "ga.ui.upload", "ga.ui.errors", "ga.api.admin", "ga.services.user", "ga.utils.helpers.focusElement", "ga.services.user"]).controller("gaPagesAdminUiChangeUserEmailController", function($scope, $state, gaServicesUser, gaApiAdmin) { | |
gaServicesUser.admin && gaServicesUser.adminLoggedIn && $scope.userId || $scope._reject && $scope._reject("cancel"), $scope.data = { | |
requestError: "", | |
email: null, | |
processing: !1 | |
}, $scope.cancel = function() { | |
$scope._reject && $scope._reject("cancel") | |
}, $scope.modalKeyUp = function(e) { | |
e.keyCode && 13 === e.keyCode && $scope.data.authKey && $scope.changeEmailRequest() | |
}, $scope.changeEmail = function() { | |
$scope.data.processing = !0, gaApiAdmin.changeUserEmail($scope.userId, $scope.data.email).then(function() { | |
$scope.data.processing = !1, $scope.data.requestError = "", $scope._resolve && $scope._resolve() | |
}).catch(function(errors) { | |
$scope.data.requestError = errors[0] && errors[0].msg ? errors[0].msg : "", $scope.data.processing = !1 | |
}) | |
} | |
}), angular.module("ga.pages.admin.ui.changeStudioOwner", ["ui.router", "ga.config", "ga.ui.tagInput", "ga.ui.upload", "ga.ui.errors", "ga.api.admin", "ga.services.user", "ga.utils.helpers.focusElement", "ga.services.user"]).controller("gaPagesAdminUiChangeStudioOwnerController", function($scope, $state, gaServicesUser, gaApiAdmin) { | |
gaServicesUser.admin && gaServicesUser.adminLoggedIn && $scope.studioId || $scope._reject && $scope._reject("cancel"), $scope.data = { | |
requestError: "", | |
processing: !1 | |
}, $scope.initUserSearchSettings = { | |
focusOnInit: !0 | |
}, $scope.userSelected = {}, $scope.cancelUser = function() { | |
$scope.userSelected = {} | |
}, $scope.cancel = function() { | |
$scope._reject && $scope._reject("cancel") | |
}, $scope.changeOwner = function() { | |
$scope.userSelected.id && ($scope.data.processing = !0, gaApiAdmin.changeStudioOwner($scope.studioId, $scope.userSelected.id).then(function() { | |
$scope.data.processing = !1, $scope.data.requestError = "", $scope._resolve && $scope._resolve() | |
}).catch(function(errors) { | |
$scope.data.requestError = errors[0] && errors[0].msg ? errors[0].msg : "", $scope.data.processing = !1 | |
})) | |
} | |
}), angular.module("ga.pages.admin.home", ["ga.api.data", "ga.api.meta", "ga.ui.modal", "ga.api.admin", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.utils.date", "ga.utils.cache"]).controller("gaPagesAdminHomeController", function($rootScope, $scope, $timeout, gaApiData, gaApiMeta, gaUiModal, gaUtilsDate, gaUtilsCache, gaApiAdmin) { | |
var forceRefresh = function() { | |
gaApiAdmin.getHomeStats(!0).then(function(result) { | |
$scope.gaHomeStats = result | |
}) | |
}; | |
forceRefresh(), $scope.forceRefresh = forceRefresh | |
}), angular.module("ga.pages.admin.logs", ["ga.api.data", "ga.api.meta", "ga.ui.modal", "ga.api.admin", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.utils.date", "ga.utils.cache"]).controller("gaPagesAdminLogsController", function($rootScope, $scope, $timeout, gaApiData, gaApiMeta, gaUiModal, gaUtilsDate, gaUtilsCache, gaApiAdmin) { | |
$scope.gaLogFilters = { | |
userId: null, | |
action: [], | |
resourceId: null, | |
resourceType: [], | |
pagination: 0, | |
order: null, | |
orderBy: null | |
}; | |
var logsRefresh = function(force) { | |
gaApiAdmin.getUserLogs($scope.gaLogFilters, force).then(function(result) { | |
$scope.gaLogs = result | |
}) | |
}, | |
paginationPrev = function() { | |
$scope.gaLogFilters.pagination <= 0 ? $scope.gaLogFilters.pagination = 0 : ($scope.gaLogFilters.pagination -= 1, logsRefresh()) | |
}, | |
paginationNext = function() { | |
$scope.gaLogFilters.pagination += 1, logsRefresh() | |
}; | |
logsRefresh(!0), $scope.logsRefresh = logsRefresh, $scope.paginationPrev = paginationPrev, $scope.paginationNext = paginationNext | |
}), angular.module("ga.pages.admin.search", ["ga.api.data", "ga.api.meta", "ga.ui.modal", "ga.api.admin", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.utils.date", "ga.utils.cache", "ga.ui.notify", "ga.services.user", "ga.pages.admin.ui.searchUsers", "ga.pages.admin.ui.searchGames", "ga.pages.admin.ui.searchStudios"]).controller("gaPagesAdminSearchController", function($window, $rootScope, $scope, $timeout, $state, gaApiData, gaApiMeta, gaUiModal, gaUtilsDate, gaUtilsCache, gaApiAdmin, gaUiNotify, gaServicesUser) { | |
$scope.activeSearch = "user", $scope.adminSearch = { | |
usersFound: [], | |
gamesFound: [], | |
studiosFound: [], | |
userSearchInFocus: { | |
focus: !1 | |
}, | |
gameSearchInFocus: { | |
focus: !1 | |
}, | |
studioSearchInFocus: { | |
focus: !1 | |
} | |
}, $scope.initUserSearchSettings = { | |
focusOnInit: !0 | |
}, $scope.$watch("adminSearch.userSearchInFocus", function(newVal, oldVal) { | |
newVal !== oldVal && newVal && newVal.focus && newVal.focus === !0 && ($scope.activeSearch = "user") | |
}), $scope.$watch("adminSearch.gameSearchInFocus", function(newVal, oldVal) { | |
newVal !== oldVal && newVal && newVal.focus && newVal.focus === !0 && ($scope.activeSearch = "game") | |
}), $scope.$watch("adminSearch.studioSearchInFocus", function(newVal, oldVal) { | |
newVal !== oldVal && newVal && newVal.focus && newVal.focus === !0 && ($scope.activeSearch = "studio") | |
}), $scope.impersonateUser = function(user_id, $event) { | |
$event.stopPropagation(), $event.preventDefault(), gaApiAdmin.impersonateUser(user_id).then(function() { | |
gaServicesUser.getUserData(!1, !0).then(function() { | |
gaUiNotify.show("user impersonation started!", 4e3, "default"), $state.go("user.home") | |
}) | |
}).catch(function(errors) { | |
errors && errors.length && errors[0].msg && gaUiNotify.show(errors[0].msg, 4e3, "warning") | |
}) | |
}, $scope.selectUser = function(user_id) { | |
$state.go("admin.user", { | |
userId: user_id | |
}) | |
}, $scope.selectGame = function(game_id) { | |
$state.go("admin.game", { | |
gameId: game_id | |
}) | |
}, $scope.selectStudio = function(studio_id) { | |
$state.go("admin.studio", { | |
studioId: studio_id | |
}) | |
} | |
}), angular.module("ga.pages.admin.user", ["ga.api.data", "ga.api.meta", "ga.ui.modal", "ga.api.admin", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.utils.date", "ga.utils.cache", "ga.services.user", "ga.ui.notify", "ga.pages.admin.controller"]).controller("gaPagesAdminUserController", function($window, $rootScope, $scope, $timeout, $state, gaApiData, gaApiMeta, gaUiModal, gaUtilsDate, gaUtilsCache, gaApiAdmin, gaServicesUser, gaUiNotify, gaPagesAdminController) { | |
var user_id = $state.params.userId; | |
gaApiAdmin.getUser(user_id).then(function(data) { | |
$scope.gaUser = data | |
}), $scope.gaUserLogFilters = { | |
userId: parseInt(user_id, 10), | |
action: [], | |
resourceId: null, | |
resourceType: [], | |
pagination: 0, | |
order: null, | |
orderBy: null | |
}; | |
var impersonateUser = function(user_id) { | |
gaApiAdmin.impersonateUser(user_id).then(function() { | |
gaServicesUser.getUserData(!1, !0).then(function() { | |
gaUiNotify.show("user impersonation started!", 4e3, "default"), $state.go("user.home") | |
}) | |
}).catch(function(errors) { | |
errors && errors.length && errors[0].msg && gaUiNotify.show(errors[0].msg, 4e3, "warning") | |
}) | |
}, | |
logsRefresh = function(force) { | |
gaApiAdmin.getUserLogs($scope.gaUserLogFilters, force).then(function(result) { | |
$scope.gaUserLogs = result | |
}) | |
}, | |
showStudio = function(studioId) { | |
$state.go("admin.studio", { | |
studioId: studioId, | |
state: null | |
}) | |
}, | |
showGame = function(gameId) { | |
$state.go("admin.game", { | |
gameId: gameId, | |
state: null | |
}) | |
}, | |
paginationPrev = function() { | |
$scope.gaUserLogFilters.pagination <= 0 ? $scope.gaUserLogFilters.pagination = 0 : ($scope.gaUserLogFilters.pagination -= 1, logsRefresh()) | |
}, | |
paginationNext = function() { | |
$scope.gaUserLogFilters.pagination += 1, logsRefresh() | |
}, | |
adminChangeUserEmailModal = function(userId) { | |
gaPagesAdminController.changeUserEmailModal(userId).then(function() { | |
gaUiNotify.show("email successfully changed!", 4e3, "default"), $state.go("admin.user", { | |
userId: userId | |
}, { | |
reload: !0 | |
}) | |
}) | |
}; | |
logsRefresh(!0), $scope.logsRefresh = logsRefresh, $scope.impersonateUser = impersonateUser, $scope.paginationPrev = paginationPrev, $scope.paginationNext = paginationNext, $scope.showGame = showGame, $scope.showStudio = showStudio, $scope.adminChangeUserEmailModal = adminChangeUserEmailModal | |
}), angular.module("ga.pages.admin.game", ["ga.api.data", "ga.api.meta", "ga.ui.modal", "ga.api.admin", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.utils.date", "ga.utils.cache"]).controller("gaPagesAdminGameController", function($rootScope, $scope, $timeout, $state, gaApiData, gaApiMeta, gaUiModal, gaUtilsDate, gaUtilsCache, gaApiAdmin) { | |
var game_id = $state.params.gameId; | |
gaApiAdmin.getGame(game_id).then(function(data) { | |
$scope.gaGame = data | |
}), $scope.gaGameLogFilters = { | |
userId: null, | |
action: [], | |
resourceId: parseInt(game_id, 10), | |
resourceType: ["game"], | |
pagination: 0, | |
order: null, | |
orderBy: null | |
}, $scope.gaGameLogs = gaApiAdmin.getUserLogs($scope.gaGameLogFilters, !0); | |
var logsRefresh = function(force) { | |
gaApiAdmin.getUserLogs($scope.gaGameLogFilters, force).then(function(result) { | |
$scope.gaGameLogs = result | |
}) | |
}, | |
paginationPrev = function() { | |
$scope.gaGameLogFilters.pagination <= 0 ? $scope.gaGameLogFilters.pagination = 0 : ($scope.gaGameLogFilters.pagination -= 1, logsRefresh()) | |
}, | |
showStudio = function(studioId) { | |
$state.go("admin.studio", { | |
studioId: studioId, | |
state: null | |
}) | |
}, | |
showUser = function(userId) { | |
$state.go("admin.user", { | |
userId: userId, | |
state: null | |
}) | |
}, | |
paginationNext = function() { | |
$scope.gaGameLogFilters.pagination += 1, logsRefresh() | |
}; | |
logsRefresh(!0), $scope.logsRefresh = logsRefresh, $scope.paginationPrev = paginationPrev, $scope.paginationNext = paginationNext, $scope.showStudio = showStudio, $scope.showUser = showUser | |
}), angular.module("ga.pages.admin.studio", ["ga.api.data", "ga.api.meta", "ga.ui.modal", "ga.api.admin", "ga.ui.metricpicker", "ga.ui.dimensionpicker", "ga.utils.date", "ga.utils.cache", "ga.ui.notify", "ga.pages.admin.controller"]).controller("gaPagesAdminStudioController", function($rootScope, $scope, $timeout, $state, gaApiData, gaApiMeta, gaUiModal, gaUtilsDate, gaUtilsCache, gaApiAdmin, gaUiNotify, gaPagesAdminController) { | |
var studio_id = $state.params.studioId; | |
gaApiAdmin.getStudio(studio_id).then(function(data) { | |
$scope.gaStudio = data | |
}), $scope.gaStudioLogFilters = { | |
userId: null, | |
action: [], | |
resourceId: parseInt(studio_id, 10), | |
resourceType: ["studio"], | |
pagination: 0, | |
order: null, | |
orderBy: null | |
}; | |
var logsRefresh = function(force) { | |
gaApiAdmin.getUserLogs($scope.gaStudioLogFilters, force).then(function(result) { | |
$scope.gaStudioLogs = result | |
}) | |
}, | |
showUser = function(userId) { | |
$state.go("admin.user", { | |
userId: userId, | |
state: null | |
}) | |
}, | |
showGame = function(gameId) { | |
$state.go("admin.game", { | |
gameId: gameId, | |
state: null | |
}) | |
}, | |
paginationPrev = function() { | |
$scope.gaStudioLogFilters.pagination <= 0 ? $scope.gaStudioLogFilters.pagination = 0 : ($scope.gaStudioLogFilters.pagination -= 1, logsRefresh()) | |
}, | |
paginationNext = function() { | |
$scope.gaStudioLogFilters.pagination += 1, logsRefresh() | |
}, | |
adminChangeStudioOwnerModal = function(studioId) { | |
gaPagesAdminController.adminChangeStudioOwnerModal(studioId).then(function() { | |
gaUiNotify.show("ownership successfully changed!", 4e3, "default"), $state.go("admin.studio", { | |
studioId: studioId | |
}, { | |
reload: !0 | |
}) | |
}) | |
}; | |
logsRefresh(!0), $scope.logsRefresh = logsRefresh, $scope.paginationPrev = paginationPrev, $scope.paginationNext = paginationNext, $scope.showUser = showUser, $scope.showGame = showGame, $scope.adminChangeStudioOwnerModal = adminChangeStudioOwnerModal | |
}), angular.module("ga.pages.admin.haystack", ["uiSlider", "ga.api.meta", "ga.utils.date", "ga.ui.pager", "ga.api.userDb.authenticated.haystack"]).service("haystackService", function($q, $http, gaUtilsDate, gaApiUserDbAuthenticatedHaystack) { | |
var data; | |
this.getData = function() { | |
return data ? $q.when(data) : gaApiUserDbAuthenticatedHaystack.haystackJson().then(function(data) { | |
return data = data, $q.when(data) | |
}) | |
}, this.getPeriod = function() { | |
return this.getData().then(function(data) { | |
var period = { | |
start: 0, | |
end: 0 | |
}; | |
for (var key in data) { | |
period.start = gaUtilsDate.moment(data[key].snapshot_date).add(-7, "day").format("ddd DD MMM YYYY"), period.end = gaUtilsDate.moment(data[key].snapshot_date).format("ddd DD MMM YYYY"); | |
break | |
} | |
return $q.when(period) | |
}) | |
} | |
}).directive("haystackSlider", function() { | |
var template = '<span><label class="ga-label small">{{ meta.XXX.title }} (YYY)</label>\n<label class="ga-label inline bold small darker" style="font-size:.7em; width:10px; margin-right: 5px; text-align:right;">0</label>\n<slider class="slider small" floor="0" ceiling="{{ meta.XXX.niceMax }}" step="{{ meta.XXX.step }}" precision="0"\n ng-model-low="filters.XXX.min" ng-model-high="filters.XXX.max" style="width:125px;"></slider>\n<label class="ga-label inline bold small darker" style="font-size:.7em; width:30px; text-align:left;">{{ meta.XXX.type===\'percent\' ? \'100%\' : (meta.XXX.niceMax | formatUnitType:meta.XXX.type) }}</label>\n<input class="ga-input small" type="text" ng-model="filters.XXX.min" style="width:75px; padding: 0 5px;" />\n<input class="ga-input small" type="text" ng-model="filters.XXX.max" style="width:75px; padding: 0 5px;" /></span>\n', | |
compile = function(element, attrs) { | |
return element.html(element.get(0).innerHTML.replace(/XXX/g, attrs.meta).replace(/YYY/g, attrs.aggregation || "MEAN")), | |
function() {} | |
}; | |
return { | |
restrict: "E", | |
replace: !0, | |
scope: !1, | |
template: template, | |
compile: compile | |
} | |
}).controller("gaPagesAdminHaystackController", function(haystackService, $scope, $rootScope, $http, $q, $timeout) { | |
$rootScope.logo = "/static/ga-app/images/haystack-logo.png", $scope.$on("$destroy", function() { | |
$rootScope.logo = null | |
}), $scope.sortBy = "dau", $scope.sortReverse = !0, $scope.page = 1, $scope.perPage = 15, $scope.pageCount = 1, $scope.games = [], $scope.gamesRender = [], $scope.gamesUrl = "/v1/admin/haystack.json", $scope.filters = {}, $scope.filtersInvalid = {}, $scope.paging = { | |
pages: 1, | |
page: 1 | |
}, $scope.meta = { | |
game_id: { | |
title: "Game ID", | |
type: "number" | |
}, | |
title: { | |
title: "Game", | |
type: "string" | |
}, | |
genres: { | |
title: "Genres", | |
type: "string" | |
}, | |
dau: { | |
title: "DAU", | |
type: "number" | |
}, | |
mau: { | |
title: "MAU", | |
type: "number" | |
}, | |
day_one_retention: { | |
title: "Ret. 1", | |
type: "percent" | |
}, | |
day_seven_retention: { | |
title: "Ret. 7", | |
type: "percent" | |
}, | |
average_session_length: { | |
title: "Avg. Session Length", | |
type: "number" | |
}, | |
new_users: { | |
title: "New Users", | |
type: "number", | |
aggregation: "SUM" | |
}, | |
total_revenue: { | |
title: "Total Revenue", | |
type: "number", | |
aggregation: "SUM" | |
}, | |
paying_users: { | |
title: "Paying Users", | |
type: "number" | |
}, | |
darppu: { | |
title: "DARPPU", | |
type: "number" | |
}, | |
darpu: { | |
title: "DARPU", | |
type: "number" | |
}, | |
transactions: { | |
title: "Transactions", | |
type: "number", | |
aggregation: "SUM" | |
}, | |
active_users: { | |
title: "Active Users", | |
type: "number" | |
}, | |
logins: { | |
title: "Logins", | |
type: "number" | |
}, | |
email_report_subscribers: { | |
title: "Email Subscribers", | |
type: "number" | |
}, | |
event_count: { | |
title: "Event Count", | |
type: "number", | |
aggregation: "SUM" | |
} | |
}; | |
var setSort = function(key) { | |
$scope.page = 1, $scope.sortBy === key ? ($scope.sortReverse = !$scope.sortReverse, render()) : ($scope.sortBy = key, $scope.sortReverse = "string" === $scope.meta[key].type ? !1 : !0, render()) | |
}; | |
$scope.$watch("paging.page", function(newVal, oldVal) { | |
newVal !== oldVal && render() | |
}); | |
var setPage = function(page) { | |
page && (1 > page && (page = 1), page > $scope.pageCount && (page = $scope.pageCount), $scope.page = page, render()) | |
}; | |
$scope.dataStatus = "init"; | |
var loadData = function() { | |
$scope.dataStatus = "loading", haystackService.getData().then(function(data) { | |
haystackService.getPeriod().then(function(period) { | |
$scope.period = period, parseData(data) | |
}) | |
}) | |
}; | |
$scope.dateStart = "", $scope.dateEnd = ""; | |
var filterChangeTimer, parseData = function(data) { | |
data.forEach(function(game) { | |
for (var key in game) $scope.meta[key] && ($scope.meta[key].aggregation = $scope.meta[key].aggregation || "MEAN", $scope.meta[key].max = $scope.meta[key].max || 100, "number" === $scope.meta[key].type && ($scope.meta[key].max = $scope.meta[key].max || 100, $scope.meta[key].max = $scope.meta[key].max < game[key] ? game[key] : $scope.meta[key].max)) | |
}), angular.forEach($scope.meta, function(meta, key) { | |
if ("percent" === meta.type) return meta.niceMax = 100, meta.step = 1, void($scope.filters[key] = { | |
min: 0, | |
max: meta.niceMax | |
}); | |
if ("number" === meta.type) { | |
var i, iMax, temp = Math.ceil(meta.max); | |
for (iMax = temp.toString().length - 1, i = 1; iMax >= i; i++) temp /= 10; | |
for (temp = Math.ceil(temp), i = 1; iMax >= i; i++) temp = 10 * temp; | |
meta.niceMax = temp, meta.step = temp / 100, ("number" === meta.type || "percent" === meta.type) && ($scope.filters[key] = { | |
min: 0, | |
max: meta.niceMax | |
}) | |
} | |
}), $scope.games = data, render(), $scope.dataStatus = "" | |
}, | |
sort = function(a, b) { | |
var sortA = a[$scope.sortBy], | |
sortB = b[$scope.sortBy]; | |
return "string" === $scope.meta[$scope.sortBy].type && (sortA = sortA.toString().toLowerCase(), sortB = sortB.toString().toLowerCase()), a[$scope.sortBy] < b[$scope.sortBy] ? $scope.sortReverse ? 1 : -1 : a[$scope.sortBy] === b[$scope.sortBy] ? 0 : $scope.sortReverse ? -1 : 1 | |
}, | |
sanitizeRegExp = function(string) { | |
return string.replace(/[\?\(\)\[\]\$\^\:\.]/g, "\\$&") | |
}, | |
filter = function(game) { | |
var truthy = !0; | |
return angular.forEach($scope.filters, function(value, key) { | |
if (truthy) { | |
var meta = $scope.meta[key]; | |
switch (meta.type) { | |
case "number": | |
isNumeric(value.min) && isNumeric(value.max) && (truthy = !(game[key] > value.max || game[key] < value.min)); | |
break; | |
case "percent": | |
isNumeric(value.min) && isNumeric(value.max) && (truthy = !(100 * game[key] > value.max || 100 * game[key] < value.min)); | |
break; | |
default: | |
var pattern = new RegExp(sanitizeRegExp($scope.filters[key]), "i"); | |
truthy = (game[key] || "").toString().match(pattern) | |
} | |
} | |
}), truthy | |
}, | |
render = function() { | |
var temp = $scope.games.filter(filter).sort(sort); | |
$scope.paging.pageCount = Math.ceil(temp.length / $scope.perPage) || 1, $scope.paging.page < 1 && ($scope.paging.page = 1), $scope.paging.page > $scope.paging.pageCount && ($scope.paging.page = $scope.paging.pageCount); | |
var sliceStart = ($scope.paging.page - 1) * $scope.perPage, | |
sliceEnd = $scope.paging.page * $scope.perPage; | |
temp = temp.slice(sliceStart, sliceEnd), $scope.gamesRender = temp | |
}, | |
isNumeric = function(n) { | |
return !isNaN(parseFloat(n)) && isFinite(n) | |
}; | |
$scope.$watch("filters", function(newFilters, oldFilters) { | |
angular.equals(newFilters, oldFilters) || ($timeout.cancel(filterChangeTimer), filterChangeTimer = $timeout(render, 500)) | |
}, !0), $scope.setSort = setSort, $scope.setPage = setPage, loadData() | |
}), | |
function() { | |
var MODULE_NAME, SLIDER_TAG, angularize, bindHtml, gap, halfWidth, hide, inputEvents, module, offset, offsetLeft, pixelize, qualifiedDirectiveDefinition, roundStep, show, sliderDirective, width; | |
MODULE_NAME = "uiSlider", SLIDER_TAG = "slider", angularize = function(element) { | |
return angular.element(element) | |
}, pixelize = function(position) { | |
return "" + position + "px" | |
}, hide = function(element) { | |
return element.css({ | |
opacity: 0 | |
}) | |
}, show = function(element) { | |
return element.css({ | |
opacity: 1 | |
}) | |
}, offset = function(element, position) { | |
return element.css({ | |
left: position | |
}) | |
}, halfWidth = function(element) { | |
return element[0].offsetWidth / 2 | |
}, offsetLeft = function(element) { | |
return element[0].offsetLeft | |
}, width = function(element) { | |
return element[0].offsetWidth | |
}, gap = function(element1, element2) { | |
return offsetLeft(element2) - offsetLeft(element1) - width(element1) | |
}, bindHtml = function(element, html) { | |
return element.attr("ng-bind-html-unsafe", html) | |
}, roundStep = function(value, precision, step, floor) { | |
var decimals, remainder, roundedValue, steppedValue; | |
return null == floor && (floor = 0), null == step && (step = 1 / Math.pow(10, precision)), remainder = (value - floor) % step, steppedValue = remainder > step / 2 ? value + step - remainder : value - remainder, decimals = Math.pow(10, precision), roundedValue = steppedValue * decimals / decimals, roundedValue.toFixed(precision) | |
}, inputEvents = { | |
mouse: { | |
start: "mousedown", | |
move: "mousemove", | |
end: "mouseup" | |
}, | |
touch: { | |
start: "touchstart", | |
move: "touchmove", | |
end: "touchend" | |
} | |
}, sliderDirective = function($timeout) { | |
return { | |
restrict: "EA", | |
scope: { | |
floor: "@", | |
ceiling: "@", | |
step: "@", | |
precision: "@", | |
ngModel: "=?", | |
ngModelLow: "=?", | |
ngModelHigh: "=?", | |
translate: "&" | |
}, | |
template: '<span class="bar"></span><span class="bar selection"></span><span class="pointer"></span><span class="pointer"></span><span class="bubble selection"></span><span ng-bind-html-unsafe="translate({value: floor})" class="bubble limit"></span><span ng-bind-html-unsafe="translate({value: ceiling})" class="bubble limit"></span><span class="bubble"></span><span class="bubble"></span><span class="bubble"></span>', | |
compile: function(element, attributes) { | |
var ceilBub, cmbBub, e, flrBub, fullBar, highBub, lowBub, maxPtr, minPtr, range, refHigh, refLow, selBar, selBub, watchables, _i, _len, _ref, _ref1; | |
if (attributes.translate && attributes.$set("translate", "" + attributes.translate + "(value)"), range = null == attributes.ngModel && null != attributes.ngModelLow && null != attributes.ngModelHigh, _ref = function() { | |
var _i, _len, _ref, _results; | |
for (_ref = element.children(), _results = [], _i = 0, _len = _ref.length; _len > _i; _i++) e = _ref[_i], _results.push(angularize(e)); | |
return _results | |
}(), fullBar = _ref[0], selBar = _ref[1], minPtr = _ref[2], maxPtr = _ref[3], selBub = _ref[4], flrBub = _ref[5], ceilBub = _ref[6], lowBub = _ref[7], highBub = _ref[8], cmbBub = _ref[9], refLow = range ? "ngModelLow" : "ngModel", refHigh = "ngModelHigh", bindHtml(selBub, "'Range: ' + translate({value: diff})"), bindHtml(lowBub, "translate({value: " + refLow + "})"), bindHtml(highBub, "translate({value: " + refHigh + "})"), bindHtml(cmbBub, "translate({value: " + refLow + "}) + ' - ' + translate({value: " + refHigh + "})"), !range) | |
for (_ref1 = [selBar, maxPtr, selBub, highBub, cmbBub], _i = 0, _len = _ref1.length; _len > _i; _i++) element = _ref1[_i], element.remove(); | |
return watchables = [refLow, "floor", "ceiling"], range && watchables.push(refHigh), { | |
post: function(scope, element, attributes) { | |
var barWidth, boundToInputs, dimensions, maxOffset, maxValue, minOffset, minValue, ngDocument, offsetRange, pointerHalfWidth, updateDOM, valueRange, w, _j, _len1; | |
for (boundToInputs = !1, ngDocument = angularize(document), attributes.translate || (scope.translate = function(value) { | |
return value.value || 0 | |
}), pointerHalfWidth = barWidth = minOffset = maxOffset = minValue = maxValue = valueRange = offsetRange = void 0, dimensions = function() { | |
var value, _j, _len1, _ref2, _ref3; | |
for (null == (_ref2 = scope.precision) && (scope.precision = 0), null == (_ref3 = scope.step) && (scope.step = 1), _j = 0, _len1 = watchables.length; _len1 > _j; _j++) value = watchables[_j], scope[value] = parseFloat(scope[value]), scope[value] = isNaN(scope[value]) ? "" : scope[value], "" !== scope[value] && scope[value] > maxValue ? scope[value] = maxValue : "" !== scope[value] && scope[value] < minValue && (scope[value] = minValue); | |
return scope.diff = roundStep(scope[refHigh] - scope[refLow], parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor)), pointerHalfWidth = halfWidth(minPtr), barWidth = width(fullBar), minOffset = 0, maxOffset = barWidth - width(minPtr), minValue = parseFloat(attributes.floor), maxValue = parseFloat(attributes.ceiling), valueRange = maxValue - minValue, offsetRange = maxOffset - minOffset | |
}, updateDOM = function() { | |
var adjustBubbles, bindToInputEvents, fitToBar, percentOffset, percentToOffset, percentValue, setBindings, setPointers; | |
return dimensions(), percentOffset = function(offset) { | |
return (offset - minOffset) / offsetRange * 100 | |
}, percentValue = function(value) { | |
return (value - minValue) / valueRange * 100 | |
}, percentToOffset = function(percent) { | |
return pixelize(percent * offsetRange / 100) | |
}, fitToBar = function(element) { | |
return offset(element, pixelize(Math.min(Math.max(0, offsetLeft(element)), barWidth - width(element)))) | |
}, setPointers = function() { | |
var newHighValue, newLowValue; | |
return offset(ceilBub, pixelize(barWidth - width(ceilBub))), newLowValue = percentValue(scope[refLow]), offset(minPtr, percentToOffset(newLowValue)), offset(lowBub, pixelize(offsetLeft(minPtr) - halfWidth(lowBub) + pointerHalfWidth)), range ? (newHighValue = percentValue(scope[refHigh]), offset(maxPtr, percentToOffset(newHighValue)), offset(highBub, pixelize(offsetLeft(maxPtr) - halfWidth(highBub) + pointerHalfWidth)), offset(selBar, pixelize(offsetLeft(minPtr) + pointerHalfWidth)), selBar.css({ | |
width: percentToOffset(newHighValue - newLowValue) | |
}), offset(selBub, pixelize(offsetLeft(selBar) + halfWidth(selBar) - halfWidth(selBub))), offset(cmbBub, pixelize(offsetLeft(selBar) + halfWidth(selBar) - halfWidth(cmbBub)))) : void 0 | |
}, adjustBubbles = function() { | |
var bubToAdjust; | |
return fitToBar(lowBub), bubToAdjust = highBub, range && (fitToBar(highBub), fitToBar(selBub), gap(lowBub, highBub) < 10 ? (hide(lowBub), hide(highBub), fitToBar(cmbBub), show(cmbBub), bubToAdjust = cmbBub) : (show(lowBub), show(highBub), hide(cmbBub), bubToAdjust = highBub)), gap(flrBub, lowBub) < 5 ? hide(flrBub) : range && gap(flrBub, bubToAdjust) < 5 ? hide(flrBub) : show(flrBub), gap(lowBub, ceilBub) < 5 ? hide(ceilBub) : range && gap(bubToAdjust, ceilBub) < 5 ? hide(ceilBub) : show(ceilBub) | |
}, bindToInputEvents = function(pointer, ref, events) { | |
var onEnd, onMove, onStart; | |
return onEnd = function() { | |
return pointer.removeClass("active"), ngDocument.unbind(events.move), ngDocument.unbind(events.end) | |
}, onMove = function(event) { | |
var eventX, newOffset, newPercent, newValue; | |
return eventX = event.clientX || event.touches[0].clientX, newOffset = eventX - element[0].getBoundingClientRect().left - pointerHalfWidth, newOffset = Math.max(Math.min(newOffset, maxOffset), minOffset), newPercent = percentOffset(newOffset), newValue = minValue + valueRange * newPercent / 100, range && (ref === refLow ? newValue > scope[refHigh] && (ref = refHigh, minPtr.removeClass("active"), maxPtr.addClass("active")) : newValue < scope[refLow] && (ref = refLow, maxPtr.removeClass("active"), minPtr.addClass("active"))), newValue = roundStep(newValue, parseInt(scope.precision), parseFloat(scope.step), parseFloat(scope.floor)), scope[ref] = newValue, scope.$apply() | |
}, onStart = function(event) { | |
return pointer.addClass("active"), dimensions(), event.stopPropagation(), event.preventDefault(), ngDocument.bind(events.move, onMove), ngDocument.bind(events.end, onEnd) | |
}, pointer.bind(events.start, onStart) | |
}, setBindings = function() { | |
var bind, inputMethod, _j, _len1, _ref2, _results; | |
for (boundToInputs = !0, bind = function(method) { | |
return bindToInputEvents(minPtr, refLow, inputEvents[method]), bindToInputEvents(maxPtr, refHigh, inputEvents[method]) | |
}, _ref2 = ["touch", "mouse"], _results = [], _j = 0, _len1 = _ref2.length; _len1 > _j; _j++) inputMethod = _ref2[_j], _results.push(bind(inputMethod)); | |
return _results | |
}, setPointers(), adjustBubbles(), boundToInputs ? void 0 : setBindings() | |
}, $timeout(updateDOM), _j = 0, _len1 = watchables.length; _len1 > _j; _j++) w = watchables[_j], scope.$watch(w, updateDOM) | |
} | |
} | |
} | |
} | |
}, qualifiedDirectiveDefinition = ["$timeout", sliderDirective], (module = function(window, angular) { | |
return angular.module(MODULE_NAME, []).directive(SLIDER_TAG, qualifiedDirectiveDefinition) | |
})(window, window.angular) | |
}.call(this), angular.module("ga.pages.admin.export", ["ga.api.admin", "ga.ui.notify", "ga.pages.admin.ui.searchGames", "ga.components.moment"]).controller("gaPagesAdminExportController", function($window, $rootScope, $scope, $timeout, $http, $location, gaApiData, gaApiMeta, gaUiModal, gaUtilsDate, gaUtilsCache, gaApiAdmin, gaUiNotify, moment) { | |
$scope.inclusionGameSelected = {}, $scope.similarityGameSelected = {}, $scope.gameWithAppStoreSearchInitSettings = { | |
only_with_store_apps_defined: !0 | |
}, $scope.$watch("similarityGameSelected", function(newVal, oldVal) { | |
newVal !== oldVal && newVal && "similarity" === $scope.gameType && newVal.id && getSimilarityScoresForGame(newVal.id) | |
}), $scope.gaCountries = null; | |
var pollRedshift = function() { | |
gaApiAdmin.getRedshiftStatus().then(function(result) { | |
if (result.createTime) try { | |
result.createTime = moment.utc(result.createTime, "X").format("MMMM Do YYYY, HH:mm") | |
} catch (e) { | |
result.createTime = "non valid date returned.." | |
} | |
$scope.redshiftStatus = result | |
}).catch(function() { | |
gaUiNotify.show("An error occured getting redshift status!", 4e3, "warning") | |
}) | |
}, | |
startExport = function() { | |
if (!$scope.loading) { | |
$scope.loading = !0; | |
var currentGameIdTarget = "none"; | |
"similarity" === $scope.gameType && $scope.similarityGameSelected && $scope.similarityGameSelected.id ? currentGameIdTarget = $scope.similarityGameSelected.id : "inclusion" === $scope.gameType && $scope.inclusionGameSelected && $scope.inclusionGameSelected.id && (currentGameIdTarget = $scope.inclusionGameSelected.id); | |
var tempGameIds = []; | |
angular.forEach($scope.targetSimilarGames, function(value) { | |
tempGameIds.push(value.id) | |
}); | |
var similiarGamesIdList = tempGameIds.join(","); | |
$scope.rankCriterion = $scope.rankCriterion1 + $scope.rankCriterion2 + $scope.rankCriterion3 + $scope.rankCriterion4 === "" ? "none" : $scope.rankCriterion1 + $scope.rankCriterion2 + $scope.rankCriterion3 + $scope.rankCriterion4, gaApiAdmin.getRedshiftIdentifiers($scope.idType, $scope.rankCriterion, $scope.gameType, currentGameIdTarget, similiarGamesIdList, $scope.countryType, $scope.targetCountries).then(function(result) { | |
$scope.exportData = $scope.exportData.concat(result.urls), $scope.loading = !1 | |
}).catch(function(errors) { | |
$scope.loading = !1, errors && errors.length && errors[0].msg && gaUiNotify.show(errors[0].msg, 4e3, "warning") | |
}) | |
} | |
}, | |
getSimilarityScoresForGame = function(gameId) { | |
gaApiAdmin.getSimilarityScoresForGame(gameId).then(function(result) { | |
$scope.similarityScores = result | |
}).catch(function() { | |
gaUiNotify.show("An error occured getting similarity scores!", 4e3, "warning"), $scope.similarityScores = [] | |
}) | |
}, | |
searchGameFilter = function(game) { | |
var gameSearchString = (game.id + " " + game.title).toLowerCase(); | |
return $scope.gameListFilter && 0 !== $scope.gameListFilter.length && -1 === gameSearchString.indexOf($scope.gameListFilter) ? !1 : !0 | |
}, | |
searchCountryFilter = function(country) { | |
var countryCodeSearchString = country.code, | |
countrySearchString = country.name; | |
return $scope.countryListFilter && 0 !== $scope.countryListFilter.length && -1 === countryCodeSearchString.indexOf($scope.countryListFilter) && -1 === countrySearchString.indexOf(capitaliseFirstLetter($scope.countryListFilter)) ? !1 : !0 | |
}, | |
capitaliseFirstLetter = function(string) { | |
return string.charAt(0).toUpperCase() + string.slice(1) | |
}, | |
refresh = function() { | |
$scope.idType = "ios", $scope.gameType = "all", $scope.countryType = "all", $scope.targetCountries = "none", $scope.targetSimilarGames = "none", $scope.threshold = .5, $scope.exportData = [], $scope.loading = !1, $scope.rankCriterion1 = "", $scope.rankCriterion2 = "", $scope.rankCriterion3 = "", $scope.rankCriterion4 = "", $scope.gaCountries || $http.get("/static/json/country-codes.json").then(function(result) { | |
$scope.gaCountries = result.data | |
}), pollRedshift() | |
}, | |
assignCountries = function(countries) { | |
$scope.targetCountries = countries | |
}, | |
greaterThanThreshold = function(game) { | |
return game.score >= $scope.threshold / 100 | |
}; | |
refresh(), $scope.refresh = refresh, $scope.startExport = startExport, $scope.pollRedshift = pollRedshift, $scope.searchGameFilter = searchGameFilter, $scope.searchCountryFilter = searchCountryFilter, $scope.assignCountries = assignCountries, $scope.greaterThanThreshold = greaterThanThreshold | |
}), angular.module("ga.filters.numberFormat", ["ga.values.user"]).filter("gaNumberFormat", function($rootScope, gaValuesUser) { | |
var numberFormatSettings = { | |
1: { | |
thousandSeperator: ",", | |
comma: "." | |
}, | |
2: { | |
thousandSeperator: ".", | |
comma: "," | |
}, | |
3: { | |
thousandSeperator: "'", | |
comma: "." | |
}, | |
4: { | |
thousandSeperator: " ", | |
comma: "," | |
} | |
}, | |
getValue = function(input, noShorten, forcedPostfix, forcedFormatType) { | |
var userNumberFormat = 1; | |
forcedFormatType && forcedFormatType > 0 ? userNumberFormat = forcedFormatType : gaValuesUser.settings.numberFormat && gaValuesUser.settings.numberFormat > 0 && (userNumberFormat = gaValuesUser.settings.numberFormat); | |
var currentFormatSettings = numberFormatSettings[userNumberFormat]; | |
if (!angular.isNumber(input)) return input; | |
var postfix = "", | |
isNegative = 0 > input; | |
input = Math.abs(input); | |
var commaDecimals = 2; | |
if (1 > input && input > 0) | |
for (var tmp = input.toFixed(5).split(".")[1], i = 0; 5 > i; i++) | |
if ("0" !== tmp.substr(i, 1)) { | |
commaDecimals = i + 1; | |
break | |
} | |
if (2 > commaDecimals && (commaDecimals = 2), !noShorten) { | |
var pf = getPostfix(input, forcedPostfix); | |
input = pf.input, postfix = pf.postfix | |
} | |
var formatted = input.toFixed(commaDecimals); | |
return formatted = formatted.split("."), formatted = formatted[0].replace(/\B(?=(\d{3})+(?!\d))/g, currentFormatSettings.thousandSeperator) + currentFormatSettings.comma + formatted[1], (isNegative ? "-" : "") + formatted + postfix | |
}, | |
getValues = function(input, noShorten, forcedFormatType) { | |
var highest = Math.abs(input[input.length - 1]), | |
postfix = getPostfix(highest).postfix, | |
returnObj = {}; | |
return angular.forEach(input, function(value) { | |
returnObj[value] = getValue(value, noShorten, postfix, forcedFormatType) | |
}), returnObj | |
}, | |
getPostfix = function(input, forcedPostfix) { | |
var postfix = ""; | |
return input > 0 && (input >= 1e12 || "T" === forcedPostfix ? (postfix = "T", input /= 1e12) : input >= 1e9 || "B" === forcedPostfix ? (postfix = "B", input /= 1e9) : input >= 1e6 || "M" === forcedPostfix ? (postfix = "M", input /= 1e6) : (input >= 1e4 || "K" === forcedPostfix) && (postfix = "K", input /= 1e3)), { | |
postfix: postfix, | |
input: input | |
} | |
}; | |
return function(input, noShorten, forcedFormatType) { | |
return angular.isArray(input) ? getValues(input, noShorten, forcedFormatType) : getValue(input, noShorten, null, forcedFormatType) | |
} | |
}), angular.module("ga.filters.dateFormat", ["ga.utils.date"]).filter("gaFiltersDateFormat", function(gaUtilsDate) { | |
return function(interval) { | |
return gaUtilsDate.getIntervalTitle(interval) | |
} | |
}), angular.module("ga.filters.titleCase", []).filter("gaFiltersTitleCase", function() { | |
return function(input) { | |
var words = angular.isString(input) ? input.split(" ") : []; | |
return words = words.map(function(word) { | |
return word && (word = word.charAt(0).toUpperCase() + word.toLowerCase().slice(1)), word | |
}), words.join(" ") | |
} | |
}), angular.module("ga.filters.range", []).filter("gaFiltersRange", function() { | |
return function(input, total) { | |
total = parseInt(total, 10); | |
for (var i = 0; total > i; i++) input.push(i); | |
return input | |
} | |
}), angular.module("ga.filters.slice", []).filter("gaFiltersSlice", ["$parse", | |
function() { | |
return function(input, start, end) { | |
return start = parseInt(start, 10), end = end ? parseInt(end, 10) : end, input ? input.slice(start, end) : [] | |
} | |
} | |
]), angular.module("ga.utils.helpers", []).factory("gaHelpers", function() { | |
var isScope = function(obj) { | |
return obj && obj.$evalAsync && obj.$watch | |
}, | |
isWindow = function(obj) { | |
return obj && obj.document && obj.location && obj.alert && obj.setInterval | |
}, | |
isRegExp = function(value) { | |
return "[object RegExp]" === {}.toString.call(value) | |
}, | |
equals = function(o1, o2, ignore) { | |
if (o1 === o2) return !0; | |
if (null === o1 || null === o2) return !1; | |
if (o1 !== o1 && o2 !== o2) return !0; | |
var length, key, keySet, t1 = typeof o1, | |
t2 = typeof o2; | |
if (t1 === t2 && "object" === t1) { | |
if (!angular.isArray(o1)) { | |
if (angular.isDate(o1)) return angular.isDate(o2) && o1.getTime() === o2.getTime(); | |
if (isRegExp(o1) && isRegExp(o2)) return o1.toString() === o2.toString(); | |
if (isScope(o1) || isScope(o2) || isWindow(o1) || isWindow(o2) || angular.isArray(o2)) return !1; | |
keySet = {}; | |
for (key in o1) | |
if (!(ignore && ignore.indexOf(key) > -1 || "$" === key.charAt(0) || angular.isFunction(o1[key]))) { | |
if (!equals(o1[key], o2[key], ignore)) return !1; | |
keySet[key] = !0 | |
} | |
for (key in o2) | |
if (!(ignore && ignore.indexOf(key) > -1 || keySet.hasOwnProperty(key) || "$" === key.charAt(0) || void 0 === o2[key] || angular.isFunction(o2[key]))) return !1; | |
return !0 | |
} | |
if (!angular.isArray(o2)) return !1; | |
if ((length = o1.length) === o2.length) { | |
for (key = 0; length > key; key++) | |
if (!equals(o1[key], o2[key], ignore)) return !1; | |
return !0 | |
} | |
} | |
return !1 | |
}, | |
copy = function(object) { | |
try { | |
return JSON.parse(JSON.stringify(object)) | |
} catch (e) { | |
return angular.copy(object) | |
} | |
}, | |
parse = function(string, fallback) { | |
var object; | |
try { | |
object = JSON.parse(string) | |
} catch (e) { | |
object = fallback | |
} finally { | |
object = object || fallback || {} | |
} | |
return object | |
}, | |
serializeObject = function(object) { | |
var values = {}; | |
for (var key in object) values[key] = object[key]; | |
return values | |
}, | |
customSort = function(name, type) { | |
return function(o, p) { | |
var a, b; | |
return o && p && "object" == typeof o && "object" == typeof p ? (a = o[name], b = p[name], a === b ? "function" == typeof type ? type(o, p) : o : typeof a == typeof b ? a > b ? -1 : 1 : typeof b > typeof a ? -1 : 1) : void 0 | |
} | |
}, | |
scrollTop = function() { | |
return "undefined" != typeof window.pageYOffset ? window.pageYOffset : document.documentElement.scrollTop ? document.documentElement.scrollTop : document.body.scrollTop ? document.body.scrollTop : 0 | |
}, | |
randomNumber = function(min, max) { | |
return Math.floor(Math.random() * (max - min + 1)) + min | |
}; | |
return { | |
isScope: isScope, | |
isWindow: isWindow, | |
isRegExp: isRegExp, | |
equals: equals, | |
copy: copy, | |
parse: parse, | |
serializeObject: serializeObject, | |
customSort: customSort, | |
randomNumber: randomNumber, | |
scrollTop: scrollTop | |
} | |
}), angular.module("ga.utils.helpers.clickElement", []).directive("gaUtilsHelpersClickElement", function($parse) { | |
var linkingFunction = function($scope, $element, $attrs) { | |
var segments = $attrs.gaUtilsHelpersClickElement.split(":"), | |
event = "click", | |
el = segments[0], | |
fn = $parse(segments[1]), | |
eventFn = function(e) { | |
$scope.$apply(function() { | |
fn($scope, { | |
$event: e | |
}) | |
}) | |
}; | |
$element.on(event, el, eventFn), $scope.$on("$destroy", function() { | |
$element.off(event, el, eventFn) | |
}) | |
}; | |
return { | |
restrict: "AC", | |
link: linkingFunction, | |
scope: !1 | |
} | |
}), angular.module("ga.utils.helpers.focusElement", []).directive("gaUtilsHelpersFocusElement", function() { | |
return function($scope, $element, $attr) { | |
$scope.$watch($attr.ngFocusElement, function(value) { | |
value && ($element.select(), $element.focus()) | |
}) | |
} | |
}).directive("focusElement", function($timeout) { | |
return function($scope, $element, $attr) { | |
$scope.$watch($attr.focusElement, function(value) { | |
value && $timeout(function() { | |
$element.select(), $element.focus() | |
}, 0) | |
}) | |
} | |
}).filter("capitalize", function() { | |
return function(input) { | |
return angular.isString(input) ? input.charAt(0).toUpperCase() + input.slice(1) : input | |
} | |
}), angular.module("ga.utils.helpers.on", []).directive("gaUtilsHelpersOn", function($parse) { | |
var linkingFunction = function($scope, $element, $attrs) { | |
var segments = $attrs.gaUtilsHelpersOn.split(":"), | |
event = segments.length > 1 ? segments[0] : "click", | |
fn = $parse(segments.length > 1 ? segments[1] : segments[0]), | |
eventFn = function(e) { | |
$scope.$apply(function() { | |
fn($scope, { | |
$event: e | |
}) | |
}) | |
}; | |
$element.on(event, eventFn), $scope.$on("$destroy", function() { | |
$element.off(event, eventFn) | |
}) | |
}; | |
return { | |
restrict: "AC", | |
link: linkingFunction, | |
scope: !1 | |
} | |
}), angular.module("ga.utils.date", ["ga.components.moment", "ga.values.user"]).factory("gaUtilsDate", function($rootScope, gaValuesUser, moment) { | |
var cachedTimeZoneList = null, | |
getInterval = function(start, end, resolution, offset) { | |
start = moment(start).utc().startOf("day"), end = moment(end).utc().startOf("day"), offset = offset || 0; | |
for (var interval = [], ts = start; end > ts; ts += resolution) interval.push(ts + offset); | |
return interval | |
}, | |
generateCalendar = function(year, month, startOfWeek) { | |
for (var date = moment.utc(month + "-" + year, "M-YYYY"), shiftDay = (date.day() || 7) - ("Sunday" === startOfWeek ? 0 : 1), firstDay = date.clone().add("days", -shiftDay), calendarArray = [], y = 0; 5 >= y; y++) { | |
calendarArray[y] = []; | |
for (var x = 0; 6 >= x; x++) { | |
var tmpDate = moment(firstDay + 864e5 * (7 * y + x)).utc(); | |
calendarArray[y][x] = { | |
timestamp: tmpDate.valueOf(), | |
date: tmpDate.date(), | |
month: tmpDate.month(), | |
year: tmpDate.year(), | |
offMonth: tmpDate.month() !== date.month() | |
} | |
} | |
} | |
return calendarArray | |
}, | |
validateDate = function(str, options) { | |
if (!str) return !1; | |
var mDate; | |
return options = angular.extend({ | |
dateMin: null, | |
dateMax: null, | |
formats: null, | |
test: null | |
}, options), options.dateMin = options.dateMin || moment.utc([2e3, 0, 1]).valueOf(), mDate = moment.utc(str, options.formats), mDate.isValid() ? options.dateMin && mDate < options.dateMin ? !1 : options.dateMax && mDate > options.dateMax ? !1 : mDate : !1 | |
}, | |
getPeriodRange = function(period) { | |
var range = { | |
start: 0, | |
end: 0 | |
}; | |
switch (period) { | |
case "last24hours": | |
var start = moment().utc().startOf("hour"); | |
range.start = start.clone().add("days", -1).valueOf(), range.end = start.valueOf(); | |
break; | |
case "yesterday": | |
range.start = moment.utc().startOf("day").add("days", -1).valueOf(), range.end = moment.utc().startOf("day").add("days", -1).valueOf(); | |
break; | |
case "lastWeek": | |
range.start = moment.utc().startOf("week").add("days", -6).valueOf(), range.end = moment.utc(range.start).add("days", 6).valueOf(); | |
break; | |
case "lastMonth": | |
range.start = moment.utc().startOf("month").add("month", -1).valueOf(), range.end = moment.utc().startOf("month").add("days", -1).valueOf(); | |
break; | |
case "last30Days": | |
range.start = moment.utc().startOf("day").add("days", -31).valueOf(), range.end = moment.utc(range.start).add("days", 30).valueOf(); | |
break; | |
default: | |
var pattern = /last([0-9]+)(weeks|months|days)/gi, | |
values = pattern.exec(period); | |
if (values && 3 === values.length) { | |
var ln = values[1], | |
type = values[2]; | |
"weeks" === type ? (range.start = moment.utc().startOf("week").add("days", -7 * parseInt(ln - 1, 10) - 6).valueOf(), range.end = moment.utc(range.start).add("days", 6 + 7 * parseInt(ln - 1, 10)).valueOf()) : "months" === type && (range.start = moment.utc().startOf("month").add("month", -1 * parseInt(ln, 10)).valueOf(), range.end = moment.utc().startOf("month").add("days", -1).valueOf()) | |
} | |
} | |
return range | |
}, | |
getPeriodRangeName = function(period) { | |
var name = ""; | |
switch (period) { | |
case "yesterday": | |
name = "Yesterday"; | |
break; | |
case "lastWeek": | |
name = "Last week"; | |
break; | |
case "lastMonth": | |
name = "Last month"; | |
break; | |
default: | |
var pattern = /last([0-9]+)(weeks|months|Days)/gi, | |
values = pattern.exec(period); | |
if (3 === values.length) { | |
var ln = values[1], | |
type = values[2]; | |
"weeks" === type ? name = "Last " + parseInt(ln, 10) + " weeks" : "months" === type ? name = "Last " + parseInt(ln, 10) + " months" : "Days" === type && (name = "Last " + parseInt(ln, 10) + " days") | |
} | |
} | |
return name | |
}, | |
getPreviousPeriod = function(period) { | |
var start = moment.utc(period.start), | |
days = Math.abs(start.diff(period.end, "days")) + 1, | |
weeks = Math.ceil(days / 7); | |
start.add("weeks", -weeks); | |
var end = start.clone().add("days", days - 1).valueOf(); | |
return start = start.valueOf(), { | |
start: start, | |
end: end | |
} | |
}, | |
validateRange = function(range) { | |
return null === range || void 0 === range ? !1 : range.start && range.end && moment(range.start).isValid() && moment(range.end).isValid() ? range.start > range.end ? !1 : !0 : !1 | |
}, | |
getIntervalTitle = function(interval) { | |
var formatString = getCurrentDateFormatString(), | |
formatStringNoYear = formatString.replace("YYYY", "").trim(), | |
title = ""; | |
if (interval && interval.start && interval.end) { | |
var dateStart = moment.utc(interval.start), | |
dateEnd = moment.utc(interval.end); | |
dateStart.isValid() && dateEnd.isValid() && (interval.start === interval.end ? title = dateStart.format(formatString) : (title = dateStart.format(dateStart.year() !== dateEnd.year() ? formatString : formatStringNoYear), title = dateStart.format(dateStart.year() !== dateEnd.year() ? formatString : formatStringNoYear), title += " - " + dateEnd.format(formatString))) | |
} | |
return title | |
}, | |
getIntervalTitles = function(interval, compareInterval, html) { | |
var title = ""; | |
return interval || compareInterval ? title = compareInterval ? html ? "<div>" + getIntervalTitle(interval) + "</div><em>" + getIntervalTitle(compareInterval) + "</em>" : getIntervalTitle(interval) + " - " + getIntervalTitle(compareInterval) : getIntervalTitle(interval) : title | |
}, | |
getTimeZoneData = function(timeZoneId, offsetMinutes) { | |
var offset = moment().tz(timeZoneId).format("Z"); | |
return { | |
displayName: timeZoneId, | |
offsetMinutesUTC: offsetMinutes, | |
displayNameOffset: "(UTC " + offset + ") " + timeZoneId | |
} | |
}, | |
getTimeZonesAvailable = function(force) { | |
if (null !== cachedTimeZoneList && !force) return cachedTimeZoneList; | |
var _compareFunction = function(a, b) { | |
return a.offsetMinutesUTC < b.offsetMinutesUTC ? -1 : a.offsetMinutesUTC > b.offsetMinutesUTC ? 1 : 0 | |
}, | |
timeZones = moment.tz.zones(), | |
parsedTimeZones = []; | |
try { | |
for (var i = 0; i < timeZones.length; i += 1) { | |
var offsetTotalMinutes = parseInt(timeZones[i].zones[timeZones[i].zones.length - 1].offset, 10), | |
timeZoneEntry = getTimeZoneData(timeZones[i].displayName, offsetTotalMinutes); | |
parsedTimeZones.push(timeZoneEntry) | |
} | |
} catch (e) { | |
parsedTimeZones = [] | |
} | |
return parsedTimeZones.sort(_compareFunction), cachedTimeZoneList = parsedTimeZones, parsedTimeZones | |
}, | |
getCurrentTimeString = function(timeFormat, timeZoneId) { | |
timeZoneId = timeZoneId || gaValuesUser.settings.timeZone, timeFormat = timeFormat || gaValuesUser.settings.timeFormat; | |
var result = null; | |
return result = moment().tz(timeZoneId).format("24hour" === timeFormat ? "HH:mm" : "12hour" === timeFormat ? "hh:mm A" : "HH:mm") | |
}, | |
getCurrentDateString = function(dateFormat, timeZoneId) { | |
timeZoneId = timeZoneId || gaValuesUser.settings.timeZone, dateFormat = dateFormat || gaValuesUser.settings.dateFormat; | |
var result = null; | |
return result = moment().tz(timeZoneId).format("MDY" === dateFormat ? "MMM D. YYYY" : "DMY" === dateFormat ? "D. MMM YYYY" : "YMD" === dateFormat ? "YYYY MMM D" : "MMM D. YYYY") | |
}, | |
getCurrentTimeFormat = function() { | |
switch (gaValuesUser.settings.timeFormat) { | |
case "12hour": | |
return "h:mm A"; | |
default: | |
return "HH:mm" | |
} | |
}, | |
getCurrentDateFormat = function() { | |
switch (gaValuesUser.settings.dateFormat) { | |
case "DMY": | |
return "DD.MM.YYYY"; | |
case "MDY": | |
return "MM.DD.YYYY"; | |
default: | |
return "YYYY.MM.DD" | |
} | |
}, | |
getCurrentDateFormatString = function() { | |
switch (gaValuesUser.settings.dateFormat) { | |
case "DMY": | |
return "D. MMM YYYY"; | |
case "MDY": | |
return "MMM D. YYYY"; | |
default: | |
return "YYYY MMM D" | |
} | |
}; | |
return { | |
moment: moment, | |
generateCalendar: generateCalendar, | |
validateDate: validateDate, | |
getInterval: getInterval, | |
getPeriodRange: getPeriodRange, | |
getPreviousPeriod: getPreviousPeriod, | |
validateRange: validateRange, | |
getIntervalTitle: getIntervalTitle, | |
getIntervalTitles: getIntervalTitles, | |
getTimeZonesAvailable: getTimeZonesAvailable, | |
getTimeZoneData: getTimeZoneData, | |
getCurrentTimeString: getCurrentTimeString, | |
getCurrentDateString: getCurrentDateString, | |
getCurrentTimeFormat: getCurrentTimeFormat, | |
getCurrentDateFormat: getCurrentDateFormat, | |
getCurrentDateFormatString: getCurrentDateFormatString, | |
getPeriodRangeName: getPeriodRangeName | |
} | |
}), angular.module("ga.utils.detect", []).factory("gaDetect", function($window) { | |
var _browser, OS = function(overrideNavigator) { | |
var nav = overrideNavigator || $window.navigator.appVersion; | |
return -1 !== nav.indexOf("Win") ? "windows" : -1 !== nav.indexOf("Mac") ? "mac" : -1 !== nav.indexOf("X11") ? "unix" : -1 !== nav.indexOf("Linux") ? "linux" : "unknown" | |
}, | |
browser = function(overrideNavigator) { | |
var nav = overrideNavigator || $window.navigator; | |
return void 0 === _browser && (nav.appVersion && -1 !== nav.appVersion.indexOf("Chrome") ? _browser = "chrome" : nav.appVersion && -1 !== nav.appVersion.indexOf("Firefox") ? _browser = "firefox" : nav.appVersion && -1 !== nav.appVersion.indexOf("Apple") ? _browser = "safari" : (_browser = "unknown", "Microsoft Internet Explorer" === nav.appName ? _browser = "ie" : "Netscape" === nav.appName && nav.appVersion && nav.appVersion.indexOf("Trident") > -1 && (_browser = "ie"))), _browser | |
}, | |
cookiesEnabled = function() { | |
var cookieEnabled = navigator.cookieEnabled ? !0 : !1; | |
return "undefined" != typeof navigator.cookieEnabled || cookieEnabled || (document.cookie = "testcookie", cookieEnabled = -1 !== document.cookie.indexOf("testcookie") ? !0 : !1), cookieEnabled | |
}; | |
return { | |
OS: OS, | |
browser: browser, | |
cookiesEnabled: cookiesEnabled | |
} | |
}), angular.module("ga.utils.mailman", []).factory("gaUtilsMailman", function() { | |
function parseEventName(event) { | |
var evt = event.split(":"); | |
return 3 === evt.length ? { | |
namespace: evt[0], | |
id: evt[1], | |
event: evt[2] | |
} : null | |
} | |
function publish(event, data) { | |
var eventObj = parseEventName(event); | |
if (null !== eventObj) | |
for (var i = 0, max = subscribers.length; max > i; i++) !("*" !== eventObj.namespace && "*" !== subscribers[i].namespace && subscribers[i].namespace !== eventObj.namespace || "*" !== eventObj.id && "*" !== subscribers[i].id && subscribers[i].id !== eventObj.id || "*" !== eventObj.event && "*" !== subscribers[i].event && subscribers[i].event !== eventObj.event || !angular.isFunction(subscribers[i].callback) || !subscribers[i].callback({ | |
sender: eventObj.id, | |
event: eventObj.event | |
}, data)) | |
} | |
function request(event, callback) { | |
var eventObj = parseEventName(event); | |
if (null !== eventObj) | |
for (var i = 0, max = responders.length; max > i; i++)("*" === eventObj.namespace || "*" === responders[i].namespace || responders[i].namespace === eventObj.namespace) && ("*" === eventObj.id || "*" === responders[i].id || responders[i].id === eventObj.id) && ("*" === eventObj.event || "*" === responders[i].event || responders[i].event === eventObj.event) && angular.isFunction(responders[i].callback) && angular.isFunction(callback) && callback({ | |
sender: responders[i].id, | |
event: responders[i].event | |
}, responders[i].callback({ | |
sender: eventObj.id, | |
event: eventObj.event | |
})) | |
} | |
function subscribe(event, callback, clientid) { | |
var eventObj = parseEventName(event); | |
null !== eventObj && subscribers.push({ | |
namespace: eventObj.namespace, | |
event: eventObj.event, | |
id: eventObj.id, | |
callback: callback, | |
clientid: clientid | |
}) | |
} | |
function unsubscribeAll(clientid) { | |
var tmpArray = []; | |
angular.forEach(subscribers, function(sub) { | |
sub.clientid !== clientid && tmpArray.push(sub) | |
}), subscribers = tmpArray | |
} | |
function respond(event, callback) { | |
var eventObj = parseEventName(event); | |
null !== eventObj && responders.push({ | |
namespace: eventObj.namespace, | |
event: eventObj.event, | |
id: eventObj.id, | |
callback: callback | |
}) | |
} | |
function outOfOffice(id) { | |
suspended.push(id) | |
} | |
function back(id) { | |
var index = suspended.indexOf(id); | |
index > -1 && (suspended[index] = null) | |
} | |
function destroy() {} | |
var subscribers = [], | |
responders = [], | |
suspended = []; | |
return { | |
request: request, | |
respond: respond, | |
subscribe: subscribe, | |
unsubscribeAll: unsubscribeAll, | |
publish: publish, | |
destroy: destroy, | |
outOfOffice: outOfOffice, | |
back: back | |
} | |
}), angular.module("ga.utils.throttle", []).factory("gaUtilsThrottle", function() { | |
var debounce = function(func, wait, immediate) { | |
var timeout; | |
return function() { | |
var context = this, | |
args = arguments, | |
later = function() { | |
timeout = null, immediate || func.apply(context, args) | |
}; | |
immediate && !timeout && func.apply(context, args), clearTimeout(timeout), timeout = setTimeout(later, wait) | |
} | |
}, | |
throttle = function(func, wait) { | |
var context, args, timeout, throttling, more, result, whenDone = debounce(function() { | |
more = throttling = !1 | |
}, wait); | |
return function() { | |
context = this, args = arguments; | |
var later = function() { | |
timeout = null, more && func.apply(context, args), whenDone() | |
}; | |
return timeout || (timeout = setTimeout(later, wait)), throttling ? more = !0 : result = func.apply(context, args), whenDone(), throttling = !0, result | |
} | |
}; | |
return { | |
throttle: throttle, | |
debounce: debounce | |
} | |
}), angular.module("ga.utils.transform", ["ga.api.meta", "ga.utils.date"]).factory("gaUtilsTransform", function($injector, $q, $filter, gaUtilsDate, gaApiMeta) { | |
var parse = function(requestObject, dimensions, sortArray) { | |
var deferred = $q.defer(); | |
if (requestObject.mainQuery.filter && "*" === requestObject.mainQuery.filter.values[0]) | |
if (requestObject.mainQuery.unknownDimension === !0) { | |
var tmpDimensions = _getDimensionsFromData(requestObject), | |
tmp = _parse(requestObject, tmpDimensions); | |
deferred.resolve(_parse(requestObject, tmp.sortArray)) | |
} else $injector.invoke(function(gaApiData) { | |
gaApiData.getValue("/dimensions", requestObject.mainQuery.gameId).then(function(dimensions) { | |
deferred.resolve(_parse(requestObject, dimensions[requestObject.mainQuery.filter.dimension], sortArray)) | |
}) | |
}); | |
else deferred.resolve(requestObject.mainQuery.filter ? _parse(requestObject, requestObject.mainQuery.filter.values) : _parse(requestObject)); | |
return deferred.promise | |
}, | |
_getDimensionsFromData = function(requestObject) { | |
var dimensions = [], | |
dimensionType = requestObject.mainQuery.filter.dimension; | |
return angular.forEach(requestObject.queries, function(query, queryIndex) { | |
var queryMetric = query.metric.event, | |
typeData = requestObject.response[queryIndex].timeseries ? "timeseries" : "aggregated"; | |
angular.forEach(requestObject.response[queryIndex][typeData][queryMetric], function(dataEntry) { | |
dataEntry.dimensions && dataEntry.dimensions[dimensionType] && angular.forEach(dataEntry.dimensions[dimensionType], function(dimensionData, dimensionIndexName) { | |
dimensions.indexOf(dimensionIndexName) < 0 && dimensions.push(dimensionIndexName) | |
}) | |
}) | |
}), 0 === dimensions.length ? [] : dimensions | |
}, | |
_parse = function(requestObject, dimensions, sortArray) { | |
var doSort = !0; | |
requestObject = preprocessResponse(requestObject); | |
var parsed = { | |
aggregation: requestObject.mainQuery.aggregation, | |
aggregation_aggregated: requestObject.mainQuery.aggregation_aggregated, | |
group: requestObject.mainQuery.group, | |
normalized: requestObject.mainQuery.normalized, | |
filter: requestObject.mainQuery.filter, | |
interval: requestObject.mainQuery.interval, | |
intervalDisplay: gaUtilsDate.getIntervalTitle(requestObject.mainQuery.interval), | |
meta: { | |
type: "date", | |
unit: "date", | |
title: "Date" | |
}, | |
sortArray: [], | |
data: {} | |
}; | |
if (requestObject.mainQuery.realtime && (parsed.meta = { | |
type: "time", | |
unit: "time", | |
title: "Time", | |
tooltipType: "datetime" | |
}), requestObject.mainQuery.filter && (parsed.dimensionMeta = gaApiMeta.getDimension(requestObject.mainQuery.filter.dimension), parsed.dimensionMeta.parent && (parsed.dimensionMeta.title = parsed.dimensionMeta.parent.title + " " + parsed.dimensionMeta.title), parsed.dimensionMeta.type = parsed.dimensionMeta.type || "dimension", requestObject.mainQuery.rollup && parsed.dimensionMeta.name.indexOf("cohort_") > -1 && (parsed.dimensionMeta.name = parsed.dimensionMeta.name + "_" + requestObject.mainQuery.rollup)), requestObject.mainQuery.normalized) parsed.meta = { | |
type: requestObject.mainQuery.filter.dimension, | |
unit: "none", | |
title: "Week" | |
}, requestObject.mainQuery.rollup && requestObject.mainQuery.filter.dimension.indexOf("cohort_") > -1 && (parsed.meta.type = requestObject.mainQuery.filter.dimension + "_" + requestObject.mainQuery.rollup); | |
else if ("dimension" === requestObject.mainQuery.group) parsed.meta = gaApiMeta.getDimension(requestObject.mainQuery.filter.dimension), parsed.meta.parent && (parsed.meta.title = parsed.meta.parent.title + " " + parsed.meta.title); | |
else if ("value" === requestObject.mainQuery.group) { | |
var tmpMeta = gaApiMeta.getMetric(requestObject.mainQuery.metric[0].category, requestObject.mainQuery.metric[0].event), | |
title = gaApiMeta.getMetricDisplay(tmpMeta.category, tmpMeta.event, !0); | |
doSort = !tmpMeta.noSort, parsed.meta = { | |
type: tmpMeta.keyUnit || "string", | |
unit: "none", | |
title: title, | |
subTitle: tmpMeta.groupValuesUnit || "" | |
} | |
} | |
if (requestObject.mainQuery.compareInterval && (parsed.compare = !0, parsed.compareInterval = requestObject.mainQuery.compareInterval, parsed.compareIntervalDisplay = gaUtilsDate.getIntervalTitle(requestObject.mainQuery.compareInterval)), angular.forEach(requestObject.queries, function(query, queryIndex) { | |
if (requestObject.queries.length !== requestObject.response.length) throw "Queries length does not match response length"; | |
var dataType = "time" === query.group ? "timeseries" : "aggregated", | |
queryResponse = requestObject.response[queryIndex][dataType], | |
newQueryResponse = {}; | |
newQueryResponse = "histogram" === query.aggregation ? splitHistogram(query, queryResponse, dataType, dimensions) : queryResponse; | |
var eventNameArray = []; | |
if (angular.forEach(newQueryResponse, function(eventData, eventName) { | |
eventNameArray.push("business" === query.metric.category || "design" === query.metric.category ? { | |
event: eventName.split(":").slice(-1)[0], | |
path: eventName | |
} : eventName) | |
}), "business" === query.metric.category || "design" === query.metric.category) { | |
var isNotNumber = eventNameArray.filter(function(data) { | |
return isNaN(data.event) | |
}).length; | |
eventNameArray = eventNameArray.sort(isNotNumber ? function(a, b) { | |
return a.event && b.event ? a.event.localeCompare(b.event) : 0 | |
} : function(a, b) { | |
return (parseFloat(a.event) || 0) - (parseFloat(b.event) || 0) | |
}), eventNameArray = eventNameArray.map(function(e) { | |
return e.path | |
}) | |
} else "core" !== query.metric.category && eventNameArray.sort(); | |
angular.forEach(eventNameArray, function(eventName) { | |
var eventData = newQueryResponse[eventName]; | |
switch (dataType) { | |
case "timeseries": | |
parsed.data["timeseries" + (query.isCompare ? "Compare" : "")] = parsed.data["timeseries" + (query.isCompare ? "Compare" : "")] || [], parsed.data["timeseries" + (query.isCompare ? "Compare" : "")].push(parseTimeseries(query, eventData, eventName, dimensions)); | |
break; | |
case "aggregated": | |
parsed.data["aggregated" + (query.isCompare ? "Compare" : "")] = parsed.data["aggregated" + (query.isCompare ? "Compare" : "")] || [], parsed.data["aggregated" + (query.isCompare ? "Compare" : "")].push(parseAggregated(query, eventData, eventName, dimensions)); | |
break; | |
default: | |
throw "unknown dataType: " + dataType | |
} | |
}) | |
}), requestObject.mainQuery.filter && !requestObject.mainQuery.merged && parsed.data.aggregated && parsed.data.aggregated[0]) { | |
var tmp = sortAndSlice(requestObject.mainQuery, requestObject.mainQuery.top, parsed.data, sortArray); | |
parsed.data = tmp.data, parsed.sortArray = tmp.sortArray | |
} | |
if (requestObject.mainQuery.compareInterval && requestObject.mainQuery.mergeCompare && (parsed.data = mergeCompare(parsed.data)), "value" === requestObject.mainQuery.group) { | |
var groupedEvents = [], | |
dimensionsList = parsed.data.aggregated && parsed.data.aggregated[0].data.map(function(item) { | |
return item.dimension | |
}) || []; | |
angular.forEach(parsed.data.aggregated, function(data, eventIndex) { | |
angular.forEach(dimensionsList || [null], function(dimension, dimensionIndex) { | |
groupedEvents[dimensionIndex] = groupedEvents[dimensionIndex] || { | |
total: null, | |
cTotal: null, | |
data: [], | |
meta: { | |
title: dimension || "Value", | |
subTitle: data.meta.unitTitle ? dimension || "" : "" | |
} | |
}; | |
var dimensionData = data.data.filter(function(item) { | |
return dimension ? item.dimension === dimension : !item.dimension | |
})[0] || {}; | |
groupedEvents[dimensionIndex].data[eventIndex] = { | |
cValue: angular.isNumber(dimensionData.cValue) ? dimensionData.cValue : null, | |
value: angular.isNumber(dimensionData.value) ? dimensionData.value : null, | |
dimension: data.meta.title, | |
index: eventIndex, | |
meta: data.meta, | |
vDimension: dimension | |
} | |
}) | |
}), parsed.data.aggregated = groupedEvents | |
} | |
if ("value" === requestObject.mainQuery.group && requestObject.mainQuery.valuesTop && parsed.data.aggregated.map(function(data) { | |
doSort && (data.data = data.data.sort(function(a, b) { | |
return (b.value || 0) - (a.value || 0) | |
})), data.data = data.data.slice(0, requestObject.mainQuery.valuesTop) | |
}), requestObject.mainQuery.noAggregation) { | |
var hasTimeData = parsed.data.timeseries.some(function(item) { | |
var hasSubData = item.data.some(function(subItem) { | |
var hasSubValueData = subItem.data.some(function(subItemValue) { | |
return null !== subItemValue.total | |
}); | |
return hasSubValueData | |
}); | |
return hasSubData | |
}); | |
hasTimeData || (parsed.noData = !0) | |
} else if (parsed.data.aggregated && parsed.data.aggregated.length) { | |
var hasData = parsed.data.aggregated.some(function(item) { | |
var hasSubData = item.data.some(function(subItem) { | |
return void 0 !== subItem.cValue ? null !== subItem.value || null !== subItem.cValue : null !== subItem.value | |
}); | |
return hasSubData | |
}); | |
hasData || (parsed.noData = !0) | |
} else parsed.noData = !0; if (requestObject.mainQuery.rollup && "time" === requestObject.mainQuery.group) { | |
var rollupMeta = gaApiMeta.getMetric(requestObject.mainQuery.metric[0].category, requestObject.mainQuery.metric[0].event); | |
rollupMeta.ignore_rollup || (parsed.rollup = requestObject.mainQuery.rollup, parsed.rollupStart = { | |
main: requestObject.mainQuery.interval.start, | |
compare: requestObject.mainQuery.compareInterval ? requestObject.mainQuery.compareInterval.start : null | |
}, parsed.rollupEnd = { | |
main: requestObject.mainQuery.interval.end, | |
compare: requestObject.mainQuery.compareInterval ? requestObject.mainQuery.compareInterval.end : null | |
}) | |
} | |
return parsed | |
}, | |
preprocessResponse = function(requestObject, dimensions) { | |
var dimension = requestObject.mainQuery.filter && requestObject.mainQuery.filter.dimension; | |
angular.forEach(requestObject.response, function(data, index) { | |
var query = requestObject.queries[index]; | |
"time" === query.group ? angular.forEach(data.timeseries, function(values) { | |
values = (values || []).map(function(item) { | |
item.total = void 0 !== item.total ? item.total : "histogram" === query.aggregation ? [] : null, dimension && (item.dimensions = item.dimensions || {}, item.dimensions.total = void 0 !== item.dimensions.total ? item.dimensions.total : "histogram" === query.aggregation ? [] : null, item.dimensions[dimension] = item.dimensions[dimension] || {}, angular.forEach(dimensions, function(dimensionValue) { | |
item.dimensions[dimension][dimensionValue] = void 0 !== item.dimensions[dimension][dimensionValue] ? item.dimensions[dimension][dimensionValue] : "histogram" === query.aggregation ? [] : null | |
})) | |
}) | |
}) : angular.forEach(data.aggregated, function(values) { | |
values.total = void 0 !== values.total ? values.total : "histogram" === query.aggregation ? [] : null, dimension && (values.dimensions = values.dimensions || {}, values.dimensions.total = void 0 !== values.dimensions.total ? values.dimensions.total : "histogram" === query.aggregation ? [] : null, values.dimensions[dimension] = values.dimensions[dimension] || {}, angular.forEach(dimensions, function(dimensionValue) { | |
values.dimensions[dimension][dimensionValue] = void 0 !== values.dimensions[dimension][dimensionValue] ? values.dimensions[dimension][dimensionValue] : "histogram" === query.aggregation ? [] : null | |
})) | |
}) | |
}); | |
var tmpMeta = gaApiMeta.getMetric(requestObject.mainQuery.metric[0].category, requestObject.mainQuery.metric[0].event); | |
if ("histogram" === requestObject.mainQuery.aggregation) { | |
var keyCount = 0, | |
maxIndex = 0, | |
keyList = []; | |
requestObject.mainQuery.filter ? (angular.forEach(requestObject.response, function(data, index) { | |
data.aggregated[tmpMeta.event].dimensions.total.length > keyCount && (keyCount = data.aggregated[tmpMeta.event].dimensions.total.length, maxIndex = index) | |
}), keyList = requestObject.response[maxIndex].aggregated[tmpMeta.event].dimensions.total.map(function(item) { | |
return item.key | |
}), angular.forEach(requestObject.response, function(data) { | |
for (var i = data.aggregated[tmpMeta.event].dimensions.total.length; keyCount > i; i++) data.aggregated[tmpMeta.event].dimensions.total.push({ | |
key: keyList[i], | |
value: null | |
}) | |
})) : (angular.forEach(requestObject.response, function(data, index) { | |
data.aggregated[tmpMeta.event].total.length > keyCount && (keyCount = data.aggregated[tmpMeta.event].total.length, maxIndex = index) | |
}), keyList = requestObject.response[maxIndex].aggregated[tmpMeta.event].total.map(function(item) { | |
return item.key | |
}), angular.forEach(requestObject.response, function(data) { | |
for (var i = data.aggregated[tmpMeta.event].total.length; keyCount > i; i++) data.aggregated[tmpMeta.event].total.push({ | |
key: keyList[i], | |
value: null | |
}) | |
})) | |
} | |
return requestObject.mainQuery.filter && "*" === requestObject.mainQuery.filter.values[0] && angular.forEach(requestObject.response, function(data) { | |
data.aggregated && angular.forEach(data.aggregated, function(eventData) { | |
eventData.dimensions.total = void 0 === eventData.dimensions.total ? eventData.total : eventData.dimensions.total | |
}) | |
}), requestObject | |
}, | |
mergeCompare = function(transformData) { | |
return angular.forEach(transformData, function(typeData, type) { | |
type.indexOf("Compare") > -1 && (angular.forEach(typeData, function(data, event) { | |
var parent = transformData[type.replace("Compare", "")][event]; | |
parent && (type.indexOf("aggregated") > -1 && (parent.cTotal = data.total), parent.data = mergeEvent(parent.data, data.data)) | |
}), delete transformData[type]) | |
}), transformData | |
}, | |
mergeEvent = function(parent, child) { | |
return angular.forEach(parent, function(data, event) { | |
var childData = child[event]; | |
data.data ? angular.forEach(data.data, function(d, i) { | |
var c = childData.data[i]; | |
c && (d.cTs = c.ts, d.cTotal = c.total) | |
}) : data.cValue = angular.copy(childData.value) | |
}), parent | |
}, | |
sortAndSlice = function(query, top, data, dimensions) { | |
if (!dimensions) { | |
var sortByDimensionName = query.filter && ("cohort_month" === query.filter.dimension || "cohort_week" === query.filter.dimension); | |
data.aggregated[0].data = data.aggregated[0].data.sort(function(a, b) { | |
return sortByDimensionName ? parseInt(a.dimension, 10) - parseInt(b.dimension, 10) : (b.value || 0) - (a.value || 0) | |
}), top && (data.aggregated[0].data = data.aggregated[0].data.slice(0, top)), dimensions = data.aggregated[0].data.map(function(item) { | |
return item.dimension | |
}) | |
} | |
return angular.forEach(data, function(typeData) { | |
angular.forEach(typeData, function(dataItem) { | |
dataItem.data = dataItem.data.filter(function(item) { | |
return dimensions.indexOf(item.dimension) > -1 | |
}).sort(function(a, b) { | |
return dimensions.indexOf(a.dimension) - dimensions.indexOf(b.dimension) | |
}) | |
}) | |
}), { | |
data: data, | |
sortArray: dimensions | |
} | |
}, | |
splitHistogram = function(query, queryResponse, dataType, dimensions) { | |
var newQueryResponse = {}; | |
return angular.forEach(queryResponse, function(data) { | |
angular.forEach(dimensions || [null], function(dimension) { | |
var totalGroup = dimension ? data.dimensions.total : data.total; | |
angular.forEach(totalGroup, function(totalItem) { | |
if (newQueryResponse[totalItem.key] = newQueryResponse[totalItem.key] || { | |
total: angular.isNumber(totalItem.value) ? totalItem.value : null | |
}, dimensions) { | |
var keyData = (data.dimensions[query.filter.dimension][dimension] || []).filter(function(item) { | |
return item.key === totalItem.key | |
})[0] || {}; | |
newQueryResponse[totalItem.key].dimensions = newQueryResponse[totalItem.key].dimensions || {}, newQueryResponse[totalItem.key].dimensions[query.filter.dimension] = newQueryResponse[totalItem.key].dimensions[query.filter.dimension] || {}, newQueryResponse[totalItem.key].dimensions[query.filter.dimension][dimension] = angular.isNumber(keyData.value) ? keyData.value : null | |
} | |
}) | |
}) | |
}), newQueryResponse | |
}, | |
parseVal = function(query, value) { | |
var returnValue = null; | |
return angular.isObject(value) ? returnValue = query.metric.currency && value[query.metric.currency] ? angular.isObject(value[query.metric.currency]) ? value[query.metric.currency][query.aggregation] : value[query.metric.currency] : value[query.aggregation] : angular.isNumber(value) && (returnValue = value), angular.isNumber(returnValue) ? returnValue : null | |
}, | |
parseMeta = function(query, subEvent) { | |
var meta = gaApiMeta.getMetric(query.metric.category, query.metric.event, subEvent), | |
parsedMeta = meta.axisY; | |
return parsedMeta.inactive = query.metric.inactive || !1, parsedMeta.category = query.metric.category, parsedMeta.event = query.metric.event, subEvent !== parsedMeta.event && (parsedMeta.subEvent = subEvent), parsedMeta.title = "event_count" === query.aggregation ? meta.eventCountTitle : meta.displayTitle, parsedMeta.keyUnit = meta.keyUnit, subEvent !== parsedMeta.event && (parsedMeta.subEvent = subEvent), "event_count" === query.aggregation ? (parsedMeta.unit = meta.eventCountUnit && meta.eventCountUnit.unit || "event", parsedMeta.type = meta.eventCountUnit && meta.eventCountUnit.type || "number") : meta.currency && (parsedMeta.currency = query.metric.currency || "USD"), parsedMeta | |
}, | |
parseTimeseries = function(query, dataSerie, subEvent, dimensions) { | |
var parsed = { | |
data: [], | |
meta: parseMeta(query, subEvent) | |
}; | |
return dimensions = dimensions && !query.merged ? dimensions : [null], angular.forEach(dimensions, function(dimension, index) { | |
parsed.data[index] = parsed.data[index] || { | |
data: [] | |
}, dimension && (parsed.data[index].dimension = dimension), angular.forEach(dataSerie, function(data) { | |
var temp; | |
if (null === dimension) temp = { | |
ts: data.timestamp * (query.normalized ? 1 : 1e3) + (query.normalized ? "" : 0), | |
total: parseVal(query, data.total) | |
}; | |
else { | |
var total = data.dimensions && data.dimensions[query.filter.dimension] && data.dimensions[query.filter.dimension][dimension]; | |
query.useZeroWhenNoDimensionData && void 0 === total && null !== data.total && (total = 0), temp = { | |
ts: data.timestamp * (query.normalized ? 1 : 1e3) + (query.normalized ? "" : 0), | |
total: parseVal(query, total) | |
} | |
} | |
query.normalized && (temp.index = parseInt(temp.ts, 10)), parsed.data[index].data.push(temp) | |
}) | |
}), parsed | |
}, | |
parseAggregated = function(query, data, subEvent, dimensions) { | |
var parsed = { | |
data: [], | |
meta: parseMeta(query, subEvent), | |
total: null | |
}; | |
return dimensions = dimensions ? dimensions : [null], query.filter ? (parsed.total = parseVal(query, data.dimensions && data.dimensions.total ? data.dimensions.total : null), angular.forEach(dimensions, function(dimension) { | |
var dimensionData = data.dimensions && data.dimensions[query.filter.dimension] && data.dimensions[query.filter.dimension][dimension] ? data.dimensions[query.filter.dimension][dimension] : null; | |
parsed.data.push({ | |
dimension: dimension, | |
value: parseVal(query, dimensionData) | |
}) | |
})) : (parsed.total = parseVal(query, data.total), parsed.data.push({ | |
value: parsed.total | |
})), parsed | |
}, | |
parseFunnelData = function(data, funnel) { | |
if (!data || !data.result || !Object.keys(data.result).length) return $q.reject(funnel); | |
var filters = [], | |
dimensions = [], | |
dimensionMetas = [], | |
timeseriesData = [], | |
xValues = funnel.metrics.map(function(metric, index) { | |
return { | |
title: metric.event, | |
meta: parseMeta({ | |
metric: metric | |
}), | |
values: { | |
sum: data.result.counts.total[index], | |
diff: data.result.counts.total[index] / data.result.counts.total[index - 1] | |
} | |
} | |
}); | |
if (funnel.filters.length) { | |
funnel.filters = funnel.filters.sort(function(a, b) { | |
return a.values.length < b.values.length | |
}); | |
var sortedFilter = {}; | |
angular.forEach(data.result.counts, function(filters, key) { | |
if ("total" !== key) { | |
var tmpDimCount = []; | |
angular.forEach(filters, function(vals, name) { | |
var count = vals.reduce(function(prev, dataItem) { | |
return prev + (dataItem || 0) | |
}, 0); | |
tmpDimCount.push({ | |
name: name, | |
value: count | |
}) | |
}), tmpDimCount.sort(function(a, b) { | |
return a.value > b.value ? -1 : 1 | |
}), sortedFilter[key] = tmpDimCount | |
} | |
}), funnel.filters.forEach(function(filter) { | |
var sortedValues = sortedFilter[filter.dimension].map(function(o) { | |
return o.name | |
}); | |
filter.values.forEach(function(f) { | |
-1 === sortedValues.indexOf(f) && sortedValues.push(f) | |
}), filter.values = sortedValues | |
}), dimensions = funnel.filters.map(function(filter) { | |
return filter | |
}), angular.forEach(funnel.filters, function(filter, filterIndex) { | |
filters.push({ | |
dimension: filter.dimension, | |
values: filter.values | |
}); | |
var arrAggrData = []; | |
dimensionMetas.push(gaApiMeta.getDimension(filter.dimension) || null); | |
var calcFilterData = {}, | |
countFilterData = {}, | |
diffFilterData = {}; | |
angular.forEach(data.result.counts[filter.dimension], function(values, key) { | |
values.forEach(function(value, valueIndex) { | |
calcFilterData[key] || (calcFilterData[key] = []), countFilterData[key] || (countFilterData[key] = []), diffFilterData[key] || (diffFilterData[key] = []), diffFilterData[key].push(valueIndex > 0 ? value / values[valueIndex - 1] * 100 / 100 : null), calcFilterData[key].push(value / data.result.counts.total[0] * 100 / 100), countFilterData[key].push(value) | |
}) | |
}), filter.values.forEach(function(filterValue) { | |
var aggrData = { | |
meta: { | |
subTitle: "", | |
title: filterValue | |
}, | |
total: null, | |
data: [] | |
}; | |
aggrData = [], angular.forEach(funnel.metrics, function(metric, index) { | |
var metricMeta = parseMeta({ | |
metric: metric | |
}); | |
metricMeta.type = "percent", metricMeta.unit = "percent"; | |
var extraValues = null; | |
if (index > 0) try { | |
var extras = data.result["dwell-times"][filter.dimension][filterValue][index - 1]; | |
extraValues = { | |
count: extras.observations | |
}, countFilterData[filterValue][index - 1] > 0 && (countFilterData[filterValue][index] || (countFilterData[filterValue][index] = 0), extraValues.avgTime = "nan" !== extras.mean ? extras.mean : 0, extraValues.dropoff = countFilterData[filterValue][index - 1] ? countFilterData[filterValue][index - 1] - countFilterData[filterValue][index] : 0, extraValues.diff = diffFilterData[filterValue][index] ? diffFilterData[filterValue][index] : null) | |
} catch (e) { | |
extraValues = { | |
count: 0 | |
} | |
} else try { | |
extraValues = { | |
count: countFilterData[filterValue][index] | |
} | |
} catch (e) { | |
extraValues = { | |
count: 0 | |
} | |
} | |
aggrData.push({ | |
value: calcFilterData[filterValue] ? calcFilterData[filterValue][index] : 0, | |
extraValues: extraValues | |
}) | |
}), arrAggrData.push({ | |
data: aggrData, | |
dimension: filterValue | |
}) | |
}), timeseriesData.push({ | |
data: arrAggrData, | |
meta: dimensions[filterIndex].meta, | |
total: 0 | |
}) | |
}) | |
} else { | |
var tmpTimeseriesData = { | |
total: 1, | |
meta: { | |
title: "Value", | |
subTitle: "" | |
}, | |
data: [] | |
}; | |
angular.forEach(funnel.metrics, function(metric, index) { | |
var metricMeta = parseMeta({ | |
metric: metric | |
}); | |
metricMeta.type = "percent", metricMeta.unit = "percent"; | |
var extraValues = null; | |
if (index > 0) try { | |
var extras = data.result["dwell-times"].total[index - 1]; | |
extraValues = { | |
count: extras.observations, | |
avgTime: extras.mean && "nan" !== extras.mean ? extras.mean : null, | |
dropoff: data.result.counts.total[index - 1] - data.result.counts.total[index], | |
diff: data.result.counts.total[index] / data.result.counts.total[index - 1] | |
} | |
} catch (e) {} else extraValues = { | |
count: data.result.counts.total[index] | |
}; | |
tmpTimeseriesData.data.push({ | |
meta: metricMeta, | |
index: index, | |
value: data.result.counts.total[index] / data.result.counts.total[0] * 100 / 100, | |
values: { | |
sum: data.result.counts.total[index], | |
diff: data.result.counts.total[index] / data.result.counts.total[index - 1] | |
}, | |
extraValues: extraValues | |
}) | |
}), timeseriesData.push(tmpTimeseriesData) | |
} | |
var query = { | |
aggregation: "sum", | |
aggregation_aggregated: "sum", | |
compare: !1, | |
data: { | |
timeseries: timeseriesData | |
}, | |
xValues: xValues || null, | |
yMeta: { | |
type: "percent", | |
unit: "percent" | |
}, | |
dimensions: dimensions || null, | |
dimensionMeta: dimensionMetas || null, | |
filter: filters || null, | |
group: "metric", | |
interval: { | |
start: funnel.range.main.start, | |
end: funnel.range.main.end | |
}, | |
intervalDisplay: gaUtilsDate.getIntervalTitle(funnel.range.main), | |
meta: { | |
subTitle: "", | |
title: funnel.name, | |
type: "string", | |
unit: "none" | |
}, | |
type: "bar" | |
}, | |
overview = {}; | |
try { | |
var total = data.result.counts.total[0], | |
conversions = data.result.counts.total[data.result.counts.total.length - 1]; | |
overview = { | |
dropoffs: total - conversions, | |
conversions: conversions, | |
conversionRate: conversions / total, | |
avgTime: "nan" === data.result["total-dwell-times"].total.mean ? null : data.result["total-dwell-times"].total.mean, | |
total: total | |
} | |
} catch (e) {} | |
return { | |
query: query, | |
overview: overview | |
} | |
}, | |
parseEmptyFunnelData = function(funnel) { | |
var data = { | |
result: { | |
"total-dwell-times": { | |
total: { | |
observations: 0, | |
mean: null | |
} | |
}, | |
"dwell-times": { | |
total: [{ | |
observations: 0, | |
mean: null | |
}] | |
}, | |
counts: { | |
total: [] | |
} | |
} | |
}, | |
steps = funnel.metrics.length; | |
return funnel.metrics.forEach(function() { | |
data.result.counts.total.push(0), data.result["dwell-times"].total.push({ | |
observations: 0, | |
mean: null | |
}) | |
}), funnel.filters && funnel.filters.forEach(function(filter) { | |
data.result["total-dwell-times"][filter.dimension] || (data.result["total-dwell-times"][filter.dimension] = {}), data.result["dwell-times"][filter.dimension] || (data.result["dwell-times"][filter.dimension] = {}), data.result.counts[filter.dimension] || (data.result.counts[filter.dimension] = {}), filter.values && filter.values.forEach(function(value) { | |
data.result["total-dwell-times"][filter.dimension][value] = { | |
observations: 0, | |
mean: null | |
}, data.result["dwell-times"][filter.dimension][value] = [], data.result.counts[filter.dimension][value] = []; | |
for (var i = 1; steps > i; i++) data.result["dwell-times"][filter.dimension][value].push({ | |
observations: 0, | |
mean: null | |
}), data.result.counts[filter.dimension][value].push(0) | |
}) | |
}), parseFunnelData(data, funnel) | |
}; | |
return { | |
parse: parse, | |
_parse: _parse, | |
parseFunnelData: parseFunnelData, | |
parseEmptyFunnelData: parseEmptyFunnelData | |
} | |
}), angular.module("ga.utils.transform.chart", ["ga.api.meta", "ga.utils.helpers"]).factory("gaUtilsChartTransform", function($q, $filter, gaApiMeta, gaHelpers) { | |
var formatUnitType = $filter("formatUnitType"), | |
canvasParseSeries = function(queryData, xValues) { | |
var datasets = []; | |
return queryData.data.timeseries.forEach(function(serie) { | |
var dataset = { | |
title: serie.meta.title, | |
items: [] | |
}; | |
serie.data.forEach(function(serieItem) { | |
var datasetItem = { | |
data: [], | |
hidden: serie.meta.inactive || !1 | |
}; | |
serieItem.dimension && (datasetItem.dimension = queryData.dimensionMeta ? formatUnitType(serieItem.dimension, queryData.dimensionMeta) : serieItem.dimension), serieItem.data.forEach(function(value, i) { | |
var tmp = {}; | |
tmp.y = value.total, tmp.x = xValues[i].sort, queryData.compare && (tmp.compareY = value.cTotal), datasetItem.data.push(tmp) | |
}), dataset.items.push(datasetItem) | |
}), datasets.push(dataset) | |
}), datasets | |
}, | |
canvasParseAggregated = function(queryData, xValues) { | |
var datasets = []; | |
return queryData.data.aggregated.forEach(function(series) { | |
datasets.push(_canvasParseAggregatedSeries(series, queryData, xValues)) | |
}), datasets | |
}, | |
canvasParseMetricSeries = function(queryData, xValues) { | |
var datasets = []; | |
if (!queryData.dimensions.length) { | |
var dataset = { | |
title: null, | |
items: [] | |
}, | |
datesetItems = { | |
title: null, | |
data: [], | |
hidden: !1, | |
index: 0 | |
}; | |
return queryData.data.timeseries[0].data.forEach(function(series) { | |
datesetItems.data.push({ | |
x: series.index, | |
y: series.value, | |
extraValues: series.extraValues || null | |
}) | |
}), dataset.items.push(datesetItems), [dataset] | |
} | |
return queryData.data.timeseries.forEach(function(series, seriesIndex) { | |
series.data.forEach(function(seriesItem, seriesItemindex) { | |
datasets[seriesItemindex] || (datasets[seriesItemindex] = { | |
title: null, | |
items: [] | |
}); | |
var datasetItem = { | |
data: [], | |
hidden: series.meta.inactive || !1 | |
}; | |
seriesItem.dimension ? (datasetItem.dimension = queryData.dimensions ? formatUnitType(seriesItem.dimension, queryData.dimensions[seriesIndex].meta) : seriesItem.dimension, seriesItem.data.forEach(function(value, i) { | |
var tmp = {}; | |
tmp.y = value.value, tmp.x = xValues[i].sort, tmp.extraValues = value.extraValues || null, datasetItem.data.push(tmp) | |
})) : datasetItem.data.push({ | |
x: seriesItem.index, | |
y: seriesItem.value | |
}), datasets[seriesItemindex].items.push(datasetItem) | |
}) | |
}), datasets | |
}, | |
_canvasParseAggregatedSeries = function(series, queryData, xValues) { | |
var dataset = { | |
title: queryData.dimensionMeta ? formatUnitType(series.meta.title, queryData.dimensionMeta) : series.meta.title, | |
items: [] | |
}, | |
datasetItem = { | |
data: [] | |
}; | |
return series.data.forEach(function(serieItem, i) { | |
var tmp = {}; | |
tmp.y = serieItem.value, tmp.x = xValues[i].sort, queryData.compare && (tmp.compareY = serieItem.cValue), datasetItem.data.push(tmp) | |
}), dataset.items.push(datasetItem), dataset | |
}, | |
canvasParse = function(queriesData, stack) { | |
var parsed = {}; | |
if (!queriesData || !queriesData.left && !queriesData.right) return null; | |
angular.forEach(queriesData, function(data, position) { | |
var parsedPosition = {}; | |
data.noData && (parsedPosition.noData = !0), parsedPosition.realtime = data.realtime, parsedPosition.group = data.group, parsedPosition.type = data.type, parsedPosition.intervalTitle = data.intervalDisplay, parsedPosition.xMeta = data.meta, parsedPosition.position = position, parsedPosition.dimensions = data.dimensions || null, data.compare && (parsedPosition.compare = !0, parsedPosition.compareIntervalTitle = data.compareIntervalDisplay), queriesData.left && queriesData.right && data.data.aggregated && data.data.aggregated.length && data.data.aggregated.forEach(function(dataset) { | |
dataset.data && dataset.data.length && dataset.data.sort(gaHelpers.customSort("dimension")) | |
}), "time" === data.group ? (data.dimensionMeta && (parsedPosition.dimensionMeta = data.dimensionMeta), data.data.timeseries && data.data.timeseries.length && data.data.timeseries[0].data.length && (parsedPosition.xValues = data.data.timeseries[0].data[0].data.map(function(item) { | |
var tmp = { | |
x: item.ts, | |
sort: isNaN(parseInt(item.ts, 10)) ? item.ts : parseInt(item.ts, 10) | |
}; | |
return data.compare && (tmp.compareX = item.cTs), tmp | |
}), parsedPosition.yMeta = gaApiMeta.getUnit(data.data.timeseries[0].meta.unit), parsedPosition.yMeta.currency = data.data.timeseries[0].meta.currency, parsedPosition.yMeta.currency && (parsedPosition.yMeta.postFix = gaApiMeta.getCurrency(parsedPosition.yMeta.currency).symbol), parsedPosition.yMeta.type = data.data.timeseries[0].meta.type, parsedPosition.yMeta.unit = data.data.timeseries[0].meta.unit, parsedPosition.yValues = canvasParseSeries(data, parsedPosition.xValues))) : "dimension" === data.group ? data.data.aggregated && data.data.aggregated.length && data.data.aggregated[0].data.length && (parsedPosition.xValues = data.data.aggregated[0].data.map(function(item) { | |
var tmp = { | |
x: item.dimension, | |
sort: formatUnitType(item.dimension, data.meta) | |
}; | |
return data.compare && (tmp.compareX = item.dimension), tmp | |
}), parsedPosition.yMeta = gaApiMeta.getUnit(data.data.aggregated[0].meta.unit), parsedPosition.yMeta.type = data.data.aggregated[0].meta.type, parsedPosition.yMeta.unit = data.data.aggregated[0].meta.unit, parsedPosition.yValues = canvasParseAggregated(data, parsedPosition.xValues)) : "metric" === data.group ? (data.dimensions && (parsedPosition.dimensions = data.dimensions), parsedPosition.xValues = data.xValues.map(function(val, index) { | |
return { | |
x: val.title, | |
meta: val.meta, | |
values: val.values, | |
sort: index | |
} | |
}), parsedPosition.yMeta = gaApiMeta.getUnit(data.yMeta.unit), parsedPosition.yMeta.type = data.yMeta.type, parsedPosition.yMeta.unit = data.yMeta.unit, parsedPosition.yValues = canvasParseMetricSeries(data, parsedPosition.xValues)) : "value" === data.group && (data.dimensionMeta && (parsedPosition.dimensionMeta = data.dimensionMeta), data.data.aggregated && data.data.aggregated.length && data.data.aggregated[0].data.length && (parsedPosition.xValues = data.data.aggregated[0].data.map(function(item, index) { | |
var tmp = { | |
x: item.dimension, | |
sort: index | |
}; | |
return item.values && (tmp.values = item.values), data.compare && (tmp.compareX = item.dimension), tmp | |
}), parsedPosition.yMeta = gaApiMeta.getUnit(data.data.aggregated[0].data[0].meta.unit), parsedPosition.yMeta.type = data.data.aggregated[0].data[0].meta.type, parsedPosition.yMeta.unit = data.data.aggregated[0].data[0].meta.unit, parsedPosition.yValues = canvasParseAggregated(data, parsedPosition.xValues))), parsedPosition.xValues = parsedPosition.xValues || [], parsedPosition.yMeta = parsedPosition.yMeta || null, parsedPosition.yValues = parsedPosition.yValues || [], parsed[position] = stack ? stackEvents(parsedPosition) : parsedPosition | |
}), parsed.left && parsed.right; | |
var tmpParsed = parsed.left || parsed.right, | |
leftCount = (parsed.left ? parsed.left.xValues : []).length, | |
rightCount = (parsed.right ? parsed.right.xValues : []).length, | |
combined = { | |
realtime: tmpParsed.realtime, | |
compare: tmpParsed.compare, | |
intervalTitle: tmpParsed.intervalTitle, | |
xMeta: tmpParsed.xMeta, | |
xValues: leftCount >= rightCount ? parsed.left.xValues : parsed.right.xValues, | |
group: tmpParsed.group, | |
data: {} | |
}; | |
tmpParsed.dimensionMeta && (combined.dimensionMeta = tmpParsed.dimensionMeta), combined.compare && (combined.compareIntervalTitle = tmpParsed.compareIntervalTitle), parsed.left && (combined.data.left = { | |
datasets: parsed.left.yValues, | |
meta: parsed.left.yMeta, | |
type: parsed.left.type | |
}), parsed.left && parsed.left.noData && (combined.data.left.noData = !0), parsed.right && (combined.data.right = { | |
datasets: parsed.right.yValues, | |
meta: parsed.right.yMeta, | |
type: parsed.right.type | |
}), parsed.right && parsed.right.noData && (combined.data.right.noData = !0); | |
var cohort_filter = null; | |
if (queriesData.left ? cohort_filter = (queriesData.left || queriesData.left.rollup).filter && ((queriesData.left || queriesData.left.rollup).filter.dimension || "").match(/cohort/) : queriesData.right && (cohort_filter = (queriesData.right || queriesData.right.rollup).filter && ((queriesData.right || queriesData.right.rollup).filter.dimension || "").match(/cohort/)), !cohort_filter && queriesData.left && queriesData.left.rollup || queriesData.right && queriesData.right.rollup) { | |
var rollupStart = queriesData.left ? queriesData.left.rollupStart : queriesData.right.rollupStart, | |
rollupEnd = queriesData.left ? queriesData.left.rollupEnd : queriesData.right.rollupEnd, | |
first = combined.xValues[0], | |
last = combined.xValues[combined.xValues.length - 1]; | |
last.x = rollupEnd.main, rollupEnd.compare && (last.compareX = rollupEnd.compare), first.x = rollupStart.main, rollupEnd.compare && (first.compareX = rollupStart.compare) | |
} | |
return combined | |
}, | |
canvasChartSettings = function(data, size, stack) { | |
size = size || "default"; | |
var group = (data.left || data.right).group, | |
settings = { | |
height: 200, | |
width: 400, | |
sort: "dimension" === group ? ["y", "desc"] : ["x", "asc"], | |
sortEnabled: !1, | |
sortDatasets: "desc", | |
padding: { | |
left: 40, | |
right: 40, | |
top: 20, | |
bottom: 20 | |
}, | |
xAxis: { | |
ticks: 3 | |
}, | |
yAxis: { | |
lines: 9, | |
ticks: 3, | |
zeroLine: !0, | |
zeroArea: !0 | |
}, | |
legends: 3, | |
tooltip: !0, | |
compareToggle: !0, | |
chartData: {}, | |
inc: 0 | |
}; | |
switch ((data.left && data.left.rollup || data.right && data.right.rollup) && (settings.rollup = "weekly" === (data.left && data.left.rollup || data.right && data.right.rollup) ? "isoweek" : "month", settings.xAxis.showAll = !0), "time" !== (data.left && data.left.group || data.right && data.right.group) && (settings.xAxis.showAll = !0), size) { | |
case "home": | |
settings.height = 75, settings.width = 285, settings.padding = { | |
left: 0, | |
right: 0, | |
top: 0, | |
bottom: 0 | |
}, settings.xAxis = null, settings.yAxis = null, settings.legends = null, settings.tooltip = !1; | |
break; | |
case "small": | |
settings.height = 90, settings.width = 272, settings.padding = { | |
left: 10, | |
right: 10, | |
top: 0, | |
bottom: 0 | |
}, settings.xAxis = null, settings.yAxis = null, settings.legends = null; | |
break; | |
case "medium": | |
settings.height = 157, settings.width = 564, settings.xAxis.ticks = settings.xAxis.showAll ? 10 : 5, settings.xAxis.small = !0, settings.padding = { | |
left: 45, | |
right: 30, | |
top: 30, | |
bottom: 30 | |
}; | |
break; | |
case "mediumHigh": | |
settings.height = 238, settings.width = 564, settings.xAxis.ticks = settings.xAxis.showAll ? 10 : 5, settings.xAxis.small = !0, settings.padding = { | |
left: 40, | |
right: 30, | |
top: 30, | |
bottom: 27 | |
}; | |
break; | |
case "largeHigh": | |
settings.height = 534, settings.width = 1148, settings.xAxis.ticks = settings.xAxis.showAll ? 10 : 5, settings.legends = 5, settings.padding = { | |
left: 50, | |
right: 50, | |
top: 30, | |
bottom: 50 | |
}; | |
break; | |
case "large": | |
settings.height = 450, settings.width = 1148, settings.xAxis.ticks = settings.xAxis.showAll ? 10 : 5, settings.legends = 5, settings.padding = { | |
left: 50, | |
right: 50, | |
top: 30, | |
bottom: 50 | |
}; | |
break; | |
case "explore": | |
settings.height = 460, settings.width = 1150, settings.minWidth = 1150, settings.xAxis.ticks = settings.xAxis.showAll ? 10 : 5, settings.compareToggle = !1, settings.legends = 5, settings.sortEnabled = !0, settings.padding = { | |
left: 50, | |
right: 50, | |
top: 30, | |
bottom: 50 | |
}; | |
break; | |
case "quality": | |
settings.width = 1105, settings.height = 430, settings.xAxis.ticks = settings.xAxis.showAll ? 10 : 5, settings.legends = 5, settings.padding = { | |
left: 50, | |
right: 20, | |
top: 30, | |
bottom: 20 | |
}; | |
break; | |
case "mini": | |
settings.width = 130, settings.height = 65, settings.xAxis = !1, settings.yAxis = !1, settings.legends = 0, settings.compareToggle = !1, settings.tooltip = !1, settings.noProgress = !0, settings.padding = { | |
left: 0, | |
right: 0, | |
top: 0, | |
bottom: 0 | |
}; | |
break; | |
case "funnel": | |
settings.height = 460, settings.width = 1150, settings.minWidth = 1150, settings.xAxis.ticks = settings.xAxis.showAll ? 10 : 5, settings.compareToggle = !1, settings.legends = 5, settings.disableLegendClick = !0, settings.sortEnabled = !0, settings.bars = { | |
width: 90, | |
padding: 80, | |
diffContainer: !0 | |
}, settings.yAxis = { | |
min: 0, | |
max: 1 | |
}, settings.padding = { | |
left: 50, | |
right: 50, | |
top: 50, | |
bottom: 50 | |
}, settings.innerPadding = { | |
left: 20 | |
}; | |
break; | |
default: | |
angular.isObject(size) && (settings = size) | |
} | |
return settings.chartData = canvasParse(data, stack), settings.chartData.data.right && (settings.compareToggle = !1), settings.xAxis && settings.xAxis.ticks && settings.chartData.xValues && settings.chartData.xValues.length <= 7 && (settings.xAxis.ticks = 7), settings.sortEnabled && ("time" === group ? (settings.sort = ["x", "asc"], settings.sortEnabled = !1) : settings.chartData.data.left && settings.chartData.data.right ? (settings.sort = ["x", "asc"], settings.sortEnabled = "x") : (settings.chartData.data.left || settings.chartData.data.right).datasets.length > 1 && (settings.sort = ["x", "asc"], settings.sortEnabled = "x")), settings | |
}, | |
setSort = function(settings, sort) { | |
return settings.sortEnabled === !1 ? (settings.sort = ["x", "asc"], settings) : "x" === settings.sortEnabled && "y" === sort[0] ? (settings.sort = ["x", "asc"], settings) : (settings.sort = sort, settings) | |
}, | |
stackEvents = function(data) { | |
var newDatasets = []; | |
return data.yValues.forEach(function(dataset) { | |
dataset.items.forEach(function(datasetItem, index) { | |
newDatasets[index] = newDatasets[index] || { | |
position: data.position, | |
title: data.dimensionMeta ? formatUnitType(datasetItem.dimension, data.dimensionMeta) : datasetItem.dimension, | |
type: data.type, | |
items: [] | |
}, datasetItem.index = dataset.index || 0, "metric" === data.group ? (datasetItem.title = datasetItem.dimension, data.dimensions && data.dimensions[index] && (newDatasets[index].meta = data.dimensions[index].meta, newDatasets[index].title = data.dimensions[index].meta.title)) : datasetItem.dimension ? datasetItem.dimension = dataset.title : (delete datasetItem.dimension, datasetItem.title = dataset.title), newDatasets[index].items.push(datasetItem) | |
}) | |
}), delete data.dimensionMeta, data.yValues = newDatasets, data | |
}; | |
return { | |
canvasChartSettings: canvasChartSettings, | |
canvasParse: canvasParse, | |
setSort: setSort | |
} | |
}), angular.module("ga.utils.transform.grid", ["ga.api.meta", "ga.utils.date"]).factory("gaUtilsGridTransform", function(gaApiMeta, $filter, gaUtilsDate) { | |
var formatUnitType = $filter("formatUnitType"), | |
parse = function(queryResponse, nosplit) { | |
var parsed = { | |
header: { | |
values: [] | |
}, | |
footer: { | |
values: [] | |
}, | |
rows: [], | |
meta: { | |
axis: {}, | |
cols: [], | |
dimension: null | |
} | |
}; | |
queryResponse.dimensionMeta && (parsed.meta.dimension = queryResponse.dimensionMeta); | |
var aggregationName = function() { | |
var aggr = queryResponse.aggregation_aggregated || queryResponse.aggregation; | |
switch (aggr) { | |
case "sum": | |
return "SUM"; | |
case "mean": | |
return "MEAN"; | |
case "event_count": | |
return "Count" | |
} | |
}; | |
return parsed.header.axis = { | |
value: queryResponse.meta.title, | |
subValue: queryResponse.meta.subTitle | |
}, parsed.footer.axis = { | |
value: aggregationName() | |
}, ".*" === parsed.header.axis.value && (parsed.header.axis.value = "All (.*)"), parsed.meta.axis = queryResponse.meta, parsed = "time" === queryResponse.group ? _parseTime(queryResponse, parsed, nosplit) : "metric-dimension" === queryResponse.group ? _parseMetricDimension(queryResponse, parsed) : "metric" === queryResponse.group ? _parseMetric(queryResponse, parsed) : _parseDefault(queryResponse, parsed, nosplit), parsed.header.values.length || (parsed.header.values.push({ | |
col: 1, | |
value: " " | |
}), parsed.footer.values.push({ | |
col: 1, | |
value: " " | |
}), parsed.rows.push({ | |
axis: { | |
value: null | |
}, | |
values: [{ | |
value: null | |
}] | |
})), queryResponse.rollup && (parsed.rollup = !0), parsed | |
}, | |
_parseTime = function(queryResponse, parsed, nosplit) { | |
!nosplit && queryResponse.data && queryResponse.data.aggregated && queryResponse.data.timeseries && 1 === queryResponse.data.timeseries.length && 1 === queryResponse.data.timeseries[0].data.length && (queryResponse.compare && (queryResponse.data.timeseries[1] = angular.copy(queryResponse.data.timeseries[0]), queryResponse.data.timeseries[1].meta.title = "Comparison", queryResponse.data.timeseries[1].meta.compare = !0, queryResponse.data.timeseries[0].data[0].data.map(function(item) { | |
item.cTs = null, item.cTotal = null | |
}), queryResponse.data.timeseries[1].data[0].data.map(function(item) { | |
item.ts = item.cTs, item.total = item.cTotal, item.cTs = null, item.cTotal = null | |
}), queryResponse.data.aggregated[1] = angular.copy(queryResponse.data.aggregated[0]), queryResponse.data.aggregated[1].data[0].value = queryResponse.data.aggregated[1].data[0].cValue, queryResponse.data.aggregated[1].data[0].cValue = null), queryResponse.data.aggregated[0].data[0].cValue = null, queryResponse.compare = !1); | |
var colIndex = 0; | |
return angular.forEach(queryResponse.data.aggregated, function(event) { | |
angular.forEach(event.data, function(data) { | |
parsed.footer.values.push({ | |
value: angular.isNumber(data.value) ? data.value : null, | |
cValue: angular.isNumber(data.cValue) ? data.cValue : null | |
}), colIndex++ | |
}) | |
}), colIndex = 0, angular.forEach(queryResponse.data.timeseries, function(event) { | |
angular.forEach(event.data, function(data) { | |
parsed.meta.cols.push(event.meta), data.dimension && parsed.meta.dimension && "dimension" !== parsed.meta.dimension.type && (data.dimensionTitle = formatUnitType(data.dimension, parsed.meta.dimension)), queryResponse.dimensionMeta && !data.dimensionTitle && data.dimension && (data.dimensionTitle = formatUnitType(data.dimension, queryResponse.dimensionMeta)), parsed.header.values.push({ | |
col: colIndex + 1, | |
value: event.meta.title, | |
subValue: data.dimensionTitle || data.dimension || null, | |
dimensionValue: data.dimension || null | |
}), angular.forEach(data.data, function(dataItem, rowIndex) { | |
var display, cDisplay, cohort_filter = queryResponse.filter && queryResponse.filter.dimension.match(/cohort/); | |
if (!cohort_filter && queryResponse.rollup && "time" === queryResponse.group && "normalized" !== queryResponse.group) { | |
0 === rowIndex && (dataItem.ts = queryResponse.interval.start, queryResponse.compare && (dataItem.cTs = queryResponse.compareInterval.start)); | |
var rollup = "weekly" === queryResponse.rollup ? "isoweek" : "month"; | |
cDisplay = null, data.data.length === rowIndex + 1 ? (dataItem.ts = queryResponse.interval.end, queryResponse.compare && (dataItem.cTs = queryResponse.compareInterval.end), display = gaUtilsDate.getIntervalTitle({ | |
start: gaUtilsDate.moment.utc(dataItem.ts).startOf(rollup).valueOf(), | |
end: dataItem.ts | |
})) : display = gaUtilsDate.getIntervalTitle({ | |
start: dataItem.ts, | |
end: gaUtilsDate.moment.utc(dataItem.ts).endOf(rollup).valueOf() | |
}), parsed.rows[rowIndex] = parsed.rows[rowIndex] || { | |
axis: { | |
value: dataItem.ts, | |
cValue: dataItem.cTs || null, | |
index: dataItem.index, | |
display: display | |
}, | |
values: [] | |
} | |
} else parsed.rows[rowIndex] = parsed.rows[rowIndex] || { | |
axis: { | |
value: dataItem.ts, | |
cValue: dataItem.cTs || null, | |
index: dataItem.index | |
}, | |
values: [] | |
}; | |
var share = null, | |
cShare = null; | |
if ("percent" !== event.meta.type && parsed.footer.values[colIndex]) { | |
if (angular.isNumber(dataItem.total) && 0 !== dataItem.total) | |
if ("number" === event.meta.type && "mean" === queryResponse.aggregation_aggregated) { | |
var diff = dataItem.total - parsed.footer.values[colIndex].value, | |
diffTotal = diff / parsed.footer.values[colIndex].value; | |
share = Math.abs(diffTotal) > 10 ? 10 : diffTotal | |
} else "number" === event.meta.type && (share = dataItem.total / parsed.footer.values[colIndex].value); | |
if (angular.isNumber(dataItem.cTotal) && 0 !== dataItem.cTotal) | |
if ("number" === event.meta.type && "mean" === queryResponse.aggregation_aggregated) { | |
var cDiff = dataItem.cTotal - parsed.footer.values[colIndex].cValue, | |
cDiffTotal = cDiff / parsed.footer.values[colIndex].cValue; | |
cShare = Math.abs(cDiffTotal) > 10 ? 10 : cDiffTotal | |
} else "number" === event.meta.type && (cShare = dataItem.cTotal / parsed.footer.values[colIndex].cValue) | |
} | |
parsed.rows[rowIndex].values[colIndex] = { | |
value: angular.isNumber(dataItem.total) ? dataItem.total : null, | |
cValue: angular.isNumber(dataItem.cTotal) ? dataItem.cTotal : null, | |
share: share, | |
cShare: cShare, | |
shareMeta: { | |
type: "percent", | |
unit: "percent" | |
} | |
} | |
}), colIndex++ | |
}) | |
}), parsed | |
}, | |
_parseDefault = function(queryResponse, parsed, nosplit) { | |
return !nosplit && queryResponse.data && queryResponse.data.aggregated && 1 === queryResponse.data.aggregated.length && (queryResponse.compare && (queryResponse.data.aggregated[1] = angular.copy(queryResponse.data.aggregated[0]), queryResponse.data.aggregated[1].meta.title = "Comparison", queryResponse.data.aggregated[1].meta.compare = !0, queryResponse.data.aggregated[1].total = queryResponse.data.aggregated[1].cTotal, queryResponse.data.aggregated[1].cTotal = null, queryResponse.data.aggregated[1].data.map(function(item) { | |
item.value = item.cValue, item.cValue = null | |
})), queryResponse.data.aggregated[0].cTotal = null, queryResponse.data.aggregated[0].data.map(function(item) { | |
item.cValue = null | |
}), queryResponse.compare = !1), angular.forEach(queryResponse.data.aggregated, function(colData, colIndex) { | |
parsed.meta.cols.push(colData.meta); | |
var title = colData.meta.title; | |
"value" === queryResponse.group && queryResponse.dimensionMeta && (title = $filter("formatUnitType")(colData.meta.title, queryResponse.dimensionMeta)), parsed.header.values.push({ | |
col: colIndex + 1, | |
value: title, | |
subValue: colData.meta.subTitle | |
}), parsed.footer.values.push({ | |
value: colData.total, | |
cValue: colData.cTotal | |
}), angular.forEach(colData.data, function(rowData, rowIndex) { | |
var dimensionMeta = gaApiMeta.getDimension(rowData.dimension); | |
parsed.rows[rowIndex] = parsed.rows[rowIndex] || { | |
axis: { | |
value: dimensionMeta.title, | |
index: rowData.index, | |
event: rowData.meta ? rowData.meta.subEvent : null | |
}, | |
values: [] | |
}; | |
var share = null, | |
cShare = null; | |
if (parsed.footer.values[colIndex]) { | |
if (angular.isNumber(rowData.value) && 0 !== rowData.value) | |
if ("percent" === colData.meta.type || "number" === colData.meta.type && "mean" === queryResponse.aggregation_aggregated) { | |
var diff = rowData.value - parsed.footer.values[colIndex].value, | |
diffTotal = diff / parsed.footer.values[colIndex].value; | |
share = Math.abs(diffTotal) > 10 ? 10 : diffTotal | |
} else "number" === colData.meta.type && (share = rowData.value / parsed.footer.values[colIndex].value); | |
if (angular.isNumber(rowData.cValue) && 0 !== rowData.cValue) | |
if ("percent" === colData.meta.type || "number" === colData.meta.type && "mean" === queryResponse.aggregation_aggregated) { | |
var cDiff = rowData.cValue - parsed.footer.values[colIndex].cValue, | |
cDiffTotal = cDiff / parsed.footer.values[colIndex].cValue; | |
cShare = Math.abs(cDiffTotal) > 10 ? 10 : cDiffTotal | |
} else "number" === colData.meta.type && (cShare = rowData.cValue / parsed.footer.values[colIndex].cValue) | |
} | |
parsed.rows[rowIndex].values[colIndex] = { | |
value: rowData.value, | |
cValue: rowData.cValue, | |
meta: rowData.meta, | |
share: share, | |
cShare: cShare, | |
shareMeta: { | |
type: "percent", | |
unit: "percent" | |
} | |
} | |
}) | |
}), parsed | |
}, | |
_parseMetric = function(queryResponse, parsed) { | |
return parsed.header.axis = { | |
value: "Steps", | |
subValue: null | |
}, parsed = queryResponse.dimensions && queryResponse.dimensions.length ? _parseMetricWithDimensions(queryResponse, parsed) : _parseMetricWithoutDimensions(queryResponse, parsed) | |
}, | |
_parseMetricWithDimensions = function(queryResponse, parsed) { | |
parsed.header.values = [{ | |
col: 1, | |
value: "Total", | |
subValue: null, | |
dimensionValue: null | |
}]; | |
var activeDimensionIndex = queryResponse.activeDimensionIndex || 0; | |
return queryResponse.dimensions[activeDimensionIndex].values.some(function(headerVal, headerIndex) { | |
parsed.header.values.push({ | |
col: headerIndex + 2, | |
value: $filter("formatUnitType")(headerVal, queryResponse.dimensions[activeDimensionIndex].meta), | |
subValue: null, | |
dimensionValue: null | |
}) | |
}), parsed.rows = [], angular.forEach(queryResponse.data.timeseries[activeDimensionIndex].data, function(row, colIndex) { | |
row.data.some(function(objData, rowIndex) { | |
parsed.rows[rowIndex] || (parsed.rows[rowIndex] = { | |
axis: { | |
index: colIndex, | |
value: queryResponse.xValues[rowIndex].meta.title, | |
fullValue: _parseMetricFullPath(queryResponse.xValues[rowIndex].meta) | |
}, | |
values: [{ | |
value: queryResponse.xValues[rowIndex].values.sum, | |
share: queryResponse.xValues[rowIndex].values.diff, | |
shareMeta: { | |
type: "percent", | |
unit: "percent" | |
} | |
}] | |
}), parsed.rows[rowIndex].values[colIndex + 1] || (parsed.rows[rowIndex].values[colIndex + 1] = {}), parsed.rows[rowIndex].values[colIndex + 1] = { | |
value: objData.extraValues.count, | |
share: objData.extraValues.diff, | |
shareMeta: { | |
type: "percent", | |
unit: "percent" | |
}, | |
extraValues: objData.extraValues | |
} | |
}) | |
}), parsed | |
}, | |
_parseMetricWithoutDimensions = function(queryResponse, parsed) { | |
return parsed.header.values = [{ | |
col: 1, | |
value: "Converting users", | |
subValue: null, | |
dimensionValue: null | |
}, { | |
col: 2, | |
value: "Dropoff", | |
subValue: null, | |
dimensionValue: null | |
}, { | |
col: 3, | |
value: "Avg. conversion time", | |
subValue: null, | |
dimensionValue: null | |
}], parsed.meta.cols = [{ | |
type: "number", | |
unit: "user" | |
}, { | |
type: "number", | |
unit: "user" | |
}, { | |
type: "seconds", | |
unit: "seconds" | |
}], parsed.rows = [], angular.forEach(queryResponse.data.timeseries[0].data, function(row, rowIndex) { | |
parsed.rows.push({ | |
axis: { | |
index: rowIndex, | |
value: row.meta ? row.meta.title : "", | |
fullValue: _parseMetricFullPath(row.meta) | |
}, | |
values: [{ | |
value: row.extraValues.count, | |
share: row.extraValues.diff, | |
shareMeta: { | |
type: "percent", | |
unit: "percent" | |
}, | |
extraValues: row.extraValues | |
}, { | |
value: row.extraValues.dropoff || null, | |
extraValues: row.extraValues | |
}, { | |
value: row.extraValues.avgTime || null, | |
extraValues: row.extraValues | |
}] | |
}) | |
}), parsed | |
}, | |
_parseMetricDimension = function(queryResponse, parsed) { | |
var activeDimensionIndex = queryResponse.activeDimensionIndex || 0, | |
dimensionObj = queryResponse.dimensions[activeDimensionIndex]; | |
return parsed.meta.axis = dimensionObj.meta, parsed.header.axis = { | |
value: dimensionObj.meta.title, | |
subValue: null | |
}, parsed.footer = { | |
axis: { | |
value: "Total" | |
}, | |
values: [] | |
}, queryResponse.xValues.some(function(xVal, xValIndex) { | |
parsed.footer.values.push({ | |
value: xVal.values.sum, | |
share: xVal.values.diff, | |
shareMeta: { | |
type: "percent", | |
unit: "percent" | |
} | |
}), parsed.header.values.push({ | |
col: xValIndex + 1, | |
value: xVal.meta ? xVal.meta.title : "", | |
subValue: null, | |
dimensionValue: null | |
}) | |
}), angular.forEach(queryResponse.data.timeseries[activeDimensionIndex].data, function(row, rowIndex) { | |
var tmpRow = { | |
axis: { | |
index: rowIndex, | |
value: row.dimension | |
}, | |
values: row.data.map(function(objData) { | |
return { | |
value: objData.extraValues.count, | |
share: objData.extraValues.diff, | |
shareMeta: { | |
type: "percent", | |
unit: "percent" | |
}, | |
extraValues: objData.extraValues | |
} | |
}) | |
}; | |
parsed.rows.push(tmpRow) | |
}), parsed | |
}, | |
_parseMetricFullPath = function(meta) { | |
var str = ""; | |
return meta.category && (str = meta.category.charAt(0).toUpperCase() + meta.category.slice(1) + " > "), str += meta.event.replace(/\:/gi, " > ") | |
}, | |
flipData = function(data) { | |
var meta = { | |
axis: { | |
title: data.meta.dimension.title, | |
type: data.meta.dimension.type, | |
unit: data.meta.dimension.unit | |
}, | |
cols: [], | |
dimension: data.meta.dimension | |
}, | |
header = { | |
axis: { | |
value: data.meta.dimension.title, | |
subValue: "" | |
}, | |
values: [] | |
}, | |
footer = { | |
axis: { | |
value: "MEAN" | |
}, | |
values: [] | |
}, | |
rows = []; | |
return angular.forEach(data.header.values, function(row, key) { | |
rows.push({ | |
axis: { | |
index: key, | |
value: row.subValue, | |
dimensionValue: row.dimensionValue | |
}, | |
values: [] | |
}) | |
}), angular.forEach(data.rows, function(row, key) { | |
header.values.push({ | |
col: key + 1, | |
value: $filter("formatUnitType")(row.axis.value, data.meta.axis) | |
}), angular.forEach(rows, function(_row, index) { | |
_row.values.push(row.values[index]) | |
}); | |
var sum = 0, | |
count = 0; | |
angular.forEach(row.values, function(r) { | |
null !== r.value && void 0 !== r.value && (sum += r.value, count++) | |
}), footer.values.push({ | |
value: sum / count || null, | |
sum: sum || null | |
}), meta.cols.push(data.meta.cols[0]) | |
}), data.header = header, data.footer = footer, data.rows = rows, data.meta = meta, data | |
}; | |
return { | |
parse: parse, | |
flipData: flipData | |
} | |
}), angular.module("ga.utils.urlState", ["ui.router"]).factory("gaUtilsUrlState", function($window, $state) { | |
var setState = function(obj) { | |
obj = angular.copy(obj); | |
var params = angular.copy($state.params), | |
stringified = JSON.stringify(obj); | |
params.state = "{}" === stringified ? null : btoa(JSON.stringify(obj)), $state.go($state.current.name, params, { | |
notify: !1 | |
}) | |
}, | |
getState = function() { | |
var state = $state.params.state; | |
try { | |
state = JSON.parse(atob(state)) | |
} catch (e) {} | |
return state || {} | |
}; | |
return { | |
setState: setState, | |
getState: getState | |
} | |
}), angular.module("ga.cache-buster", ["ga.config", "ga.utils.detect"]).config(function($provide, $httpProvider) { | |
$provide.factory("cacheBuster", function($templateCache, gaConfig, gaDetect) { | |
function getBuster() { | |
return gaConfig.cacheBuster() | |
} | |
return { | |
request: function(config) { | |
if ($templateCache.get(config.url)) return config; | |
var prefix = "?"; | |
return -1 !== config.url.search("\\?") && (prefix = "&"), config.url += prefix += "_=" + getBuster(), "ie" === gaDetect.browser() && (config.url += "&ie=" + Math.random().toString().replace("0.", "")), config | |
} | |
} | |
}), $httpProvider.interceptors.push("cacheBuster") | |
}), angular.module("ga.utils.cache", ["ga.config"]).factory("gaUtilsCache", function($window, $cacheFactory, gaConfig) { | |
function _byteLength(str) { | |
var escapedStr = encodeURI(str), | |
count = 0; | |
if (-1 !== escapedStr.indexOf("%")) { | |
count = escapedStr.split("%").length - 1, 0 === count && count++; | |
var tmp = escapedStr.length - 3 * count; | |
count += tmp | |
} else count = escapedStr.length; | |
return count | |
} | |
var cache, cacheId = gaConfig.cache.id, | |
cacheExpire = gaConfig.cache.expire, | |
_defaultGet = function() { | |
return null | |
}, | |
_defaultPut = function() { | |
return null | |
}, | |
_defaultRemove = function() { | |
return null | |
}, | |
_defaultRemoveAll = function() { | |
return null | |
}; | |
switch (gaConfig.cache.type) { | |
case "localStorage": | |
cache = $window.localStorage, _defaultGet = function(key) { | |
return cache.getItem(key) | |
}, _defaultPut = function(key, value) { | |
cache.setItem(key, value) | |
}, _defaultRemove = function(key) { | |
cache.removeItem(key) | |
}, _defaultRemoveAll = function() { | |
cache.clear() | |
}; | |
break; | |
case "angular": | |
cache = $cacheFactory(cacheId), _defaultGet = cache.get, _defaultPut = cache.put, _defaultRemove = cache.remove, _defaultRemoveAll = cache.removeAll; | |
break; | |
default: | |
cache = null | |
} | |
var get = function(key, cacheType) { | |
var localGet = function() { | |
return null | |
}; | |
localGet = cacheType ? getFn(cacheType) : _defaultGet, key = cacheId + "." + key; | |
var value = localGet(key); | |
try { | |
value = JSON.parse(value) | |
} catch (e) { | |
value = null | |
} | |
return value && "object" == typeof value && value.expire && value.expire > Date.now() ? value.data : null | |
}, getFn = function(cacheType) { | |
var fn = function() { | |
return null | |
}, | |
c = null; | |
switch (cacheType) { | |
case "localStorage": | |
c = $window.localStorage, fn = function(key) { | |
return c.getItem(key) | |
}; | |
break; | |
case "angular": | |
c = $cacheFactory(cacheId), fn = cache.get | |
} | |
return fn | |
}, put = function(key, value, cacheType, expire) { | |
var localPut = function() { | |
return null | |
}, | |
localExpire = expire || cacheExpire; | |
localPut = cacheType ? putFn(cacheType) : _defaultPut, key = cacheId + "." + key, value = { | |
expire: Date.now() + localExpire, | |
data: value | |
}, localPut(key, JSON.stringify(value)) | |
}, putFn = function(cacheType) { | |
var fn = function() { | |
return null | |
}, | |
c = null; | |
switch (cacheType) { | |
case "localStorage": | |
c = $window.localStorage, fn = function(key, value) { | |
c.setItem(key, value) | |
}; | |
break; | |
case "angular": | |
c = $cacheFactory(cacheId), fn = cache.put | |
} | |
return fn | |
}, remove = function(key, cacheType) { | |
key = cacheId + "." + key, "localStorage" === cacheType ? localStorage.removeItem(key) : _defaultRemove(key) | |
}, removeAll = function() { | |
var ls = $window.localStorage; | |
if (ls.clear(), "angular" !== gaConfig.cache.type) { | |
var ang = $cacheFactory(cacheId); | |
ang.removeAll() | |
} else cache.removeAll() | |
}, info = function() { | |
if (!cache) return { | |
id: cacheId, | |
size: 0, | |
type: "none" | |
}; | |
if ("function" == typeof cache.info) { | |
var tmp = cache.info(); | |
return tmp.type = "angular", tmp | |
} | |
var size = 0; | |
for (var key in cache) key.substr(0, cacheId.length + 1) === cacheId + "." && (size += _byteLength(cache[key] + key)); | |
return { | |
id: cacheId, | |
size: size, | |
type: "localStorage" | |
} | |
}; | |
return { | |
get: get, | |
put: put, | |
remove: remove, | |
removeAll: removeAll, | |
info: info | |
} | |
}), angular.module("ga.utils.tracking", ["ga.utils.date"]).factory("gaUtilsT |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment