mirror of https://github.com/zulip/zulip.git
hash_util: Move enc/decodeHashComponent to shared.
Moves the encodeHashComponent and decodeHashComponent functions out of hash_util and into internal_url which belongs to shared. This is to accommodate sharing of this code with mobile or any other codebases that do not wish to duplicate logic.
This commit is contained in:
parent
f6d9a0b5a4
commit
c0828f118b
|
@ -25,17 +25,7 @@ const frontend = {
|
|||
stream_data.add_sub(frontend);
|
||||
|
||||
run_test("hash_util", () => {
|
||||
// Test encodeHashComponent
|
||||
const str = "https://www.zulipexample.com";
|
||||
const result1 = hash_util.encodeHashComponent(str);
|
||||
assert.equal(result1, "https.3A.2F.2Fwww.2Ezulipexample.2Ecom");
|
||||
|
||||
// Test decodeHashComponent
|
||||
const result2 = hash_util.decodeHashComponent(result1);
|
||||
assert.equal(result2, str);
|
||||
|
||||
// Test encode_operand and decode_operand
|
||||
|
||||
function encode_decode_operand(operator, operand, expected_val) {
|
||||
const encode_result = hash_util.encode_operand(operator, operand);
|
||||
assert.equal(encode_result, expected_val);
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
"use strict";
|
||||
|
||||
const {strict: assert} = require("assert");
|
||||
|
||||
const {zrequire} = require("../zjsunit/namespace");
|
||||
const {run_test} = require("../zjsunit/test");
|
||||
|
||||
const internal_url = zrequire("../shared/js/internal_url");
|
||||
|
||||
run_test("test encodeHashComponent", () => {
|
||||
const decoded = "https://www.zulipexample.com";
|
||||
const encoded = "https.3A.2F.2Fwww.2Ezulipexample.2Ecom";
|
||||
const result = internal_url.encodeHashComponent(decoded);
|
||||
assert.equal(result, encoded);
|
||||
});
|
||||
|
||||
run_test("test decodeHashComponent", () => {
|
||||
const decoded = "https://www.zulipexample.com";
|
||||
const encoded = "https.3A.2F.2Fwww.2Ezulipexample.2Ecom";
|
||||
const result = internal_url.decodeHashComponent(encoded);
|
||||
assert.equal(result, decoded);
|
||||
});
|
|
@ -1,3 +1,5 @@
|
|||
import * as internal_url from "../shared/js/internal_url";
|
||||
|
||||
import * as people from "./people";
|
||||
import * as stream_data from "./stream_data";
|
||||
|
||||
|
@ -26,20 +28,6 @@ export function get_current_hash_section() {
|
|||
return get_hash_section(window.location.hash);
|
||||
}
|
||||
|
||||
const hashReplacements = new Map([
|
||||
["%", "."],
|
||||
["(", ".28"],
|
||||
[")", ".29"],
|
||||
[".", ".2E"],
|
||||
]);
|
||||
|
||||
// Some browsers zealously URI-decode the contents of
|
||||
// window.location.hash. So we hide our URI-encoding
|
||||
// by replacing % with . (like MediaWiki).
|
||||
export function encodeHashComponent(str) {
|
||||
return encodeURIComponent(str).replace(/[%().]/g, (matched) => hashReplacements.get(matched));
|
||||
}
|
||||
|
||||
export function build_reload_url() {
|
||||
let hash = window.location.hash;
|
||||
if (hash.length !== 0 && hash[0] === "#") {
|
||||
|
@ -60,7 +48,7 @@ export function encode_operand(operator, operand) {
|
|||
return encode_stream_name(operand);
|
||||
}
|
||||
|
||||
return encodeHashComponent(operand);
|
||||
return internal_url.encodeHashComponent(operand);
|
||||
}
|
||||
|
||||
export function encode_stream_id(stream_id) {
|
||||
|
@ -68,7 +56,7 @@ export function encode_stream_id(stream_id) {
|
|||
// URI encoding piece
|
||||
const slug = stream_data.id_to_slug(stream_id);
|
||||
|
||||
return encodeHashComponent(slug);
|
||||
return internal_url.encodeHashComponent(slug);
|
||||
}
|
||||
|
||||
export function encode_stream_name(operand) {
|
||||
|
@ -76,17 +64,7 @@ export function encode_stream_name(operand) {
|
|||
// URI encoding piece
|
||||
operand = stream_data.name_to_slug(operand);
|
||||
|
||||
return encodeHashComponent(operand);
|
||||
}
|
||||
|
||||
export function decodeHashComponent(str) {
|
||||
// This fails for URLs containing
|
||||
// foo.foo or foo%foo due to our fault in special handling
|
||||
// of such characters when encoding. This can also,
|
||||
// fail independent of our fault, so just tell the user
|
||||
// that the URL is invalid.
|
||||
// TODO: Show possible valid URLs to the user.
|
||||
return decodeURIComponent(str.replace(/\./g, "%"));
|
||||
return internal_url.encodeHashComponent(operand);
|
||||
}
|
||||
|
||||
export function decode_operand(operator, operand) {
|
||||
|
@ -97,7 +75,7 @@ export function decode_operand(operator, operand) {
|
|||
}
|
||||
}
|
||||
|
||||
operand = decodeHashComponent(operand);
|
||||
operand = internal_url.decodeHashComponent(operand);
|
||||
|
||||
if (operator === "stream") {
|
||||
return stream_data.slug_to_name(operand);
|
||||
|
@ -111,7 +89,12 @@ export function by_stream_uri(stream_id) {
|
|||
}
|
||||
|
||||
export function by_stream_topic_uri(stream_id, topic) {
|
||||
return "#narrow/stream/" + encode_stream_id(stream_id) + "/topic/" + encodeHashComponent(topic);
|
||||
return (
|
||||
"#narrow/stream/" +
|
||||
encode_stream_id(stream_id) +
|
||||
"/topic/" +
|
||||
internal_url.encodeHashComponent(topic)
|
||||
);
|
||||
}
|
||||
|
||||
// Encodes an operator list into the
|
||||
|
@ -132,7 +115,7 @@ export function operators_to_hash(operators) {
|
|||
hash +=
|
||||
"/" +
|
||||
sign +
|
||||
encodeHashComponent(operator) +
|
||||
internal_url.encodeHashComponent(operator) +
|
||||
"/" +
|
||||
encode_operand(operator, operand);
|
||||
}
|
||||
|
@ -166,7 +149,7 @@ export function by_conversation_and_time_uri(message) {
|
|||
"/" +
|
||||
window.location.pathname.split("/")[1];
|
||||
|
||||
const suffix = "/near/" + encodeHashComponent(message.id);
|
||||
const suffix = "/near/" + internal_url.encodeHashComponent(message.id);
|
||||
|
||||
if (message.type === "stream") {
|
||||
return absolute_url + by_stream_topic_uri(message.stream_id, message.topic) + suffix;
|
||||
|
@ -176,7 +159,7 @@ export function by_conversation_and_time_uri(message) {
|
|||
}
|
||||
|
||||
export function stream_edit_uri(sub) {
|
||||
const hash = `#streams/${sub.stream_id}/${encodeHashComponent(sub.name)}`;
|
||||
const hash = `#streams/${sub.stream_id}/${internal_url.encodeHashComponent(sub.name)}`;
|
||||
return hash;
|
||||
}
|
||||
|
||||
|
@ -193,7 +176,7 @@ export function parse_narrow(hash) {
|
|||
for (i = 1; i < hash.length; i += 2) {
|
||||
// We don't construct URLs with an odd number of components,
|
||||
// but the user might write one.
|
||||
let operator = decodeHashComponent(hash[i]);
|
||||
let operator = internal_url.decodeHashComponent(hash[i]);
|
||||
// Do not parse further if empty operator encountered.
|
||||
if (operator === "") {
|
||||
break;
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
import $ from "jquery";
|
||||
|
||||
import {$t_html} from "./i18n";
|
||||
import * as about_zulip from "./about_zulip";
|
||||
import * as admin from "./admin";
|
||||
import * as blueslip from "./blueslip";
|
||||
|
@ -8,6 +7,7 @@ import * as browser_history from "./browser_history";
|
|||
import * as drafts from "./drafts";
|
||||
import * as floating_recipient_bar from "./floating_recipient_bar";
|
||||
import * as hash_util from "./hash_util";
|
||||
import {$t_html} from "./i18n";
|
||||
import * as info_overlay from "./info_overlay";
|
||||
import * as invite from "./invite";
|
||||
import * as message_lists from "./message_lists";
|
||||
|
@ -25,8 +25,8 @@ import * as settings_toggle from "./settings_toggle";
|
|||
import * as spectators from "./spectators";
|
||||
import * as stream_settings_ui from "./stream_settings_ui";
|
||||
import * as top_left_corner from "./top_left_corner";
|
||||
import * as ui_util from "./ui_util";
|
||||
import * as ui_report from "./ui_report";
|
||||
import * as ui_util from "./ui_util";
|
||||
import {user_settings} from "./user_settings";
|
||||
|
||||
// Read https://zulip.readthedocs.io/en/latest/subsystems/hashchange-system.html
|
||||
|
@ -138,13 +138,8 @@ function do_hashchange_normal(from_reload) {
|
|||
case "#narrow": {
|
||||
maybe_hide_recent_topics();
|
||||
ui_util.change_tab_to("#message_feed_container");
|
||||
let operators = undefined;
|
||||
let operators;
|
||||
try {
|
||||
// This fails for URLs containing
|
||||
// foo.foo or foo%foo due to our fault in special handling
|
||||
// of such characters when encoding. This can also,
|
||||
// fail independent of our fault, so just tell the user
|
||||
// that the URL is invalid.
|
||||
// TODO: Show possible valid URLs to the user.
|
||||
operators = hash_util.parse_narrow(hash);
|
||||
} catch {
|
||||
|
|
|
@ -0,0 +1,22 @@
|
|||
const hashReplacements = new Map([
|
||||
["%", "."],
|
||||
["(", ".28"],
|
||||
[")", ".29"],
|
||||
[".", ".2E"],
|
||||
]);
|
||||
|
||||
// Some browsers zealously URI-decode the contents of
|
||||
// window.location.hash. So we hide our URI-encoding
|
||||
// by replacing % with . (like MediaWiki).
|
||||
export function encodeHashComponent(str) {
|
||||
return encodeURIComponent(str).replace(/[%().]/g, (matched) => hashReplacements.get(matched));
|
||||
}
|
||||
|
||||
export function decodeHashComponent(str) {
|
||||
// This fails for URLs containing
|
||||
// foo.foo or foo%foo due to our fault in special handling
|
||||
// of such characters when encoding. This can also,
|
||||
// fail independent of our fault.
|
||||
// Here we let the calling code handle the exception.
|
||||
return decodeURIComponent(str.replace(/\./g, "%"));
|
||||
}
|
|
@ -6,8 +6,8 @@ from zerver.models import Realm, Stream, UserProfile
|
|||
|
||||
|
||||
def hash_util_encode(string: str) -> str:
|
||||
# Do the same encoding operation as hash_util.encodeHashComponent on the
|
||||
# frontend.
|
||||
# Do the same encoding operation as shared internal_url.encodeHashComponent
|
||||
# on the frontend.
|
||||
# `safe` has a default value of "/", but we want those encoded, too.
|
||||
return quote(string, safe=b"").replace(".", "%2E").replace("%", ".")
|
||||
|
||||
|
|
Loading…
Reference in New Issue