Edgewall Software

Ticket #124: wiki_list_and_quote_improvements.diff

File wiki_list_and_quote_improvements.diff, 10.3 KB (added by cboos, 3 years ago)

In addition to the previous improvements to the lists, this features improvements for the quotation blocks. Diff on trunk@3278. Take 3

  • htdocs/css/trac.css

    diff -r 3a1992166861 htdocs/css/trac.css
    a b  
    275288 padding: .25em; 
    276289 overflow: auto; 
    277290} 
     291 
     292blockquote.citation {  
     293 margin: 0; 
     294 border-style: solid;  
     295 border-width: 0 0 0 0.15em;  
     296 border-color: #b44;  
     297 padding-left: .5em; 
     298} 
     299 
    278300table.wiki { 
    279301 border: 2px solid #ccc; 
    280302 border-collapse: collapse; 
  • trac/wiki/formatter.py

    diff -r 3a1992166861 trac/wiki/formatter.py
    a b  
    179179        % (INLINE_TOKEN, INLINE_TOKEN)] 
    180180 
    181181    _post_rules = [ 
     182        r"(?P<quote>^(?P<qdepth>>+))", 
    182183        r"(?P<htmlescape>[&<>])", 
    183184        # shref corresponds to short TracLinks, i.e. sns:stgt 
    184185        r"(?P<shref>!?((?P<sns>%s):(?P<stgt>%s|%s(?:%s*%s)?)))" \ 
     
    193194         r"(\]\]|\((?P<macroargs>.*?)\)\]\]))"), 
    194195        # heading, list, definition, indent, table... 
    195196        r"(?P<heading>^\s*(?P<hdepth>=+)\s.*\s(?P=hdepth)\s*$)", 
    196         r"(?P<list>^(?P<ldepth>\s+)(?:\*|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )", 
     197        r"(?P<list>^(?P<ldepth>\s+)(?:[-*]|\d+\.|[a-zA-Z]\.|[ivxIVX]{1,5}\.) )", 
    197198        r"(?P<definition>^\s+((?:%s.*?%s|%s.*?%s|[^%s%s])+?::)(?:\s+|$))" 
    198199        % (INLINE_TOKEN, INLINE_TOKEN, STARTBLOCK_TOKEN, ENDBLOCK_TOKEN, 
    199200           INLINE_TOKEN, STARTBLOCK[0]), 
     
    456457     
    457458    def _list_formatter(self, match, fullmatch): 
    458459        ldepth = len(fullmatch.group('ldepth')) 
    459         depth = int((len(fullmatch.group('ldepth')) + 1) / 2) 
    460460        listid = match[ldepth] 
    461         self.in_list_item = depth > 0 
     461        self.in_list_item = True 
    462462        class_ = start = None 
    463         if listid == '*': 
     463        if listid in '-*': 
    464464            type_ = 'ul' 
    465465        else: 
    466466            type_ = 'ol' 
     
    473473                class_ = 'loweralpha' 
    474474            elif listid.isupper(): 
    475475                class_ = 'upperalpha' 
    476         self._set_list_depth(depth, type_, class_, start) 
     476        self._set_list_depth(ldepth, type_, class_, start) 
    477477        return '' 
    478478 
    479     def _set_list_depth(self, depth, type_, class_, start): 
    480         current_depth = len(self._list_stack) 
    481         diff = depth - current_depth 
    482         self.close_table() 
    483         self.close_paragraph() 
    484         self.close_indentation() 
    485         begin_list = type_ 
    486         if class_: 
    487             begin_list += ' class="%s"' % class_ 
    488         if start: 
    489             begin_list += start and ' start="%s"' % start 
    490         if diff > 0: 
    491             for i in range(diff): 
    492                 self._list_stack.append(type_) 
    493                 self.out.write('<%s><li>' % begin_list) 
    494         elif diff < 0: 
    495             for i in range(-diff): 
    496                 tmp = self._list_stack.pop() 
    497                 self.out.write('</li></%s>' % tmp) 
    498             if self._list_stack != [] and type_ != self._list_stack[-1]: 
    499                 tmp = self._list_stack.pop() 
    500                 self._list_stack.append(type_) 
    501                 self.out.write('</li></%s><%s><li>' % (tmp, begin_list)) 
     479    def _get_list_depth(self): 
     480        """Return the space offset associated to the deepest opened list.""" 
     481        return self._list_stack and self._list_stack[-1][1] or 0 
     482         
     483    def _set_list_depth(self, depth, new_type, list_class, start): 
     484        def open_list(): 
     485            self.close_table() 
     486            self.close_paragraph() 
     487            self.close_indentation() 
     488            self._list_stack.append((new_type, depth)) 
     489            self.out.write('<%s%s%s><li>' % 
     490                           (new_type, 
     491                            list_class and ' class="%s"' % list_class or '', 
     492                            start and ' start="%s"' % start or '')) 
     493        def close_list(tp): 
     494            self._list_stack.pop() 
     495            self.out.write('</li></%s>' % tp) 
     496 
     497        # depending on the indent/dedent, open or close lists 
     498        if depth > self._get_list_depth(): 
     499            open_list() 
     500        else: 
     501            while self._list_stack: 
     502                deepest_type, deepest_offset = self._list_stack[-1] 
     503                if depth >= deepest_offset: 
     504                    break 
     505                close_list(deepest_type) 
    502506            if depth > 0: 
    503                 self.out.write('</li><li>') 
    504         # diff == 0 
    505         elif self._list_stack != [] and type_ != self._list_stack[-1]: 
    506             tmp = self._list_stack.pop() 
    507             self._list_stack.append(type_) 
    508             self.out.write('</li></%s><%s><li>' % (tmp, begin_list)) 
    509         elif depth > 0: 
    510             self.out.write('</li><li>') 
     507                if self._list_stack: 
     508                    old_type, old_offset = self._list_stack[-1] 
     509                    if old_type != new_type: 
     510                        close_list(old_type) 
     511                        open_list() 
     512                    else: 
     513                        if old_offset != depth: # adjust last depth 
     514                            self._list_stack[-1] = (old_type, depth) 
     515                        self.out.write('</li><li>') 
     516                else: 
     517                    open_list() 
    511518 
    512519    def close_list(self): 
    513         if self._list_stack != []: 
    514             self._set_list_depth(0, None, None, None) 
     520        self._set_list_depth(0, None, None, None) 
    515521 
    516522    # Definition Lists 
    517523 
     
    530536 
    531537    # Blockquote 
    532538 
     539    def _indent_formatter(self, match, fullmatch): 
     540        idepth = len(fullmatch.group('idepth')) 
     541        ldepth = self._get_list_depth() 
     542        if ldepth > 0 and 0 <= (idepth - ldepth) <= 2: 
     543            self.in_list_item = True 
     544        elif not self.in_def_list: 
     545            self._set_quote_depth(idepth) 
     546        return '' 
     547 
     548    def _quote_formatter(self, match, fullmatch): 
     549        qdepth = len(fullmatch.group('qdepth')) 
     550        self._set_quote_depth(qdepth, True) 
     551        return '' 
     552 
    533553    def close_indentation(self): 
    534         self.close_table() 
    535         self.out.write(('</blockquote>' + os.linesep) * self.indent_level) 
    536         self.indent_level = 0 
    537  
    538     def open_indentation(self, depth): 
    539         if self.in_def_list: 
    540             return 
    541         diff = depth - self.indent_level 
    542         if diff != 0: 
     554        self._set_quote_depth(0) 
     555 
     556    def _get_quote_depth(self): 
     557        """Return the space offset associated to the deepest opened quote.""" 
     558        return self._quote_stack and self._quote_stack[-1] or 0 
     559 
     560    def _set_quote_depth(self, depth, citation=False): 
     561        if depth > 0: 
     562            self.in_quote = True 
     563        def open_quote(depth): 
    543564            self.close_table() 
    544565            self.close_paragraph() 
    545             self.close_indentation() 
    546566            self.close_list() 
    547             self.indent_level = depth 
    548             self.out.write(('<blockquote>' + os.linesep) * depth) 
    549  
    550     def _indent_formatter(self, match, fullmatch): 
    551         depth = int((len(fullmatch.group('idepth')) + 1) / 2) 
    552         list_depth = len(self._list_stack) 
    553         if list_depth > 0 and depth == list_depth + 1: 
    554             self.in_list_item = 1 
    555         else: 
    556             self.open_indentation(depth) 
    557         return '' 
     567            def open_one_quote(d): 
     568                self._quote_stack.append(d) 
     569                self.out.write('<blockquote%s>%s' % 
     570                               (citation and ' class="citation"' or '', 
     571                                os.linesep)) 
     572            if citation: 
     573                for d in range(self._get_quote_depth()+1, depth+1): 
     574                    open_one_quote(d) 
     575            else: 
     576                open_one_quote(depth) 
     577        def close_quote(): 
     578            self.close_table() 
     579            self.close_paragraph() 
     580            self._quote_stack.pop() 
     581            self.out.write('</blockquote>' + os.linesep) 
     582        if depth > self._get_quote_depth(): 
     583            open_quote(depth) 
     584        else: 
     585            while self._quote_stack: 
     586                deepest_offset = self._quote_stack[-1] 
     587                if depth >= deepest_offset: 
     588                    break 
     589                close_quote() 
     590            if not citation and depth > 0: 
     591                if self._quote_stack: 
     592                    old_offset = self._quote_stack[-1] 
     593                    if old_offset != depth: # adjust last depth 
     594                        self._quote_stack[-1] = depth 
     595                else: 
     596                    open_quote(depth) 
    558597 
    559598    # Table 
    560599     
     
    638677        elif line.strip() == Formatter.ENDBLOCK: 
    639678            self.in_code_block -= 1 
    640679            if self.in_code_block == 0 and self.code_processor: 
     680                self.close_table() 
    641681                self.close_paragraph() 
    642                 self.close_table() 
    643682                self.out.write(self.code_processor.process(self.req, self.code_text)) 
    644683            else: 
    645684                self.code_text += line + os.linesep 
     
    658697        self.out = out 
    659698        self._open_tags = [] 
    660699        self._list_stack = [] 
     700        self._quote_stack = [] 
    661701 
    662702        self.in_code_block = 0 
    663703        self.in_table = 0 
    664704        self.in_def_list = 0 
    665705        self.in_table_row = 0 
    666706        self.in_table_cell = 0 
    667         self.indent_level = 0 
    668707        self.paragraph_open = 0 
    669708 
    670709        for line in text.splitlines(): 
     
    674713                continue 
    675714            # Handle Horizontal ruler 
    676715            elif line[0:4] == '----': 
     716                self.close_table() 
    677717                self.close_paragraph() 
    678718                self.close_indentation() 
    679719                self.close_list() 
    680720                self.close_def_list() 
    681                 self.close_table() 
    682721                self.out.write('<hr />' + os.linesep) 
    683722                continue 
    684723            # Handle new paragraph 
     
    692731            if escape_newlines: 
    693732                line += ' [[BR]]' 
    694733            self.in_list_item = False 
     734            self.in_quote = False 
    695735            # Throw a bunch of regexps on the problem 
    696736            result = re.sub(self.wiki.rules, self.replace, line) 
    697737 
    698738            if not self.in_list_item: 
    699739                self.close_list() 
     740 
     741            if not self.in_quote: 
     742                self.close_indentation() 
    700743 
    701744            if self.in_def_list and not line.startswith(' '): 
    702745                self.close_def_list()