To allow scrolling in Safari mobile, we set the content of text_view_comments frame in a jQuery UI layout.
So the automated scrolling operations in c_sync.js must be adjustable to the right part to scroll.
Also, if a comment have to be shown outside of the current viewport, we scroll the correct part to that viewport
and then set the comment top Y offset to juste what it needs to avoid the "Add comment" button after scrolling
operation.
If not in Safari mobile, we add an offset here to avoid comment to display under the "Add comment" button.
# -*- coding: utf-8 -*-
from difflib import SequenceMatcher
#from cm.utils.spannifier import Spannifier
import sys, operator
from cm.utils.spannifier import spannify
from cm.converters.pandoc_converters import pandoc_convert
import logging
from cm.utils.spannifier import get_the_soup
import re
import html5lib
from html5lib import treebuilders
def compute_new_comment_positions(old_content, old_format, new_content, new_format, commentList):
# cf. TextVersion.get_content
previousVersionContent = pandoc_convert(old_content, old_format, 'html')
newVersionContent = pandoc_convert(new_content, new_format, 'html')
_, previous_char_list, span_starts_previous = spannify(previousVersionContent, False)
_, new_char_list, span_starts_new = spannify(newVersionContent, False)
sm = SequenceMatcher(None, previous_char_list, new_char_list)
opcodes = sm.get_opcodes()
to_remove_comments_ids = set()
# limit to real comments (not replies) and those that have scope
commentList = [c for c in commentList if not c.is_reply() and not c.is_scope_removed()]
for comment in commentList:
try:
comment.initial_start_offset = span_starts_previous[comment.start_wrapper] + comment.start_offset
comment.initial_end_offset = span_starts_previous[comment.end_wrapper] + comment.end_offset
except KeyError:
logging.error('Key error (wrapper out of bounds of span_starts_previous)')
continue
comment.computed_start_offset = comment.initial_start_offset
comment.computed_end_offset = comment.initial_end_offset
# comment.computed_start_wrapper = None
# comment.computed_end_wrapper = None
comment.valid = True
for tag, i1, i2, j1, j2 in opcodes:
#print tag, i1, i2, j1, j2
for i in xrange(len(commentList)) :
if tag != 'equal' :
comment = commentList[i]
if not comment.valid:
continue
if comment.initial_start_offset >= i2 :
# if offset
delta = ((j2 - j1) - (i2 - i1))
comment.computed_start_offset += delta
comment.computed_end_offset += delta
elif comment.initial_end_offset > i1:
comment.valid = False
# id, initial_start, initial_end, computed_start, computed_end, valid = self.computationResults[i]
for cc in commentList:
if cc.valid:
for id in xrange(len(span_starts_new.keys())):
start = span_starts_new.get(id, 0)
end = span_starts_new.get(id+1, sys.maxint)
# adjust start
if cc.computed_start_offset >= start and cc.computed_start_offset < end:
cc.start_wrapper = id
cc.start_offset = cc.computed_start_offset - start
# adjust end
if cc.computed_end_offset >= start and cc.computed_end_offset < end:
cc.end_wrapper = id
cc.end_offset = cc.computed_end_offset - start
# returns to_modify, to_remove
return [c for c in commentList if c.valid], \
[c for c in commentList if not c.valid]
def add_marker(text, color, start_ids, end_ids, with_markers, with_colors):
# TODO
# THESE 3 LINES ARE REALLY JUST FOR TESTING THIS IS COPIED FROM C-TEXT.CSS AND SHOULD BE DONE DIFFERENTLY
BCKCOLORS = ['#ffffff', '#ffffa8', '#fff6a1', '#ffeb99', '#ffde91', '#ffd08a', '#ffc182', '#ffaf7a', '#ff9d73', '#ff896b', '#ff7363', '#ff5c5c']
for i in range(14) :
BCKCOLORS.append('#ff5c5c')
ret = text
if with_markers:
end_ids.reverse()
ret = "%s%s%s"%(''.join(["[%s>"%start_id for start_id in start_ids]), ret, ''.join(["<%s]"%end_id for end_id in end_ids]))
if with_colors and color != 0 :
# For some reasons, abiwords can read background style attribute but not background-color
from cm.cm_settings import USE_ABI
if USE_ABI:
ret = "<span style='background:%s;'>%s</span>"%(BCKCOLORS[color], ret)
else:
ret = "<span style='background-color:%s;'>%s</span>"%(BCKCOLORS[color], ret)
return ret
# comments are comments and replies :
def insert_comment_markers(htmlcontent, comments, with_markers, with_colors) :
html = get_the_soup(htmlcontent) ;
if comments :
max_wrapper = max([comment.end_wrapper for comment in comments])
min_wrapper = min([comment.start_wrapper for comment in comments])
datas = {} # { wrapper_id : {'start_color':nb_of_comments_unterminated_at_wrapper_start, 'offsets':{offset: [[ids of wrappers starting at offset], [ids of wrappers ending at offset]]}}
# datas['offsets'][someoffset][0] and idem[1] will be ordered the way comments are (should be ('start_wrapper', 'start_offset', 'end_wrapper', 'end_offset') important)
cpt = 1 # starting numbered comment
for comment in comments :
if comment.is_reply() :
continue ;
# start
wrapper_data = datas.get(comment.start_wrapper, {'start_color':0, 'offsets':{}})
offset = wrapper_data.get('offsets').get(comment.start_offset, [[],[]])
offset[0].append(cpt)
wrapper_data['offsets'][comment.start_offset] = offset
datas[comment.start_wrapper] = wrapper_data
# end
wrapper_data = datas.get(comment.end_wrapper, {'start_color':0, 'offsets':{}})
offset = wrapper_data.get('offsets').get(comment.end_offset, [[],[]])
offset[1].append(cpt)
wrapper_data['offsets'][comment.end_offset] = offset
datas[comment.end_wrapper] = wrapper_data
for cc in range(comment.start_wrapper + 1, comment.end_wrapper + 1) :
wrapper_data = datas.get(cc, {'start_color':0, 'offsets':{}})
wrapper_data['start_color'] += 1
datas[cc] = wrapper_data
cpt = cpt + 1
# order ee values
for (wrapper_id, wrapper_data) in datas.items() :
start_color = wrapper_data['start_color']
offsets = sorted(wrapper_data['offsets'].items(), key=operator.itemgetter(0))
d = html.find(id = "sv-%d"%wrapper_id)
if not d: # comment detached
continue
content = d.contents[0]
spans = ""
if offsets :
color = start_color
start = 0
start_ids = []
end_ids = []
for offset, ids in offsets :
end_ids = ids[1]
end = offset
spans += add_marker(content[start:end], color, start_ids, end_ids, with_markers, with_colors)
start_ids = ids[0]
start = end
color += (len(ids[0]) - len(ids[1]))
end_ids = []
spans += add_marker(content[end:], color,start_ids, end_ids, with_markers, with_colors)
else : # the whole content is to be colored with start_color
spans += add_marker(content, start_color, [], [], with_markers, with_colors)
content.replaceWith(spans)
output = unicode(html)
# Soup has introduced HTML entities, which should be expanded
output =re.sub(r""", '"', output)
output =re.sub(r"&", '&', output)
output =re.sub(r">", '>', output)
output =re.sub(r"<", '<', output)
return unicode(output)