var hashchange = (function () { var exports = {}; var expected_hash; var changing_hash = false; // Some browsers zealously URI-decode the contents of // window.location.hash. So we hide our URI-encoding // by replacing % with . (like MediaWiki). exports.encodeHashComponent = function (str) { return encodeURIComponent(str) .replace(/\./g, '%2E') .replace(/%/g, '.'); }; exports.encode_operand = function (operator, operand) { if ((operator === 'pm-with') || (operator === 'sender')) { var slug = people.emails_to_slug(operand); if (slug) { return slug; } } return exports.encodeHashComponent(operand); }; function decodeHashComponent(str) { return decodeURIComponent(str.replace(/\./g, '%')); } exports.decode_operand = function (operator, operand) { if ((operator === 'pm-with') || (operator === 'sender')) { var emails = people.slug_to_emails(operand); if (emails) { return emails; } } return decodeHashComponent(operand); }; function set_hash(hash) { var location = window.location; if (history.pushState) { if (hash === '' || hash.charAt(0) !== '#') { hash = '#' + hash; } // IE returns pathname as undefined and missing the leading / var pathname = location.pathname; if (pathname === undefined) { pathname = '/'; } else if (pathname === '' || pathname.charAt(0) !== '/') { pathname = '/' + pathname; } // Build a full URL to not have same origin problems var url = location.protocol + '//' + location.host + pathname + hash; history.pushState(null, null, url); } else { location.hash = hash; } } exports.changehash = function (newhash) { if (changing_hash) { return; } $(document).trigger($.Event('zuliphashchange.zulip')); set_hash(newhash); favicon.reset(); }; // Encodes an operator list into the // corresponding hash: the # component // of the narrow URL exports.operators_to_hash = function (operators) { var hash = '#'; if (operators !== undefined) { hash = '#narrow'; _.each(operators, function (elem) { // Support legacy tuples. var operator = elem.operator; var operand = elem.operand; var sign = elem.negated ? '-' : ''; hash += '/' + sign + hashchange.encodeHashComponent(operator) + '/' + hashchange.encode_operand(operator, operand); }); } return hash; }; exports.save_narrow = function (operators) { if (changing_hash) { return; } var new_hash = exports.operators_to_hash(operators); exports.changehash(new_hash); }; exports.parse_narrow = function (hash) { var i; var operators = []; for (i=1; i -1); } function hide_overlays() { subs.close(); } function hashchanged(from_reload, e) { var old_hash; if (e) { old_hash = "#" + e.oldURL.split(/#/).slice(1).join(""); ignore.last = old_hash; } var base = get_main_hash(window.location.hash); if (should_ignore(window.location.hash)) { if (!should_ignore(old_hash || "#")) { if (base === "subscriptions") { subs.launch(); } ignore.prev = old_hash; } } else if (!should_ignore(window.location.hash) && !ignore.flag) { hide_overlays(); changing_hash = true; var ret = do_hashchange(from_reload); changing_hash = false; return ret; // once we unignore the hash, we have to set the hash back to what it was // originally (eg. '#narrow/stream/Denmark' instead of '#settings'). We // therefore ignore the hash change once more while we change it back for // no iterruptions. } else if (ignore.flag) { ignore.flag = false; } } exports.initialize = function () { // jQuery doesn't have a hashchange event, so we manually wrap // our event handler window.onhashchange = blueslip.wrap_function(function (e) { hashchanged(false, e); }); hashchanged(true); }; exports.exit_settings = function (callback) { if (should_ignore(window.location.hash)) { ui.blur_active_element(); ignore.flag = true; window.location.hash = ignore.prev || "#"; if (typeof callback === "function") { callback(); } } }; return exports; }()); if (typeof module !== 'undefined') { module.exports = hashchange; }