posthog-js
Version:
Posthog-js allows you to automatically capture usage and send events to PostHog.
185 lines • 10.2 kB
JavaScript
;
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.Toolbar = void 0;
var general_utils_1 = require("@posthog/browser-common/utils/general-utils");
var request_utils_1 = require("@posthog/browser-common/utils/request-utils");
var logger_1 = require("@posthog/browser-common/utils/logger");
var globals_1 = require("@posthog/browser-common/utils/globals");
var globals_2 = require("../utils/globals");
var constants_1 = require("@posthog/browser-common/constants");
var core_1 = require("@posthog/core");
// TRICKY: Many web frameworks will modify the route on load, potentially before posthog is initialized.
// To get ahead of this we grab it as soon as the posthog-js is parsed
var STATE_FROM_WINDOW = (globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.location)
? (0, request_utils_1._getHashParam)(globals_1.window.location.hash, '__posthog') || (0, request_utils_1._getHashParam)(location.hash, 'state')
: null;
var LOCALSTORAGE_KEY = '_postHogToolbarParams';
var logger = (0, logger_1.createLogger)('[Toolbar]');
var ToolbarState = { UNINITIALIZED: 0, LOADING: 1, LOADED: 2 };
var Toolbar = /** @class */ (function () {
function Toolbar(instance) {
this.instance = instance;
}
// NOTE: We store the state of the toolbar in the global scope to avoid multiple instances of the SDK loading the toolbar
Toolbar.prototype._setToolbarState = function (state) {
globals_2.assignableWindow['ph_toolbar_state'] = state;
};
Toolbar.prototype._getToolbarState = function () {
var _a;
return (_a = globals_2.assignableWindow['ph_toolbar_state']) !== null && _a !== void 0 ? _a : ToolbarState.UNINITIALIZED;
};
Toolbar.prototype.initialize = function () {
return this.maybeLoadToolbar();
};
/**
* To load the toolbar, we need an access token and other state. That state comes from one of three places:
* 1. In the URL hash params
* 2. From session storage under the key `toolbarParams` if the toolbar was initialized on a previous page
*/
Toolbar.prototype.maybeLoadToolbar = function (location, localStorage, history) {
if (location === void 0) { location = undefined; }
if (localStorage === void 0) { localStorage = undefined; }
if (history === void 0) { history = undefined; }
// don't load the toolbar on the toolbar :)
if ((0, general_utils_1.isToolbarInstance)(this.instance.config)) {
return false;
}
if (!globals_1.window || !globals_1.document) {
return false;
}
location = location !== null && location !== void 0 ? location : globals_1.window.location;
history = history !== null && history !== void 0 ? history : globals_1.window.history;
try {
// Before running the code we check if we can access localStorage, if not we opt-out
if (!localStorage) {
try {
globals_1.window.localStorage.setItem('test', 'test');
globals_1.window.localStorage.removeItem('test');
}
catch (_a) {
return false;
}
// If localStorage was undefined, and localStorage is supported we set the default value
localStorage = globals_1.window === null || globals_1.window === void 0 ? void 0 : globals_1.window.localStorage;
}
/**
* Info about the state
* The state is a json object
* 1. (Legacy) The state can be `state={}` as a urlencoded object of info. In this case
* 2. The state should now be found in `__posthog={}` and can be base64 encoded or urlencoded.
* 3. Base64 encoding is preferred and will gradually be rolled out everywhere
*/
var stateHash_1 = STATE_FROM_WINDOW || (0, request_utils_1._getHashParam)(location.hash, '__posthog') || (0, request_utils_1._getHashParam)(location.hash, 'state');
var toolbarParams = void 0;
var state = stateHash_1
? (0, general_utils_1.trySafe)(function () { return JSON.parse(atob(decodeURIComponent(stateHash_1))); }) ||
(0, general_utils_1.trySafe)(function () { return JSON.parse(decodeURIComponent(stateHash_1)); })
: null;
var parseFromUrl = state && state['action'] === 'ph_authorize';
if (parseFromUrl) {
// happens if they are initializing the toolbar using an old snippet
toolbarParams = state;
toolbarParams.source = 'url';
if (toolbarParams && Object.keys(toolbarParams).length > 0) {
if (state['desiredHash']) {
// hash that was in the url before the redirect
location.hash = state['desiredHash'];
}
else if (history) {
// second param is unused see https://developer.mozilla.org/en-US/docs/Web/API/History/replaceState
history.replaceState(history.state, '', location.pathname + location.search); // completely remove hash
}
else {
location.hash = ''; // clear hash (but leaves # unfortunately)
}
}
}
else {
// get credentials from localStorage from a previous initialization
toolbarParams = JSON.parse(localStorage.getItem(LOCALSTORAGE_KEY) || '{}');
toolbarParams.source = 'localstorage';
// delete "add-action" or other intent from toolbarParams, otherwise we'll have the same intent
// every time we open the page (e.g. you just visiting your own site an hour later)
delete toolbarParams.userIntent;
}
if (toolbarParams['token'] && this.instance.config.token === toolbarParams['token']) {
this.loadToolbar(toolbarParams);
return true;
}
else {
return false;
}
}
catch (_b) {
return false;
}
};
Toolbar.prototype._callLoadToolbar = function (params) {
var loadFn = globals_2.assignableWindow['ph_load_toolbar'] || globals_2.assignableWindow['ph_load_editor'];
if ((0, core_1.isNullish)(loadFn) || !(0, core_1.isFunction)(loadFn)) {
logger.warn('No toolbar load function found');
return;
}
loadFn(params, this.instance);
};
Toolbar.prototype.loadToolbar = function (params) {
var _this = this;
var _a, _b;
var toolbarRunning = !!(globals_1.document === null || globals_1.document === void 0 ? void 0 : globals_1.document.getElementById(constants_1.TOOLBAR_ID));
if (!globals_1.window || toolbarRunning) {
// The toolbar will clear the localStorage key when it's done with it. If it is present that indicates the toolbar is already open and running
return false;
}
var disableToolbarMetrics = this.instance.requestRouter.region === 'custom' && this.instance.config.advanced_disable_toolbar_metrics;
var toolbarParams = __assign(__assign(__assign({ token: this.instance.config.token }, params), { apiURL: this.instance.requestRouter.endpointFor('ui') }), (disableToolbarMetrics ? { instrument: false } : {}));
globals_1.window.localStorage.setItem(LOCALSTORAGE_KEY, JSON.stringify(__assign(__assign({}, toolbarParams), { source: undefined })));
if (this._getToolbarState() === ToolbarState.LOADED) {
this._callLoadToolbar(toolbarParams);
}
else if (this._getToolbarState() === ToolbarState.UNINITIALIZED) {
// only load the toolbar once, even if there are multiple instances of PostHogLib
this._setToolbarState(ToolbarState.LOADING);
(_b = (_a = globals_2.assignableWindow.__PosthogExtensions__) === null || _a === void 0 ? void 0 : _a.loadExternalDependency) === null || _b === void 0 ? void 0 : _b.call(_a, this.instance, 'toolbar', function (err) {
if (err) {
logger.error('[Toolbar] Failed to load', err);
_this._setToolbarState(ToolbarState.UNINITIALIZED);
return;
}
_this._setToolbarState(ToolbarState.LOADED);
_this._callLoadToolbar(toolbarParams);
});
// Turbolinks doesn't fire an onload event but does replace the entire body, including the toolbar.
// Thus, we ensure the toolbar is only loaded inside the body, and then reloaded on turbolinks:load.
(0, general_utils_1.addEventListener)(globals_1.window, 'turbolinks:load', function () {
_this._setToolbarState(ToolbarState.UNINITIALIZED);
_this.loadToolbar(toolbarParams);
});
}
return true;
};
/** @deprecated Use "loadToolbar" instead. */
Toolbar.prototype._loadEditor = function (params) {
return this.loadToolbar(params);
};
/** @deprecated Use "maybeLoadToolbar" instead. */
Toolbar.prototype.maybeLoadEditor = function (location, localStorage, history) {
if (location === void 0) { location = undefined; }
if (localStorage === void 0) { localStorage = undefined; }
if (history === void 0) { history = undefined; }
return this.maybeLoadToolbar(location, localStorage, history);
};
return Toolbar;
}());
exports.Toolbar = Toolbar;
//# sourceMappingURL=toolbar.js.map