/**
* @class
* @name Offline
* @memberof ATInternet.Tracker.Plugins
* @type {function}
* @param parent {object} Instance of the Tag used
* @description
* Plugin to save hits that could not be sent, following a loss of Internet connection, to the user’s browser.
* <br />To do this, the plugin uses the localStorage feature available in recent browsers.
* The status of the Internet connection (whether the browser is online or not) is determined by the browser’s onLine property available in HTML5.
* @public
*/
window['ATInternet']['Tracker']['Plugins']['Offline'] = function (parent) {
"use strict";
var _this = this;
var _config = {};
// Set specific plugin configuration.
// If global configuration already exists, set only undefined properties.
parent.configPlugin('Offline', dfltPluginCfg || {}, function (newConf) {
_config = newConf;
});
/**
* Check if local storage is both supported and available.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @return {boolean}
* @private
*/
var _isLocalStorageAvailable = function () {
try {
var storage = window['localStorage'],
x = '__storage_test__';
storage.setItem(x, x);
storage.removeItem(x);
return true;
}
catch (e) {
/* @if debug */
parent.debug('Offline:localStorage:Error', 'ERROR', 'Local storage may be unsupported/unavailable', {except: e});
/* @endif */
return false;
}
};
/**
* Get stored data from local storage.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @return {object}
* @private
*/
var _getStorageData = function () {
var st = localStorage.getItem('ATOffline');
var obj = {
hits: [],
length: 0
};
if (st) {
var stObj = ATInternet.Utils.jsonParse(st) || {hits: []};
obj.hits = stObj.hits;
obj.length = st.length;
}
return obj;
};
/**
* Set data into local storage.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @param value {object} Object containing array of hits
* @return {object}
* @private
*/
var _setStorageData = function (value) {
try {
localStorage.setItem('ATOffline', ATInternet.Utils.jsonSerialize(value));
}
catch (e) {
/* @if debug */
parent.debug('Offline:localStorage:setItem:Error', 'ERROR', 'Cannot set value in local storage', {
except: e,
value: ATInternet.Utils.jsonSerialize(value)
});
/* @endif */
}
};
/**
* Get estimated storage data length (max bytes).
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @return {number}
* @private
*/
var _getStorageDataLength = function () {
/* @if debug */
parent.debug('Offline:offline:getLength', 'DEBUG', 'method started');
/* @endif */
return _getStorageData().length * 4;
};
/**
* Remove hits from local storage.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @private
*/
var _removeHitsFromStorage = function () {
var value = {hits: []};
_setStorageData(value);
/* @if debug */
parent.debug('Offline:offline:remove', 'DEBUG', 'method ended');
/* @endif */
};
/**
* Get hits array from local storage.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @return {Array}
* @private
*/
var _getHitsFromStorage = function () {
/* @if debug */
parent.debug('Offline:offline:get', 'DEBUG', 'method started');
/* @endif */
return _getStorageData().hits;
};
/**
* Fire single hit from hits array.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @param hits {Array} List of hits to send
* @private
*/
var _sendSingleHit = function (hits) {
if (hits.length > 0) {
// Get URL
var url = hits.shift();
// Update localStorage
var storageHits = _getHitsFromStorage();
if (storageHits && storageHits[0] === url) {
storageHits.shift();
var value = {hits: storageHits};
_setStorageData(value);
}
// Update local object
hits = storageHits;
// Add action on trigger
parent.onTrigger('Tracker:Hit:Sent:Ok', function () {
_sendSingleHit(hits);
}, true);
// Send URL
parent.sendUrl(url);
}
else {
_sendHitsFromStorage(false);
}
};
/**
* Fire all hits from local storage.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @param store {boolean} Store new hits during dispatch if necessary
* @private
*/
var _sendHitsFromStorage = function (store) {
var hits = _getHitsFromStorage();
if (hits.length > 0) {
_sendSingleHit(hits);
if (store) {
_storeHits();
}
}
};
/**
* Store a new hit in local storage.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @param hit {string} Hit value
* @private
*/
var _storeSingleHit = function (hit) {
var obj = _getStorageData();
var storageLength = obj.length || '{"hits":[]}'.length;
var hitLength = ATInternet.Utils.jsonSerialize(hit).length;
if (((storageLength + hitLength) * 4) > (_config.storageCapacity * 1024 * 1024)) {
obj.hits.shift();
}
obj.hits.push(hit);
var value = {hits: obj.hits};
_setStorageData(value);
};
/**
* Store all new hits into local storage.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @private
*/
var _storeHits = function () {
var _process = function (h) {
if (h) {
var str = h.split(/&ref=\.*/i);
var params = '&cn=offline&olt=' + new Date().getTime();
h = str[0] + params + '&ref=' + (str[1] || '');
}
return h;
};
parent.builder.sendUrl = function (hit) {
_storeSingleHit(_process(hit));
};
};
/**
* Initialise global process.
* @memberof ATInternet.Tracker.Plugins.Offline#
* @function
* @private
*/
var _init = function () {
var isLocalStorage = _isLocalStorageAvailable();
var isOnline = navigator.onLine;
if (isLocalStorage && (typeof isOnline !== 'undefined')) {
var storageMode = _config.storageMode;
if (storageMode === 'required') {
if (isOnline) {
_sendHitsFromStorage(true);
}
else {
_storeHits();
}
}
else if (storageMode === 'always') {
_storeHits();
}
}
parent.emit('Offline:Ready', {
lvl: 'INFO',
details: {
isLocalStorageAvailable: isLocalStorage,
storageMode: _config.storageMode,
isOnline: isOnline
}
});
};
/**
* [Object added by plugin {@link ATInternet.Tracker.Plugins.Offline Offline}] Tags to manage local storage.
* @name offline
* @memberof ATInternet.Tracker.Tag
* @inner
* @type {object}
* @property {function} getLength Tag helper, see details here {@link ATInternet.Tracker.Tag#offline.getLength}
* @property {function} remove Tag helper, see details here {@link ATInternet.Tracker.Tag#offline.remove}
* @property {function} get Tag helper, see details here {@link ATInternet.Tracker.Tag#offline.get}
* @property {function} send Tag helper, see details here {@link ATInternet.Tracker.Tag#offline.send}
* @public
*/
parent['offline'] = {};
/**
* [Helper added by plugin {@link ATInternet.Tracker.Plugins.Offline Offline}] Get estimated storage data length.
* @alias offline.getLength
* @memberof! ATInternet.Tracker.Tag#
* @function
* @returns {number}
* @example
* <pre><code class="javascript">var len = tag.offline.getLength();
* </code></pre>
* @public
*/
parent['offline']['getLength'] = _getStorageDataLength;
/**
* [Helper added by plugin {@link ATInternet.Tracker.Plugins.Offline Offline}] Remove hits from local storage.
* @alias offline.remove
* @memberof! ATInternet.Tracker.Tag#
* @function
* @example
* <pre><code class="javascript">tag.offline.remove();
* </code></pre>
* @public
*/
parent['offline']['remove'] = _removeHitsFromStorage;
/**
* [Helper added by plugin {@link ATInternet.Tracker.Plugins.Offline Offline}] Get hits array from local storage.
* @alias offline.get
* @memberof! ATInternet.Tracker.Tag#
* @function
* @returns {Array}
* @example
* <pre><code class="javascript">var hitArr = tag.offline.get();
* </code></pre>
* @public
*/
parent['offline']['get'] = _getHitsFromStorage;
/**
* [Helper added by plugin {@link ATInternet.Tracker.Plugins.Offline Offline}] Send hits from local storage.
* @alias offline.send
* @memberof! ATInternet.Tracker.Tag#
* @function
* @example
* <pre><code class="javascript">tag.offline.send();
* </code></pre>
* @public
*/
parent['offline']['send'] = function () {
_sendHitsFromStorage(false);
/* @if debug */
parent.debug('Offline:offline:send', 'DEBUG', 'method ended');
/* @endif */
};
// Initialises global process.
_init();
// For unit tests on private elements !!!
/* @if test */
_this._isLocalStorageAvailable = _isLocalStorageAvailable;
_this._getStorageData = _getStorageData;
_this._setStorageData = _setStorageData;
_this._getStorageDataLength = _getStorageDataLength;
_this._removeHitsFromStorage = _removeHitsFromStorage;
_this._getHitsFromStorage = _getHitsFromStorage;
_this._sendSingleHit = _sendSingleHit;
_this._sendHitsFromStorage = _sendHitsFromStorage;
_this._storeSingleHit = _storeSingleHit;
_this._storeHits = _storeHits;
_this._init = _init;
/* @endif */
};
window['ATInternet']['Tracker']['addPlugin']('Offline');