diff --git a/frontend_tests/node_tests/dispatch.js b/frontend_tests/node_tests/dispatch.js index 40d1c00ef3..82b7e0c0a3 100644 --- a/frontend_tests/node_tests/dispatch.js +++ b/frontend_tests/node_tests/dispatch.js @@ -484,11 +484,11 @@ run_test("realm_emoji", (override) => { } }); -run_test("realm_filters", (override) => { +run_test("linkifier", (override) => { const event = event_fixtures.realm_filters; page_params.realm_filters = []; - override(settings_linkifiers, "populate_filters", noop); - override(markdown, "update_realm_filter_rules", noop); + override(settings_linkifiers, "populate_linkifiers", noop); + override(markdown, "update_linkifier_rules", noop); dispatch(event); assert_same(page_params.realm_filters, event.realm_filters); }); diff --git a/frontend_tests/node_tests/markdown.js b/frontend_tests/node_tests/markdown.js index f1024be395..a91279d045 100644 --- a/frontend_tests/node_tests/markdown.js +++ b/frontend_tests/node_tests/markdown.js @@ -390,23 +390,23 @@ run_test("marked", () => { expected: '
\n

Mention in quote: Cordelia Lear

\n
\n

Mention outside quote: @Cordelia Lear

', }, - // Test only those realm filters which don't return True for + // Test only those linkifiers which don't return True for // `contains_backend_only_syntax()`. Those which return True // are tested separately. { - input: "This is a realm filter #1234 with text after it", + input: "This is a linkifier #1234 with text after it", expected: - '

This is a realm filter #1234 with text after it

', + '

This is a linkifier #1234 with text after it

', }, - {input: "#1234is not a realm filter.", expected: "

#1234is not a realm filter.

"}, + {input: "#1234is not a linkifier.", expected: "

#1234is not a linkifier.

"}, { - input: "A pattern written as #1234is not a realm filter.", - expected: "

A pattern written as #1234is not a realm filter.

", + input: "A pattern written as #1234is not a linkifier.", + expected: "

A pattern written as #1234is not a linkifier.

", }, { - input: "This is a realm filter with ZGROUP_123:45 groups", + input: "This is a linkifier with ZGROUP_123:45 groups", expected: - '

This is a realm filter with ZGROUP_123:45 groups

', + '

This is a linkifier with ZGROUP_123:45 groups

', }, {input: "Test *italic*", expected: "

Test italic

"}, { @@ -453,8 +453,8 @@ run_test("marked", () => { }, {input: "@*notagroup*", expected: "

@*notagroup*

"}, { - input: "This is a realm filter `hello` with text after it", - expected: "

This is a realm filter hello with text after it

", + input: "This is a linkifier `hello` with text after it", + expected: "

This is a linkifier hello with text after it

", }, // Test the emoticon conversion {input: ":)", expected: "

:)

"}, @@ -650,39 +650,39 @@ run_test("message_flags", () => { assert.equal(message.mentioned, false); }); -run_test("backend_only_realm_filters", () => { - markdown.update_realm_filter_rules(page_params.realm_filters); +run_test("backend_only_linkifiers", () => { + markdown.update_linkifier_rules(page_params.realm_filters); - const backend_only_realm_filters = [ + const backend_only_linkifiers = [ "Here is the PR-#123.", "Function abc() was introduced in (PR)#123.", ]; - for (const content of backend_only_realm_filters) { + for (const content of backend_only_linkifiers) { assert.equal(markdown.contains_backend_only_syntax(content), true); } }); -run_test("python_to_js_filter", () => { - // The only way to reach python_to_js_filter is indirectly, hence the call - // to update_realm_filter_rules. - markdown.update_realm_filter_rules([["/a(?im)a/g"], ["/a(?L)a/g"]]); - let actual_value = marked.InlineLexer.rules.zulip.realm_filters; +run_test("python_to_js_linkifier", () => { + // The only way to reach python_to_js_linkifier is indirectly, hence the call + // to update_linkifier_rules. + markdown.update_linkifier_rules([["/a(?im)a/g"], ["/a(?L)a/g"]]); + let actual_value = marked.InlineLexer.rules.zulip.linkifiers; let expected_value = [/\/aa\/g(?!\w)/gim, /\/aa\/g(?!\w)/g]; assert.deepEqual(actual_value, expected_value); // Test case with multiple replacements. - markdown.update_realm_filter_rules([ + markdown.update_linkifier_rules([ ["#cf(?P\\d+)(?P[A-Z][\\dA-Z]*)", "http://google.com"], ]); - actual_value = marked.InlineLexer.rules.zulip.realm_filters; + actual_value = marked.InlineLexer.rules.zulip.linkifiers; expected_value = [/#cf(\d+)([A-Z][\dA-Z]*)(?!\w)/g]; assert.deepEqual(actual_value, expected_value); // Test incorrect syntax. blueslip.expect( "error", - "python_to_js_filter: Invalid regular expression: /!@#@(!#&((!&(@#((?!\\w)/: Unterminated group", + "python_to_js_linkifier: Invalid regular expression: /!@#@(!#&((!&(@#((?!\\w)/: Unterminated group", ); - markdown.update_realm_filter_rules([["!@#@(!#&((!&(@#(", "http://google.com"]]); - actual_value = marked.InlineLexer.rules.zulip.realm_filters; + markdown.update_linkifier_rules([["!@#@(!#&((!&(@#(", "http://google.com"]]); + actual_value = marked.InlineLexer.rules.zulip.linkifiers; expected_value = []; assert.deepEqual(actual_value, expected_value); }); diff --git a/frontend_tests/puppeteer_tests/15-realm-linkifier.ts b/frontend_tests/puppeteer_tests/15-realm-linkifier.ts index de2f4a4730..be115d3d98 100644 --- a/frontend_tests/puppeteer_tests/15-realm-linkifier.ts +++ b/frontend_tests/puppeteer_tests/15-realm-linkifier.ts @@ -5,56 +5,59 @@ import type {Page} from "puppeteer"; import common from "../puppeteer_lib/common"; async function test_add_linkifier(page: Page): Promise { - await page.waitForSelector(".admin-filter-form", {visible: true}); - await common.fill_form(page, "form.admin-filter-form", { + await page.waitForSelector(".admin-linkifier-form", {visible: true}); + await common.fill_form(page, "form.admin-linkifier-form", { pattern: "#(?P[0-9]+)", url_format_string: "https://trac.example.com/ticket/%(id)s", }); - await page.click("form.admin-filter-form button.button"); + await page.click("form.admin-linkifier-form button.button"); - const admin_filter_status_selector = "div#admin-filter-status"; - await page.waitForSelector(admin_filter_status_selector, {visible: true}); - const admin_filter_status = await common.get_text_from_selector( + const admin_linkifier_status_selector = "div#admin-linkifier-status"; + await page.waitForSelector(admin_linkifier_status_selector, {visible: true}); + const admin_linkifier_status = await common.get_text_from_selector( page, - admin_filter_status_selector, + admin_linkifier_status_selector, ); - assert.strictEqual(admin_filter_status, "Custom filter added!"); + assert.strictEqual(admin_linkifier_status, "Custom linkifier added!"); - await page.waitForSelector(".filter_row", {visible: true}); + await page.waitForSelector(".linkifier_row", {visible: true}); assert.strictEqual( - await common.get_text_from_selector(page, ".filter_row span.filter_pattern"), + await common.get_text_from_selector(page, ".linkifier_row span.linkifier_pattern"), "#(?P[0-9]+)", ); assert.strictEqual( - await common.get_text_from_selector(page, ".filter_row span.filter_url_format_string"), + await common.get_text_from_selector( + page, + ".linkifier_row span.linkifier_url_format_string", + ), "https://trac.example.com/ticket/%(id)s", ); } async function test_delete_linkifier(page: Page): Promise { - await page.click(".filter_row button"); - await page.waitForSelector(".filter_row", {hidden: true}); + await page.click(".linkifier_row button"); + await page.waitForSelector(".linkifier_row", {hidden: true}); } async function test_invalid_linkifier_pattern(page: Page): Promise { - await page.waitForSelector(".admin-filter-form", {visible: true}); - await common.fill_form(page, "form.admin-filter-form", { + await page.waitForSelector(".admin-linkifier-form", {visible: true}); + await common.fill_form(page, "form.admin-linkifier-form", { pattern: "a$", url_format_string: "https://trac.example.com/ticket/%(id)s", }); - await page.click("form.admin-filter-form button.button"); + await page.click("form.admin-linkifier-form button.button"); - await page.waitForSelector("div#admin-filter-pattern-status", {visible: true}); + await page.waitForSelector("div#admin-linkifier-pattern-status", {visible: true}); assert.strictEqual( - await common.get_text_from_selector(page, "div#admin-filter-pattern-status"), + await common.get_text_from_selector(page, "div#admin-linkifier-pattern-status"), "Failed: Invalid filter pattern. Valid characters are [ a-zA-Z_#=/:+!-].", ); } -async function realm_linkifier_test(page: Page): Promise { +async function linkifier_test(page: Page): Promise { await common.log_in(page); await common.manage_organization(page); - await page.click("li[data-section='filter-settings']"); + await page.click("li[data-section='linkifier-settings']"); await test_add_linkifier(page); await test_delete_linkifier(page); @@ -63,4 +66,4 @@ async function realm_linkifier_test(page: Page): Promise { await common.log_out(page); } -common.run_test(realm_linkifier_test); +common.run_test(linkifier_test); diff --git a/static/js/markdown.js b/static/js/markdown.js index 7f697e924d..3e4ffff275 100644 --- a/static/js/markdown.js +++ b/static/js/markdown.js @@ -22,8 +22,8 @@ import * as message_store from "./message_store"; // for example usage. let helpers; -const realm_filter_map = new Map(); -let realm_filter_list = []; +const linkifier_map = new Map(); +let linkifier_list = []; // Regexes that match some of our common backend-only Markdown syntax const backend_only_markdown_re = [ @@ -84,15 +84,15 @@ export function contains_backend_only_syntax(content) { // If it doesn't, we can immediately render it client-side for local echo. const markedup = backend_only_markdown_re.find((re) => re.test(content)); - // If a realm filter doesn't start with some specified characters + // If a linkifier doesn't start with some specified characters // then don't render it locally. It is workaround for the fact that // javascript regex doesn't support lookbehind. - const false_filter_match = realm_filter_list.find((re) => { + const false_linkifier_match = linkifier_list.find((re) => { const pattern = /[^\s"'(,:<]/.source + re[0].source + /(?!\w)/.source; const regex = new RegExp(pattern); return regex.test(content); }); - return markedup !== undefined || false_filter_match !== undefined; + return markedup !== undefined || false_linkifier_match !== undefined; } export function apply_markdown(message) { @@ -212,9 +212,9 @@ export function add_topic_links(message) { const topic = message.topic; let links = []; - for (const realm_filter of realm_filter_list) { - const pattern = realm_filter[0]; - const url = realm_filter[1]; + for (const linkifier of linkifier_list) { + const pattern = linkifier[0]; + const url = linkifier[1]; let match; while ((match = pattern.exec(topic)) !== null) { let link_url = url; @@ -340,8 +340,8 @@ function handleStreamTopic(stream_name, topic) { )}" href="/${_.escape(href)}">${_.escape(text)}`; } -function handleRealmFilter(pattern, matches) { - let url = realm_filter_map.get(pattern); +function handleLinkifier(pattern, matches) { + let url = linkifier_map.get(pattern); let current_group = 1; @@ -367,7 +367,7 @@ function handleTex(tex, fullmatch) { } } -function python_to_js_filter(pattern, url) { +function python_to_js_linkifier(pattern, url) { // Converts a python named-group regex to a javascript-compatible numbered // group regex... with a regex! const named_group_re = /\(?P<([^>]+?)>/g; @@ -404,7 +404,7 @@ function python_to_js_filter(pattern, url) { pattern = pattern.replace(inline_flag_re, ""); } - // Ideally we should have been checking that realm filters + // Ideally we should have been checking that linkifiers // begin with certain characters but since there is no // support for negative lookbehind in javascript, we check // for this condition in `contains_backend_only_syntax()` @@ -418,36 +418,36 @@ function python_to_js_filter(pattern, url) { final_regex = new RegExp(pattern, js_flags); } catch (error) { // We have an error computing the generated regex syntax. - // We'll ignore this realm filter for now, but log this + // We'll ignore this linkifier for now, but log this // failure for debugging later. - blueslip.error("python_to_js_filter: " + error.message); + blueslip.error("python_to_js_linkifier: " + error.message); } return [final_regex, url]; } -export function update_realm_filter_rules(realm_filters) { - // Update the marked parser with our particular set of realm filters - realm_filter_map.clear(); - realm_filter_list = []; +export function update_linkifier_rules(linkifiers) { + // Update the marked parser with our particular set of linkifiers + linkifier_map.clear(); + linkifier_list = []; const marked_rules = []; - for (const [pattern, url] of realm_filters) { - const [regex, final_url] = python_to_js_filter(pattern, url); + for (const [pattern, url] of linkifiers) { + const [regex, final_url] = python_to_js_linkifier(pattern, url); if (!regex) { - // Skip any realm filters that could not be converted + // Skip any linkifiers that could not be converted continue; } - realm_filter_map.set(regex, final_url); - realm_filter_list.push([regex, final_url]); + linkifier_map.set(regex, final_url); + linkifier_list.push([regex, final_url]); marked_rules.push(regex); } - marked.InlineLexer.rules.zulip.realm_filters = marked_rules; + marked.InlineLexer.rules.zulip.linkifiers = marked_rules; } -export function initialize(realm_filters, helper_config) { +export function initialize(linkifiers, helper_config) { helpers = helper_config; function disable_markdown_regex(rules, name) { @@ -506,7 +506,7 @@ export function initialize(realm_filters, helper_config) { // Disable autolink as (a) it is not used in our backend and (b) it interferes with @mentions disable_markdown_regex(marked.InlineLexer.rules.zulip, "autolink"); - update_realm_filter_rules(realm_filters); + update_linkifier_rules(linkifiers); // Tell our fenced code preprocessor how to insert arbitrary // HTML into the output. This generated HTML is safe to not escape @@ -525,7 +525,7 @@ export function initialize(realm_filters, helper_config) { unicodeEmojiHandler: handleUnicodeEmoji, streamHandler: handleStream, streamTopicHandler: handleStreamTopic, - realmFilterHandler: handleRealmFilter, + linkifierHandler: handleLinkifier, texHandler: handleTex, timestampHandler: handleTimestamp, renderer: r, diff --git a/static/js/server_events_dispatch.js b/static/js/server_events_dispatch.js index 77982f4dbc..40775a9e87 100644 --- a/static/js/server_events_dispatch.js +++ b/static/js/server_events_dispatch.js @@ -286,8 +286,8 @@ export function dispatch_normal_event(event) { case "realm_filters": page_params.realm_filters = event.realm_filters; - markdown.update_realm_filter_rules(page_params.realm_filters); - settings_linkifiers.populate_filters(page_params.realm_filters); + markdown.update_linkifier_rules(page_params.realm_filters); + settings_linkifiers.populate_linkifiers(page_params.realm_filters); break; case "realm_domains": { diff --git a/static/js/settings_linkifiers.js b/static/js/settings_linkifiers.js index 4c7596d2e4..46fec41d5f 100644 --- a/static/js/settings_linkifiers.js +++ b/static/js/settings_linkifiers.js @@ -1,6 +1,6 @@ import $ from "jquery"; -import render_admin_filter_list from "../templates/admin_filter_list.hbs"; +import render_admin_linkifier_list from "../templates/admin_linkifier_list.hbs"; import * as channel from "./channel"; import * as ListWidget from "./list_widget"; @@ -39,42 +39,42 @@ function sort_url(a, b) { return compare_by_index(a, b, 1); } -export function populate_filters(filters_data) { +export function populate_linkifiers(linkifiers_data) { if (!meta.loaded) { return; } - const filters_table = $("#admin_filters_table").expectOne(); - ListWidget.create(filters_table, filters_data, { + const linkifiers_table = $("#admin_linkifiers_table").expectOne(); + ListWidget.create(linkifiers_table, linkifiers_data, { name: "linkifiers_list", - modifier(filter) { - return render_admin_filter_list({ - filter: { - pattern: filter[0], - url_format_string: filter[1], - id: filter[2], + modifier(linkifier) { + return render_admin_linkifier_list({ + linkifier: { + pattern: linkifier[0], + url_format_string: linkifier[1], + id: linkifier[2], }, can_modify: page_params.is_admin, }); }, filter: { - element: filters_table.closest(".settings-section").find(".search"), + element: linkifiers_table.closest(".settings-section").find(".search"), predicate(item, value) { return ( item[0].toLowerCase().includes(value) || item[1].toLowerCase().includes(value) ); }, onupdate() { - ui.reset_scrollbar(filters_table); + ui.reset_scrollbar(linkifiers_table); }, }, - parent_container: $("#filter-settings").expectOne(), + parent_container: $("#linkifier-settings").expectOne(), init_sort: [sort_pattern], sort_fields: { pattern: sort_pattern, url: sort_url, }, - simplebar_container: $("#filter-settings .progressive-table-wrapper"), + simplebar_container: $("#linkifier-settings .progressive-table-wrapper"), }); loading.destroy_indicator($("#admin_page_filters_loading_indicator")); @@ -91,16 +91,16 @@ export function build_page() { // create loading indicators loading.make_indicator($("#admin_page_filters_loading_indicator")); - // Populate filters table - populate_filters(page_params.realm_filters); + // Populate linkifiers table + populate_linkifiers(page_params.realm_filters); - $(".admin_filters_table").on("click", ".delete", function (e) { + $(".admin_linkifiers_table").on("click", ".delete", function (e) { e.preventDefault(); e.stopPropagation(); const btn = $(this); channel.del({ - url: "/json/realm/filters/" + encodeURIComponent(btn.attr("data-filter-id")), + url: "/json/realm/filters/" + encodeURIComponent(btn.attr("data-linkifier-id")), error(xhr) { ui_report.generic_row_button_error(xhr, btn); }, @@ -111,38 +111,38 @@ export function build_page() { }); }); - $(".organization form.admin-filter-form") + $(".organization form.admin-linkifier-form") .off("submit") .on("submit", function (e) { e.preventDefault(); e.stopPropagation(); - const filter_status = $("#admin-filter-status"); - const pattern_status = $("#admin-filter-pattern-status"); - const format_status = $("#admin-filter-format-status"); - const add_filter_button = $(".new-filter-form button"); - add_filter_button.prop("disabled", true); - filter_status.hide(); + const linkifier_status = $("#admin-linkifier-status"); + const pattern_status = $("#admin-linkifier-pattern-status"); + const format_status = $("#admin-linkifier-format-status"); + const add_linkifier_button = $(".new-linkifier-form button"); + add_linkifier_button.prop("disabled", true); + linkifier_status.hide(); pattern_status.hide(); format_status.hide(); - const filter = {}; + const linkifier = {}; for (const obj of $(this).serializeArray()) { - filter[obj.name] = obj.value; + linkifier[obj.name] = obj.value; } channel.post({ url: "/json/realm/filters", data: $(this).serialize(), success(data) { - $("#filter_pattern").val(""); - $("#filter_format_string").val(""); - add_filter_button.prop("disabled", false); - filter.id = data.id; - ui_report.success(i18n.t("Custom filter added!"), filter_status); + $("#linkifier_pattern").val(""); + $("#linkifier_format_string").val(""); + add_linkifier_button.prop("disabled", false); + linkifier.id = data.id; + ui_report.success(i18n.t("Custom linkifier added!"), linkifier_status); }, error(xhr) { const errors = JSON.parse(xhr.responseText).errors; - add_filter_button.prop("disabled", false); + add_linkifier_button.prop("disabled", false); if (errors.pattern !== undefined) { xhr.responseText = JSON.stringify({msg: errors.pattern}); ui_report.error(i18n.t("Failed"), xhr, pattern_status); @@ -153,7 +153,7 @@ export function build_page() { } if (errors.__all__ !== undefined) { xhr.responseText = JSON.stringify({msg: errors.__all__}); - ui_report.error(i18n.t("Failed"), xhr, filter_status); + ui_report.error(i18n.t("Failed"), xhr, linkifier_status); } }, }); diff --git a/static/js/settings_sections.js b/static/js/settings_sections.js index 8a418ee89b..d79fda294e 100644 --- a/static/js/settings_sections.js +++ b/static/js/settings_sections.js @@ -56,7 +56,7 @@ export function initialize() { load_func_dict.set("org_users", settings_users.set_up_humans); load_func_dict.set("emoji-settings", settings_emoji.set_up); load_func_dict.set("default-streams-list", settings_streams.set_up); - load_func_dict.set("filter-settings", settings_linkifiers.set_up); + load_func_dict.set("linkifier-settings", settings_linkifiers.set_up); load_func_dict.set("invites-list-admin", settings_invites.set_up); load_func_dict.set("user-groups-admin", settings_user_groups.set_up); load_func_dict.set("profile-field-settings", settings_profile_fields.set_up); diff --git a/static/styles/settings.css b/static/styles/settings.css index 32a28646f4..7c30224423 100644 --- a/static/styles/settings.css +++ b/static/styles/settings.css @@ -185,9 +185,9 @@ h3 .fa-question-circle-o { word-break: break-all; } -#filter-settings { - #filter_pattern, - #filter_format_string { +#linkifier-settings { + #linkifier_pattern, + #linkifier_format_string { width: calc(100% - 10em - 6em); } } @@ -657,7 +657,7 @@ input[type="checkbox"] { } .add-new-profile-field-box, -.add-new-filter-box { +.add-new-linkifier-box { button { margin-left: calc(10em + 20px) !important; } @@ -682,8 +682,8 @@ input[type="checkbox"] { } } -#admin-filter-pattern-status, -#admin-filter-format-status { +#admin-linkifier-pattern-status, +#admin-linkifier-format-status { margin: 20px 0 0 0; } @@ -870,7 +870,7 @@ input[type="checkbox"] { #create_bot_form, #create_alert_word_form, .admin-emoji-form, -.admin-filter-form, +.admin-linkifier-form, .admin-profile-field-form, .edit_bot_form { .control-label { @@ -1825,12 +1825,12 @@ body:not(.night-mode) #settings_page .custom_user_field .datepicker { margin: auto; } - #filter-settings .new-filter-form, + #linkifier-settings .new-linkifier-form, #profile-field-settings .new-profile-field-form { width: 100%; } - #filter-settings .new-filter-form .control-label, + #linkifier-settings .new-linkifier-form .control-label, #profile-field-settings .new-profile-field-form .control-label { display: block; width: 120px; @@ -1841,7 +1841,7 @@ body:not(.night-mode) #settings_page .custom_user_field .datepicker { float: none; } - #filter-settings .new-filter-form .controls, + #linkifier-settings .new-linkifier-form .controls, #profile-field-settings .new-profile-field-form .controls { margin: auto; text-align: center; diff --git a/static/templates/admin_filter_list.hbs b/static/templates/admin_filter_list.hbs deleted file mode 100644 index 40c5737cb2..0000000000 --- a/static/templates/admin_filter_list.hbs +++ /dev/null @@ -1,17 +0,0 @@ -{{#with filter}} - - - {{pattern}} - - - {{url_format_string}} - - {{#if ../can_modify}} - - - - {{/if}} - -{{/with}} diff --git a/static/templates/admin_linkifier_list.hbs b/static/templates/admin_linkifier_list.hbs new file mode 100644 index 0000000000..4f20d7bd3a --- /dev/null +++ b/static/templates/admin_linkifier_list.hbs @@ -0,0 +1,17 @@ +{{#with linkifier}} + + + {{pattern}} + + + {{url_format_string}} + + {{#if ../can_modify}} + + + + {{/if}} + +{{/with}} diff --git a/static/templates/settings/linkifier_settings_admin.hbs b/static/templates/settings/linkifier_settings_admin.hbs index dfeba46b97..448ca3a023 100644 --- a/static/templates/settings/linkifier_settings_admin.hbs +++ b/static/templates/settings/linkifier_settings_admin.hbs @@ -1,4 +1,4 @@ -
+

@@ -36,25 +36,25 @@

{{#tr this}} - More details are available in the Help Center article. + More details are available in the Help Center article. {{/tr}}

{{#if is_admin}} -
-
-
-
{{t "Add a new linkifier" }}
-
+ +
+
+
{{t "Add a new linkifier" }}
+
- - -
+ + +
- - -
+ + +
diff --git a/static/third/marked/lib/marked.js b/static/third/marked/lib/marked.js index ebe5daf13c..eebf3cb429 100644 --- a/static/third/marked/lib/marked.js +++ b/static/third/marked/lib/marked.js @@ -484,7 +484,7 @@ var inline = { stream: noop, tex: noop, timestamp: noop, - realm_filters: [], + linkifiers: [], text: /^[\s\S]+?(?=[\\]+)>/, - realm_filters: [], + linkifiers: [], text: replace(inline.breaks.text) ('|', '|(\ud83c[\udd00-\udfff]|\ud83d[\udc00-\ude4f]|' + '\ud83d[\ude80-\udeff]|\ud83e[\udd00-\uddff]|' + @@ -645,12 +645,12 @@ InlineLexer.prototype.output = function(src) { continue; } - // realm_filters (Zulip) + // linkifier (Zulip) var self = this; - this.rules.realm_filters.forEach(function (realm_filter) { - var ret = self.inlineReplacement(realm_filter, src, function(regex, groups, match) { + this.rules.linkifiers.forEach(function (linkifier) { + var ret = self.inlineReplacement(linkifier, src, function(regex, groups, match) { // Insert the created URL - href = self.realm_filter(regex, groups, match); + href = self.linkifier(regex, groups, match); if (href !== undefined) { href = escape(href); return self.renderer.link(href, href, match); @@ -890,11 +890,11 @@ InlineLexer.prototype.timestamp = function (time) { return this.options.timestampHandler(time); }; -InlineLexer.prototype.realm_filter = function (filter, matches, orig) { - if (typeof this.options.realmFilterHandler !== 'function') +InlineLexer.prototype.linkifier = function (linkifier, matches, orig) { + if (typeof this.options.linkifierHandler !== 'function') return; - return this.options.realmFilterHandler(filter, matches); + return this.options.linkifierHandler(linkifier, matches); }; InlineLexer.prototype.usermention = function (username, orig, silent) { diff --git a/templates/zerver/api/get-messages.md b/templates/zerver/api/get-messages.md index fc64b1a38d..0cbfa874c1 100644 --- a/templates/zerver/api/get-messages.md +++ b/templates/zerver/api/get-messages.md @@ -42,5 +42,5 @@ A typical successful JSON response may look like: {generate_code_example|/messages:get|fixture(200)} [status-messages]: /help/format-your-message-using-markdown#status-messages -[linkification-filters]: /help/add-a-custom-linkification-filter +[linkifiers]: /help/add-a-custom-linkifier [message-flags]: /api/update-message-flags#available-flags diff --git a/templates/zerver/app/settings_overlay.html b/templates/zerver/app/settings_overlay.html index 91276b65ae..99524529cb 100644 --- a/templates/zerver/app/settings_overlay.html +++ b/templates/zerver/app/settings_overlay.html @@ -127,7 +127,7 @@ {% endif %} {% endif %} -
  • +
  • {{ _('Linkifiers') }}
    {% if not is_admin %} diff --git a/templates/zerver/for/companies.md b/templates/zerver/for/companies.md index 8e2624d71b..dda1cea319 100644 --- a/templates/zerver/for/companies.md +++ b/templates/zerver/for/companies.md @@ -57,7 +57,7 @@ Get events from GitHub, Stripe, Travis CI, JIRA, and [hundreds of other tools](/integrations) right in Zulip. Use topics to give each issue or decision its own place for discussion. Link to tickets in external sites with -[custom linkification filters](/help/add-a-custom-linkification-filter) like +[custom linkification filters](/help/add-a-custom-linkifier) like `Z1234` for Zendesk ticket #1234. ### Rich message formatting. diff --git a/templates/zerver/for/open-source.md b/templates/zerver/for/open-source.md index 36d23311bb..c4c2597e28 100644 --- a/templates/zerver/for/open-source.md +++ b/templates/zerver/for/open-source.md @@ -147,7 +147,7 @@ so they are useful for posterity. Efficiently refer to issues or code reviews with notation like `#1234` or `T1234`. You can set up any regex as a -[custom linkification filter](/help/add-a-custom-linkification-filter) for +[custom linkification filter](/help/add-a-custom-linkifier) for your organization. ### Hundreds of integrations. diff --git a/templates/zerver/help/add-a-custom-linkification-filter.md b/templates/zerver/help/add-a-custom-linkifier.md similarity index 91% rename from templates/zerver/help/add-a-custom-linkification-filter.md rename to templates/zerver/help/add-a-custom-linkifier.md index bdbd2965e4..45258a7668 100644 --- a/templates/zerver/help/add-a-custom-linkification-filter.md +++ b/templates/zerver/help/add-a-custom-linkifier.md @@ -1,20 +1,20 @@ -# Add a custom linkification filter +# Add a custom linkifier {!admin-only.md!} Linkifiers make it easy to refer to issues or tickets in third party issue trackers, like GitHub, Salesforce, Zendesk, and others. -For instance, you can add a filter that automatically turns `#2468` +For instance, you can add a linkifier that automatically turns `#2468` into a link to `https://github.com/zulip/zulip/issues/2468`. If the pattern appears in a message topic, Zulip adds a little button to the right of the topic that links to the appropriate URL. -### Add a custom linkification filter +### Add a custom linkifier {start_tabs} -{settings_tab|filter-settings} +{settings_tab|linkifier-settings} 1. Under **Add a new linkifier**, enter a **Pattern** and **URL format string**. diff --git a/templates/zerver/help/format-your-message-using-markdown.md b/templates/zerver/help/format-your-message-using-markdown.md index 8eb3443af7..cb3021d5b7 100644 --- a/templates/zerver/help/format-your-message-using-markdown.md +++ b/templates/zerver/help/format-your-message-using-markdown.md @@ -62,7 +62,7 @@ Numbered lists ## Links Zulip auto-linkifies URLs and valid stream names. You can also add a -[custom linkifier](/help/add-a-custom-linkification-filter) to link +[custom linkifier](/help/add-a-custom-linkifier) to link patterns like `#1234` to your ticketing system. ``` diff --git a/templates/zerver/help/getting-your-organization-started-with-zulip.md b/templates/zerver/help/getting-your-organization-started-with-zulip.md index 870d2626bf..a5ebd385c3 100644 --- a/templates/zerver/help/getting-your-organization-started-with-zulip.md +++ b/templates/zerver/help/getting-your-organization-started-with-zulip.md @@ -109,7 +109,7 @@ expert teaching other users how to use Zulip. ## Bonus things to set up * [Add custom profile fields](/help/add-custom-profile-fields). -- [Automatically linkify](/help/add-a-custom-linkification-filter) +- [Automatically linkify](/help/add-a-custom-linkifier) issue numbers. - [Write custom integrations](/api/integrations-overview) for your team’s workflow. diff --git a/templates/zerver/help/include/sidebar_index.md b/templates/zerver/help/include/sidebar_index.md index 43df40f886..cc3a0024ff 100644 --- a/templates/zerver/help/include/sidebar_index.md +++ b/templates/zerver/help/include/sidebar_index.md @@ -137,7 +137,7 @@ * [Require topics in stream messages](/help/require-topics) * [Add custom emoji](/help/add-custom-emoji) * [Configure authentication methods](/help/configure-authentication-methods) -* [Add a custom linkification filter](/help/add-a-custom-linkification-filter) +* [Add a custom linkifier](/help/add-a-custom-linkifier) * [Message retention policy](/help/message-retention-policy) * [SAML authentication](/help/saml-authentication) diff --git a/zerver/lib/markdown/help_settings_links.py b/zerver/lib/markdown/help_settings_links.py index d3fe23b3d1..fd4009f851 100644 --- a/zerver/lib/markdown/help_settings_links.py +++ b/zerver/lib/markdown/help_settings_links.py @@ -58,7 +58,11 @@ link_mapping = { "Default streams", "/#organization/default-streams-list", ], - "filter-settings": ["Manage organization", "Linkifiers", "/#organization/filter-settings"], + "linkifier-settings": [ + "Manage organization", + "Linkifiers", + "/#organization/linkifier-settings", + ], "profile-field-settings": [ "Manage organization", "Custom profile fields", diff --git a/zerver/openapi/zulip.yaml b/zerver/openapi/zulip.yaml index 9bb5875afd..a571a62d0d 100644 --- a/zerver/openapi/zulip.yaml +++ b/zerver/openapi/zulip.yaml @@ -2321,7 +2321,7 @@ paths: additionalProperties: false description: | Event sent to all users in a Zulip organization when the - set of configured [linkifiers](/help/add-a-custom-linkification-filter) + set of configured [linkifiers](/help/add-a-custom-linkifier) for the organization has changed. Processing this event is important to doing Markdown local echo @@ -5779,7 +5779,7 @@ paths: tags: ["server_and_organizations"] description: | List all of an organization's configured - [linkifiers](/help/add-a-custom-linkification-filter), regular + [linkifiers](/help/add-a-custom-linkifier), regular expression patterns that are automatically linkified when they appear in messages and topics. @@ -5829,7 +5829,7 @@ paths: operationId: add_linkifier tags: ["server_and_organizations"] description: | - Configure [linkifiers](/help/add-a-custom-linkification-filter), + Configure [linkifiers](/help/add-a-custom-linkifier), regular expression patterns that are automatically linkified when they appear in messages and topics. @@ -5877,7 +5877,7 @@ paths: operationId: remove_linkifier tags: ["server_and_organizations"] description: | - Remove [linkifiers](/help/add-a-custom-linkification-filter), regular + Remove [linkifiers](/help/add-a-custom-linkifier), regular expression patterns that are automatically linkified when they appear in messages and topics. @@ -6164,7 +6164,7 @@ paths: Present if `realm_filters` is present in `fetch_event_types`. An array of tuples (fixed-length arrays) where each tuple describes - a single realm filter ([linkifier](/help/add-a-custom-linkification-filter). + a single realm filter ([linkifier](/help/add-a-custom-linkifier). The first element of the tuple is a string regex pattern which represents the pattern that should be linkified on matching. diff --git a/zerver/webhooks/stripe/doc.md b/zerver/webhooks/stripe/doc.md index c36b5626e5..8ab28b57a1 100644 --- a/zerver/webhooks/stripe/doc.md +++ b/zerver/webhooks/stripe/doc.md @@ -12,7 +12,7 @@ Get Zulip notifications for Stripe events! **Add endpoint**. 1. [Optional] In Zulip, add a - [linkification filter](/help/add-a-custom-linkification-filter) with + [linkification filter](/help/add-a-custom-linkifier) with **Pattern** `(?Pcus_[0-9a-zA-Z]+)` and **URL format string** `https://dashboard.stripe.com/customers/%(id)s`.