var VnDate = require('./date'); var Lot = require('./lot'); /** * Class to handle the hash part of the URL as a key-value javascript object. * It also handles dates and objects as a value. */ module.exports = new Class({ Extends: Lot ,Properties: { /** * The main window object. */ window: { type: Window ,set(x) { this._window = x; x.addEventListener('hashchange', this._hashChangedHandler); this._hashChanged(); } ,get() { return this._window; } } } ,initialize(props) { Object.assign(this, { _hash: null ,_hashLock: false ,_window: null ,_hashChangedHandler: this._hashChanged.bind(this) }); Lot.prototype.initialize.call(this, props); } ,_paramsChanged() { this.updateHash(); } /** * Creates a URL with the given hash data. * * @param {Object} params A key-value object * @param {boolean} add %true to combine with the current params, %false otherwise * @return {string} The URL */ ,make(params, add) { if (add) { params = Object.assign({}, params); for (var key in this._params) if (!params[key]) params[key] = this._params[key]; } return this.renderHash(params); } /** * Updates the window hash with current params. */ ,updateHash() { if (this._hashLock) return; this._hash = this.renderHash(this._params); this._hashLock = true; location.hash = this._hash; this._hashLock = false; } /* * Called when window hash changes. */ ,_hashChanged() { var newHash = location.hash; if (this._hashLock || this._hash === newHash) return; this._hash = newHash; this._hashLock = true; this.params = this.parseHash(newHash); this._hashLock = false; } /** * Creates a URL with the given hash data. * * @param {Object} params The key-value object * @return {string} The URL */ ,renderHash(params) { var hash = '#!'; for (var key in params) if (params[key] !== undefined) { if (hash.length > 2) hash += '&'; hash += encodeURIComponent(key) +'='+ this.renderValue(params[key]); } return hash; } /** * Parses a hash string to a key-value object. * * @param {string} hashString The hash string * @return {Object} The key-value object */ ,parseHash(hashString) { var newMap = hashMap = {}; var kvPairs = hashString.substr(2).split('&'); for (var i = 0; i < kvPairs.length; i++) { var kvPair = kvPairs[i].split('=', 2); if (kvPair[0]) newMap[decodeURIComponent(kvPair[0])] = this.parseValue(kvPair[1]); } return newMap; } ,renderValue(v) { if (v == null) return ''; switch (typeof v) { case 'object': if (v instanceof Date) return VnDate.strftime(v, '%Y-%m-%d'); else return JSON.stringify(v) } return v; } ,parseValue(v) { if (v == null) return v; v = decodeURIComponent(v); if (v === '') return null; return v; } ,_destroy() { this._window.removeEventListener('hashchange', this._hashChangedHandler); this._window = null; Lot.prototype._destroy.call(this); } });