1 # -*- coding: iso-8859-1 -*- 2 """ 3 MoinMoin - SectionBreakout 4 5 Break sections out of a page, making new pages for each of the sections and 6 replacing them with Include macros. 7 8 @copyright: 2011 Paul Boddie <paul@boddie.org.uk> 9 @license: GNU GPL, see COPYING for details. 10 """ 11 12 Dependencies = ['pages'] 13 14 from MoinMoin.action import ActionBase 15 from MoinMoin.PageEditor import PageEditor 16 from MoinContentSupport import * 17 import re 18 19 # Action class and supporting functions. 20 21 class SectionBreakout(ActionBase, ActionSupport): 22 23 "An action breaking sections out of pages." 24 25 def get_form_html(self, buttons_html): 26 _ = self._ 27 request = self.request 28 page = self.page 29 form = self.get_form() 30 31 level = int(form.get("level", ["2"])[0]) 32 33 # Acquire heading details from the page. 34 35 body = page.get_raw_body() 36 heading_details = getSectionDetails(body, level, level) 37 38 d = { 39 "buttons_html" : buttons_html, 40 "heading_level_label" : escape(_("Heading level")), 41 "found_headings_label" : escape(_("Headings found in page")), 42 "propagate_categories_label" : escape(_("Propagate categories")), 43 "preview_label" : escape(_("Preview")), 44 "level" : escattr(level), 45 } 46 47 html = u''' 48 <table> 49 <tr> 50 <td class="label">%(heading_level_label)s</td> 51 <td><input type="text" name="level" value="%(level)s" size="2" /></td> 52 </tr> 53 <tr> 54 <td class="label">%(found_headings_label)s</td> 55 <td>''' % d 56 57 for heading, level, span in heading_details: 58 if heading is not None: 59 html += "%s<br />" % escape(heading) 60 61 html += ''' 62 </td> 63 </tr> 64 <tr> 65 <td class="label">%(propagate_categories_label)s</td> 66 <td class="buttons"><input type="checkbox" name="propagate" value="yes" /></td> 67 </tr> 68 <tr> 69 <td></td> 70 <td class="buttons"><input type="submit" value="%(preview_label)s" />%(buttons_html)s</td> 71 </tr> 72 </table> 73 ''' % d 74 75 return html 76 77 def do_action(self): 78 79 "Create the new event." 80 81 _ = self._ 82 form = self.get_form() 83 84 # A heading level must be provided. 85 86 level = form.get("level", [None])[0] 87 propagate = form.get("propagate", [None])[0] 88 89 if not level: 90 return 0, _("No heading level specified.") 91 92 return self.break_out_headings(int(level), propagate) 93 94 def render_success(self, msg, msgtype=None): 95 96 """ 97 Render neither 'msg' nor 'msgtype' since redirection should occur 98 instead. 99 NOTE: msgtype is optional because MoinMoin 1.5.x does not support it. 100 """ 101 102 pass 103 104 def break_out_headings(self, level, propagate): 105 106 """ 107 Break out headings at the given 'level' from the current page. If 108 'propagate' is a true value, propagate categories to subpages. 109 """ 110 111 _ = self._ 112 request = self.request 113 page = self.page 114 formatter = request.formatter 115 116 # Acquire all heading details from the page. 117 118 page_body = page.get_raw_body() 119 120 if propagate: 121 categories = getCategoryMembership(page_body) 122 123 regions = [] 124 current_region_start = None 125 126 for heading, found_level, (start, end) in getSectionDetails(page_body): 127 128 # Where a heading is provided, consider starting a section. 129 130 if found_level is not None: 131 132 # Upon finding a suitable heading, begin a new region to be broken 133 # out. 134 135 if current_region_start is None and found_level >= level: 136 current_region_start = heading, start 137 138 # Upon finding a same-level or higher-level heading, end any open 139 # region. 140 141 elif current_region_start is not None and found_level <= level: 142 regions.append(current_region_start + (start,)) 143 144 # For headings at the requested level, open a new region. 145 146 if found_level == level: 147 current_region_start = heading, start 148 else: 149 current_region_start = None 150 151 # Where no heading is provided, end the section. 152 153 elif current_region_start is not None: 154 regions.append(current_region_start + (start,)) 155 current_region_start = None 156 157 # End any open region. 158 159 else: 160 if current_region_start is not None: 161 heading, region_start = current_region_start 162 163 # Prevent any capture of end-of-page category information. 164 165 l = getCategoryDeclarations(page_body) 166 if not l: 167 region_end = len(page_body) 168 else: 169 declaration, (start, end) = l[-1] 170 region_end = max(region_start, start) 171 172 regions.append((heading, region_start, region_end)) 173 174 # Make new pages for each region, rebuilding the current page body. 175 176 retained_regions = [] 177 retained_region_start = 0 178 new_page_names = {} 179 180 for heading, start, end in regions: 181 182 # Combine the page name and the heading to make a subpage. 183 184 new_page_name = "%s/%s" % (page.page_name, heading) 185 186 # Distinguish between pages which use the same heading. 187 188 n = new_page_names.get(new_page_name, 0) 189 if n: 190 new_page_names[new_page_name] = n + 1 191 new_page_name += " (%d)" % (n + 1) 192 else: 193 new_page_names[new_page_name] = n + 1 194 195 # Open the page for editing. 196 197 new_page = PageEditor(request, new_page_name) 198 new_page_body = page_body[start:end] 199 200 if propagate: 201 new_page_categories = getCategoryMembership(new_page_body) 202 203 # Add categories if the parent page has any. 204 205 if new_page_categories != categories: 206 new_page_body += makeCategoryDeclaration(categories) 207 208 # Save the new page. 209 210 try: 211 new_page.saveText(new_page_body, 0) 212 except PageEditor.Unchanged: 213 pass 214 215 # Retain the preceding region for the current page. 216 217 retained_regions.append(page_body[retained_region_start:start]) 218 219 # Insert Include macros for the broken out text. 220 221 retained_regions.append("<<Include(%s,,editlink)>>\n" % new_page_name) 222 223 # Start a new region to retain. 224 225 retained_region_start = end 226 227 # Retain any remaining text. 228 229 else: 230 retained_regions.append(page_body[retained_region_start:]) 231 232 # Edit the current page. 233 234 edited_page = PageEditor(request, page.page_name) 235 edited_page_body = "".join(retained_regions) 236 237 if propagate: 238 edited_page_categories = getCategoryMembership(edited_page_body) 239 240 # Add categories if the parent page should have any, but these were 241 # broken out. 242 243 if edited_page_categories != categories: 244 edited_page_body += makeCategoryDeclaration(categories) 245 246 # Save the current page. 247 248 edited_page.saveText(edited_page_body, 0) 249 250 # NOTE: Perhaps show a message upon failure. 251 252 request.http_redirect(page.url(request)) 253 return 1, None 254 255 # Action function. 256 257 def execute(pagename, request): 258 SectionBreakout(pagename, request).render() 259 260 # vim: tabstop=4 expandtab shiftwidth=4