mirror of https://github.com/zulip/zulip.git
markdown: Fix stream link handler in corner cases.
* Fixes handling of multiple stream links and invalid stream names. * Fixes text regex so it handle hash sign the right way. * Adds tests for these stream link cases.
This commit is contained in:
parent
852bc6b491
commit
ade3bda025
|
@ -1,6 +1,8 @@
|
||||||
/*global Dict */
|
/*global Dict */
|
||||||
var path = require('path');
|
var path = require('path');
|
||||||
var fs = require('fs');
|
var fs = require('fs');
|
||||||
|
var jsdom = require("jsdom");
|
||||||
|
var window = jsdom.jsdom().defaultView;
|
||||||
|
|
||||||
global.stub_out_jquery();
|
global.stub_out_jquery();
|
||||||
|
|
||||||
|
@ -30,6 +32,8 @@ add_dependencies({
|
||||||
marked: 'third/marked/lib/marked.js',
|
marked: 'third/marked/lib/marked.js',
|
||||||
emoji: 'js/emoji.js',
|
emoji: 'js/emoji.js',
|
||||||
people: 'js/people.js',
|
people: 'js/people.js',
|
||||||
|
stream_data: 'js/stream_data.js',
|
||||||
|
hashchange: 'js/hashchange',
|
||||||
fenced_code: 'js/fenced_code.js'
|
fenced_code: 'js/fenced_code.js'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -49,6 +53,9 @@ set_global('$', function (obj) {
|
||||||
|
|
||||||
set_global('feature_flags', {local_echo: true});
|
set_global('feature_flags', {local_echo: true});
|
||||||
|
|
||||||
|
jsdom.changeURL(window, 'http://zulip.zulipdev.com');
|
||||||
|
set_global('window', window);
|
||||||
|
|
||||||
var people = global.people;
|
var people = global.people;
|
||||||
|
|
||||||
people.add({
|
people.add({
|
||||||
|
@ -57,6 +64,25 @@ people.add({
|
||||||
email: 'cordelia@zulip.com'
|
email: 'cordelia@zulip.com'
|
||||||
});
|
});
|
||||||
|
|
||||||
|
var stream_data = global.stream_data;
|
||||||
|
var denmark = {
|
||||||
|
subscribed: false,
|
||||||
|
color: 'blue',
|
||||||
|
name: 'Denmark',
|
||||||
|
stream_id: 1,
|
||||||
|
in_home_view: false
|
||||||
|
};
|
||||||
|
var social = {
|
||||||
|
subscribed: true,
|
||||||
|
color: 'red',
|
||||||
|
name: 'social',
|
||||||
|
stream_id: 2,
|
||||||
|
in_home_view: true,
|
||||||
|
invite_only: true
|
||||||
|
};
|
||||||
|
stream_data.add_sub('Denmark', denmark);
|
||||||
|
stream_data.add_sub('social', social);
|
||||||
|
|
||||||
var echo = require('js/echo.js');
|
var echo = require('js/echo.js');
|
||||||
|
|
||||||
var bugdown_data = JSON.parse(fs.readFileSync(path.join(__dirname, '../../zerver/fixtures/bugdown-data.json'), 'utf8', 'r'));
|
var bugdown_data = JSON.parse(fs.readFileSync(path.join(__dirname, '../../zerver/fixtures/bugdown-data.json'), 'utf8', 'r'));
|
||||||
|
@ -79,6 +105,7 @@ var bugdown_data = JSON.parse(fs.readFileSync(path.join(__dirname, '../../zerver
|
||||||
"User Mention @**leo**",
|
"User Mention @**leo**",
|
||||||
"User Mention @**leo f**",
|
"User Mention @**leo f**",
|
||||||
"User Mention @**leo with some name**",
|
"User Mention @**leo with some name**",
|
||||||
|
"Stream #**Verona**",
|
||||||
"This contains !gravatar(leo@zulip.com)",
|
"This contains !gravatar(leo@zulip.com)",
|
||||||
"And an avatar !avatar(leo@zulip.com) is here"
|
"And an avatar !avatar(leo@zulip.com) is here"
|
||||||
];
|
];
|
||||||
|
@ -138,6 +165,12 @@ var bugdown_data = JSON.parse(fs.readFileSync(path.join(__dirname, '../../zerver
|
||||||
expected: '<blockquote>\n<p>quote this for me</p>\n</blockquote>\n<p>thanks</p>'},
|
expected: '<blockquote>\n<p>quote this for me</p>\n</blockquote>\n<p>thanks</p>'},
|
||||||
{input: 'This is a @**Cordelia Lear** mention',
|
{input: 'This is a @**Cordelia Lear** mention',
|
||||||
expected: '<p>This is a <span class="user-mention" data-user-email="cordelia@zulip.com">@Cordelia Lear</span> mention</p>'},
|
expected: '<p>This is a <span class="user-mention" data-user-email="cordelia@zulip.com">@Cordelia Lear</span> mention</p>'},
|
||||||
|
{input: 'This is a #**Denmark** stream link',
|
||||||
|
expected: '<p>This is a <a class="stream" data-stream-id="1" href="http://zulip.zulipdev.com/#narrow/stream/Denmark">#Denmark</a> stream link</p>'},
|
||||||
|
{input: 'This is #**Denmark** and #**social** stream links',
|
||||||
|
expected: '<p>This is <a class="stream" data-stream-id="1" href="http://zulip.zulipdev.com/#narrow/stream/Denmark">#Denmark</a> and <a class="stream" data-stream-id="2" href="http://zulip.zulipdev.com/#narrow/stream/social">#social</a> stream links</p>'},
|
||||||
|
{input: 'And this is a #**wrong** stream link',
|
||||||
|
expected: '<p>And this is a #**wrong** stream link</p>'},
|
||||||
{input: 'mmm...:burrito:s',
|
{input: 'mmm...:burrito:s',
|
||||||
expected: '<p>mmm...<img alt=\":burrito:\" class=\"emoji\" src=\"/static/third/gemoji/images/emoji/burrito.png\" title=\":burrito:\">s</p>'},
|
expected: '<p>mmm...<img alt=\":burrito:\" class=\"emoji\" src=\"/static/third/gemoji/images/emoji/burrito.png\" title=\":burrito:\">s</p>'},
|
||||||
{input: 'This is an :poop: message',
|
{input: 'This is an :poop: message',
|
||||||
|
|
|
@ -327,6 +327,18 @@ function handleUserMentions(username) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function handleStream(streamName) {
|
||||||
|
var stream = stream_data.get_sub(streamName);
|
||||||
|
if (stream === undefined) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return '<a class="stream" data-stream-id="' + stream.stream_id + '" ' +
|
||||||
|
'href="' + window.location.origin + '/#narrow/stream/' +
|
||||||
|
hashchange.encodeHashComponent(stream.name) + '"' +
|
||||||
|
'>' + '#' + stream.name + '</a>';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
function handleRealmFilter(pattern, matches) {
|
function handleRealmFilter(pattern, matches) {
|
||||||
var url = realm_filter_map[pattern];
|
var url = realm_filter_map[pattern];
|
||||||
|
|
||||||
|
@ -340,10 +352,6 @@ function handleRealmFilter(pattern, matches) {
|
||||||
return url;
|
return url;
|
||||||
}
|
}
|
||||||
|
|
||||||
function handleStreamLinks(stream_name) {
|
|
||||||
return '<a href="' + window.location.origin + '#narrow/stream/' + hashchange.encodeHashComponent(stream_name) + '">#' + stream_name + '</a>';
|
|
||||||
}
|
|
||||||
|
|
||||||
function python_to_js_filter(pattern, url) {
|
function python_to_js_filter(pattern, url) {
|
||||||
// Converts a python named-group regex to a javascript-compatible numbered
|
// Converts a python named-group regex to a javascript-compatible numbered
|
||||||
// group regex... with a regex!
|
// group regex... with a regex!
|
||||||
|
@ -487,7 +495,7 @@ $(function () {
|
||||||
avatarHandler: handleAvatar,
|
avatarHandler: handleAvatar,
|
||||||
unicodeEmojiHandler: handleUnicodeEmoji,
|
unicodeEmojiHandler: handleUnicodeEmoji,
|
||||||
userMentionHandler: handleUserMentions,
|
userMentionHandler: handleUserMentions,
|
||||||
streamLinkHandler: handleStreamLinks,
|
streamHandler: handleStream,
|
||||||
realmFilterHandler: handleRealmFilter,
|
realmFilterHandler: handleRealmFilter,
|
||||||
renderer: r,
|
renderer: r,
|
||||||
preprocessors: [preprocess_code_blocks]
|
preprocessors: [preprocess_code_blocks]
|
||||||
|
|
|
@ -477,6 +477,7 @@ var inline = {
|
||||||
emoji: noop,
|
emoji: noop,
|
||||||
unicodeemoji: noop,
|
unicodeemoji: noop,
|
||||||
usermention: noop,
|
usermention: noop,
|
||||||
|
stream: noop,
|
||||||
avatar: noop,
|
avatar: noop,
|
||||||
gravatar: noop,
|
gravatar: noop,
|
||||||
realm_filters: [],
|
realm_filters: [],
|
||||||
|
@ -537,13 +538,13 @@ inline.zulip = merge({}, inline.breaks, {
|
||||||
emoji: /^:([A-Za-z0-9_\-\+]+?):/,
|
emoji: /^:([A-Za-z0-9_\-\+]+?):/,
|
||||||
unicodeemoji: /^(\ud83c[\udf00-\udfff]|\ud83d[\udc00-\ude4f]|\ud83d[\ude80-\udeff])/,
|
unicodeemoji: /^(\ud83c[\udf00-\udfff]|\ud83d[\udc00-\ude4f]|\ud83d[\ude80-\udeff])/,
|
||||||
usermention: /^(@(?:\*\*([^\*]+)?\*\*|(\w+)?))/m, // Match multi-word string between @** ** or match any one-word
|
usermention: /^(@(?:\*\*([^\*]+)?\*\*|(\w+)?))/m, // Match multi-word string between @** ** or match any one-word
|
||||||
streamlink: /^(#\*\*([^\*]+)\*\*)/,
|
stream: /^#\*\*([^\*]+)\*\*/m,
|
||||||
avatar: /^!avatar\(([^)]+)\)/,
|
avatar: /^!avatar\(([^)]+)\)/,
|
||||||
gravatar: /^!gravatar\(([^)]+)\)/,
|
gravatar: /^!gravatar\(([^)]+)\)/,
|
||||||
realm_filters: [],
|
realm_filters: [],
|
||||||
text: replace(inline.breaks.text)
|
text: replace(inline.breaks.text)
|
||||||
('|', '|(\ud83c[\udf00-\udfff]|\ud83d[\udc00-\ude4f]|\ud83d[\ude80-\udeff])|')
|
('|', '|(\ud83c[\udf00-\udfff]|\ud83d[\udc00-\ude4f]|\ud83d[\ude80-\udeff])|')
|
||||||
(']|', '@:]|')
|
(']|', '#@:]|')
|
||||||
()
|
()
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -725,10 +726,11 @@ InlineLexer.prototype.output = function(src) {
|
||||||
out += this.usermention(cap[2] || cap[3], cap[1]);
|
out += this.usermention(cap[2] || cap[3], cap[1]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// streamlink (zulip)
|
|
||||||
if (cap = this.rules.streamlink.exec(src)) {
|
// stream (zulip)
|
||||||
|
if (cap = this.rules.stream.exec(src)) {
|
||||||
src = src.substring(cap[0].length);
|
src = src.substring(cap[0].length);
|
||||||
out += this.streamlink(cap[2], cap[1]);
|
out += this.stream(cap[1], cap[0]);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -870,22 +872,16 @@ InlineLexer.prototype.usermention = function (username, orig) {
|
||||||
return orig;
|
return orig;
|
||||||
};
|
};
|
||||||
|
|
||||||
InlineLexer.prototype.streamlink = function(stream_name, orig) {
|
InlineLexer.prototype.stream = function (streamName, orig) {
|
||||||
if (stream_data.get_sub(stream_name) === undefined) {
|
if (typeof this.options.streamHandler !== 'function')
|
||||||
return orig;
|
return orig;
|
||||||
}
|
|
||||||
if (typeof this.options.streamLinkHandler !== 'function')
|
|
||||||
{
|
|
||||||
return orig;
|
|
||||||
}
|
|
||||||
|
|
||||||
var handled = this.options.streamLinkHandler(stream_name);
|
var handled = this.options.streamHandler(streamName);
|
||||||
if (handled !== undefined) {
|
if (handled !== undefined) {
|
||||||
return handled;
|
return handled;
|
||||||
}
|
}
|
||||||
|
|
||||||
return orig;
|
return orig;
|
||||||
}
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Smartypants Transformations
|
* Smartypants Transformations
|
||||||
|
|
Loading…
Reference in New Issue