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 = getHeadingDetails(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 html += "%s<br />" % heading 59 60 html += ''' 61 </td> 62 </tr> 63 <tr> 64 <td class="label">%(propagate_categories_label)s</td> 65 <td class="buttons"><input type="checkbox" name="propagate" value="yes" /></td> 66 </tr> 67 <tr> 68 <td></td> 69 <td class="buttons"><input type="submit" value="%(preview_label)s" />%(buttons_html)s</td> 70 </tr> 71 </table> 72 ''' % d 73 74 return html 75 76 def do_action(self): 77 78 "Create the new event." 79 80 _ = self._ 81 form = self.get_form() 82 83 # A heading level must be provided. 84 85 level = form.get("level", [None])[0] 86 propagate = form.get("propagate", [None])[0] 87 88 if not level: 89 return 0, _("No heading level specified.") 90 91 return self.break_out_headings(int(level), propagate) 92 93 def render_success(self, msg, msgtype=None): 94 95 """ 96 Render neither 'msg' nor 'msgtype' since redirection should occur 97 instead. 98 NOTE: msgtype is optional because MoinMoin 1.5.x does not support it. 99 """ 100 101 pass 102 103 def break_out_headings(self, level, propagate): 104 105 """ 106 Break out headings at the given 'level' from the current page. If 107 'propagate' is a true value, propagate categories to subpages. 108 """ 109 110 _ = self._ 111 request = self.request 112 page = self.page 113 formatter = request.formatter 114 115 # Acquire all heading details from the page. 116 117 page_body = page.get_raw_body() 118 119 if propagate: 120 categories = getCategoryMembership(page_body) 121 122 regions = [] 123 current_region_start = None 124 125 for heading, found_level, (start, end) in getHeadingDetails(page_body): 126 127 # Upon finding a suitable heading, begin a new region to be broken 128 # out. 129 130 if current_region_start is None and found_level >= level: 131 current_region_start = heading, start 132 133 # Upon finding a higher-level heading, end any open region. 134 135 elif current_region_start is not None and found_level <= level: 136 regions.append(current_region_start + (start,)) 137 138 # For headings at the requested level, open a new region. 139 140 if found_level == level: 141 current_region_start = heading, start 142 else: 143 current_region_start = None 144 145 # End any open region. 146 147 else: 148 if current_region_start is not None: 149 heading, region_start = current_region_start 150 151 # Prevent any capture of end-of-page category information. 152 153 l = getCategoryDeclarations(page_body) 154 if not l: 155 region_end = len(page_body) 156 else: 157 declaration, (start, end) = l[-1] 158 region_end = max(region_start, start) 159 160 regions.append((heading, region_start, region_end)) 161 162 # Make new pages for each region, rebuilding the current page body. 163 164 retained_regions = [] 165 retained_region_start = 0 166 new_page_names = {} 167 168 for heading, start, end in regions: 169 170 # Combine the page name and the heading to make a subpage. 171 172 new_page_name = "%s/%s" % (page.page_name, heading) 173 174 # Distinguish between pages which use the same heading. 175 176 n = new_page_names.get(new_page_name, 0) 177 if n: 178 new_page_names[new_page_name] = n + 1 179 new_page_name += " (%d)" % (n + 1) 180 else: 181 new_page_names[new_page_name] = n + 1 182 183 # Open the page for editing. 184 185 new_page = PageEditor(request, new_page_name) 186 new_page_body = page_body[start:end] 187 188 if propagate: 189 new_page_categories = getCategoryMembership(new_page_body) 190 191 # Add categories if the parent page has any. 192 193 if new_page_categories != categories: 194 new_page_body += makeCategoryDeclaration(categories) 195 196 # Save the new page. 197 198 try: 199 new_page.saveText(new_page_body, 0) 200 except PageEditor.Unchanged: 201 pass 202 203 # Retain the preceding region for the current page. 204 205 retained_regions.append(page_body[retained_region_start:start]) 206 207 # Insert Include macros for the broken out text. 208 209 retained_regions.append("<<Include(%s,,editlink)>>\n" % new_page_name) 210 211 # Start a new region to retain. 212 213 retained_region_start = end 214 215 # Retain any remaining text. 216 217 else: 218 retained_regions.append(page_body[retained_region_start:]) 219 220 # Edit the current page. 221 222 edited_page = PageEditor(request, page.page_name) 223 edited_page_body = "".join(retained_regions) 224 225 if propagate: 226 edited_page_categories = getCategoryMembership(edited_page_body) 227 228 # Add categories if the parent page should have any, but these were 229 # broken out. 230 231 if edited_page_categories != categories: 232 edited_page_body += makeCategoryDeclaration(categories) 233 234 # Save the current page. 235 236 edited_page.saveText(edited_page_body, 0) 237 238 # NOTE: Perhaps show a message upon failure. 239 240 request.http_redirect(page.url(request)) 241 return 1, None 242 243 # Action function. 244 245 def execute(pagename, request): 246 SectionBreakout(pagename, request).render() 247 248 # vim: tabstop=4 expandtab shiftwidth=4