message-edit: Patch html tags after edits on new lines.

This commit is contained in:
Jack Zhang
2017-06-09 16:49:12 -07:00
committed by showell
parent cf503017d2
commit af3b7d4c98
2 changed files with 83 additions and 17 deletions

View File

@@ -74,6 +74,21 @@ def verify_html(html):
return False
return True
def check_tags(text):
# type: (Text) -> Text
# The current diffing algorithm produces malformed html when text is
# added to existing new lines. This patch manually corrects that.
in_tag = False
if text.endswith('<'):
text = text[:-1]
for c in text:
if c == '<':
in_tag = True
elif c == '>' and not in_tag:
text = '<' + text
break
return text
def highlight_html_differences(s1, s2):
# type: (Text, Text) -> Text
differ = diff_match_patch()
@@ -85,9 +100,15 @@ def highlight_html_differences(s1, s2):
idx = 0
while idx < len(ops):
op, text = ops[idx]
next_op = None
if idx != len(ops) - 1:
next_op, next_text = ops[idx + 1]
text = check_tags(text)
if idx != 0:
prev_op, prev_text = ops[idx - 1]
prev_text = check_tags(prev_text)
# Remove visual offset from editing newlines
if '<p><br>' in text:
text = text.replace('<p><br>', '<p>')
elif prev_text.endswith('<p>') and text.startswith('<br>'):
text = text[4:]
if op == diff_match_patch.DIFF_DELETE:
chunks, in_tag = chunkize(text, in_tag)
retval += highlight_chunks(chunks, highlight_deleted)

View File

@@ -1232,34 +1232,79 @@ class EditMessageTest(ZulipTestCase):
def test_edit_message_history(self):
# type: () -> None
self.login(self.example_email("hamlet"))
msg_id = self.send_message(self.example_email("hamlet"), "Scotland", Recipient.STREAM,
subject="editing", content="content before edit")
new_content = 'content after edit'
result = self.client_patch("/json/messages/" + str(msg_id), {
'message_id': msg_id, 'content': new_content
# Single-line edit
msg_id_1 = self.send_message(self.example_email("hamlet"),
"Scotland",
Recipient.STREAM,
subject="editing",
content="content before edit")
new_content_1 = 'content after edit'
result_1 = self.client_patch("/json/messages/" + str(msg_id_1), {
'message_id': msg_id_1, 'content': new_content_1
})
self.assert_json_success(result)
self.assert_json_success(result_1)
message_edit_history = self.client_get("/json/messages/" + str(msg_id) + "/history")
json_response = ujson.loads(message_edit_history.content.decode('utf-8'))
message_history = json_response['message_history']
message_edit_history_1 = self.client_get(
"/json/messages/" + str(msg_id_1) + "/history")
json_response_1 = ujson.loads(
message_edit_history_1.content.decode('utf-8'))
message_history_1 = json_response_1['message_history']
# Check content of message after edit.
self.assertEqual(message_history[0]['rendered_content'],
self.assertEqual(message_history_1[0]['rendered_content'],
'<p>content before edit</p>')
self.assertEqual(message_history[1]['rendered_content'],
self.assertEqual(message_history_1[1]['rendered_content'],
'<p>content after edit</p>')
self.assertEqual(message_history[1]['content_html_diff'],
self.assertEqual(message_history_1[1]['content_html_diff'],
('<p>content '
'<span class="highlight_text_deleted">before</span>'
'<span class="highlight_text_inserted">after</span>'
' edit</p>'))
# Check content of message before edit.
self.assertEqual(message_history[1]['prev_rendered_content'],
self.assertEqual(message_history_1[1]['prev_rendered_content'],
'<p>content before edit</p>')
# Edits on new lines
msg_id_2 = self.send_message(self.example_email("hamlet"),
"Scotland",
Recipient.STREAM,
subject="editing",
content=('content before edit, line 1\n'
'\n'
'content before edit, line 3'))
new_content_2 = ('content before edit, line 1\n'
'content after edit, line 2\n'
'content before edit, line 3')
result_2 = self.client_patch("/json/messages/" + str(msg_id_2), {
'message_id': msg_id_2, 'content': new_content_2
})
self.assert_json_success(result_2)
message_edit_history_2 = self.client_get(
"/json/messages/" + str(msg_id_2) + "/history")
json_response_2 = ujson.loads(
message_edit_history_2.content.decode('utf-8'))
message_history_2 = json_response_2['message_history']
self.assertEqual(message_history_2[0]['rendered_content'],
('<p>content before edit, line 1</p>\n'
'<p>content before edit, line 3</p>'))
self.assertEqual(message_history_2[1]['rendered_content'],
('<p>content before edit, line 1<br>\n'
'content after edit, line 2<br>\n'
'content before edit, line 3</p>'))
self.assertEqual(message_history_2[1]['content_html_diff'],
('<p>content before edit, line 1</p>'
'<span class="highlight_text_deleted">\n'
'</span><p><span class="highlight_text_inserted">\n'
'content after edit, line 2</span><br>'
'<span class="highlight_text_inserted">\n'
'</span>content before edit, line 3</p>'))
self.assertEqual(message_history_2[1]['prev_rendered_content'],
('<p>content before edit, line 1</p>\n'
'<p>content before edit, line 3</p>'))
def test_edit_cases(self):
# type: () -> None
"""This test verifies the accuracy of construction of Zulip's edit