def parse_links(html, request_path=None, encoding=None): """Process all links in given html and replace them if markup is added.""" if encoding is None: encoding = settings.DEFAULT_CHARSET # The passed HTML may be a string or bytes, depending on what is calling # this method. For example, Django response.content is always bytes. We # always want this content to be a string for our purposes. html_as_text = force_str(html, encoding=encoding) # This call invokes Wagtail-specific logic that converts references to # Wagtail pages, documents, and images to their proper link URLs. expanded_html = expand_db_html(html_as_text) # Parse links only in the <body> of the HTML body_html = get_body_html(expanded_html) if body_html is None: return expanded_html link_tags = get_link_tags(body_html) for tag in link_tags: tag_with_markup = add_link_markup(tag, request_path) if tag_with_markup: expanded_html = expanded_html.replace(tag, tag_with_markup) return expanded_html
def render(self, name, value, attrs=None): if value is None: translated_value = None else: translated_value = expand_db_html(value) #, for_editor=True) return super(TinyMCERichTextArea, self).render(name, translated_value, attrs)
def get_html(news_stories, additional_link_params, header_html, extra_html, footer_html): html = "<html><head></head><body>" + header_html html = html + "<ul>" for news_story in news_stories.order_by('-story_date'): url = 'https://loop.lib.uchicago.edu' + news_story.url_path.replace( '/loop', '', 1) + '?' + urllib.parse.urlencode(additional_link_params) html = html + "<li><a href='" + url + "'>" html = html + news_story.title html = html + "</a></li>" html = html + "</ul>" html = html + extra_html html = html + footer_html html = html + "</body></html>" # rough pass to clean strangely nested elements. soup = BeautifulSoup(html, "lxml") # do more cleanup work. html = clean_html(str(soup)) # get the real links for things like documents and internal pages. html = expand_db_html(html) return html
def richtext_force_external_links(value): """Filter to force all href["target"] attributes to be blank This is similar to the core richtext filter https://github.com/wagtail/wagtail/blob/main/wagtail/core/templatetags/wagtailcore_tags.py#L97-L108 The main difference being we want to force all links to open in a new window, this is useful for front end form elements where the user would risk losing any form data. Typical scenario is getting the the end of a form, clicking a link to view "terms and conditions", then upon returning to the form page the form inputs could be reset. We still set html via `expand_db_html`, to take care of any processing that may be added already, or in the future. """ if isinstance(value, RichText): # passing a RichText value through the |richtext_force_external_links filter should have no effect return value elif value is None: html = "" else: if not isinstance(value, str): raise TypeError( "'richtext' template filter received an invalid value; expected string, got {}.".format( type(value) ) ) html = expand_db_html(value) soup = BeautifulSoup(html, "html.parser") links = soup.find_all("a") for link in links: link["target"] = "_blank" html = str(soup) return render_to_string("wagtailcore/shared/richtext.html", {"html": html})
def test_expand_db_html_with_embed(self, get_embed): from wagtail.embeds.models import Embed get_embed.return_value = Embed(html="test html") html = '<embed embedtype="media" url="http://www.youtube.com/watch" />' result = expand_db_html(html) self.assertIn("test html", result)
def richtext(value): if value is not None: html = expand_db_html(value) else: html = '' return mark_safe(html)
def rich_text(value): if isinstance(value, RichText): # passing a RichText value through the |richtext filter should have no effect return str(value) elif value is None: html = '' else: html = expand_db_html(value) return mark_safe(html)
def richtext(value): if isinstance(value, RichText): # passing a RichText value through the |richtext filter should have no effect return value elif value is None: html = '' else: html = expand_db_html(value) return mark_safe('<div class="rich-text">' + html + '</div>')
def richtext(value): if isinstance(value, RichText): # passing a RichText value through the |richtext filter should have no effect return value elif value is None: html = '' else: html = expand_db_html(value) return mark_safe('<div class="rich-text">' + html + '</div>')
def richtext_unwrapped(value): # if isinstance(value, RichText): # return value if value is None: html = "" else: html = expand_db_html(value) if html.startswith("<p>") and html.endswith("</p>"): html = html[3:-4] return mark_safe(html)
def simplerichtext(value): """ Simple richtext filter to avoid the wrapping <div class='richtext'></div> markup """ if isinstance(value, SimpleRichText): html = value elif value is None: html = '' else: html = expand_db_html(value) return mark_safe(html)
def inlinerichtext(value): if value is None: html = '' else: if isinstance(value, str): html = expand_db_html(value) else: raise TypeError( "'richtext' template filter received an invalid value; expected string, got {}.".format(type(value))) html = html.replace('<p>', '') html = html.replace('</p>', '') return mark_safe(html)
def render(self, name, value, attrs=None): if value is None: translated_value = None else: # if WAGTAIL_VERSION >= '2.0': # translated_value = self.converter.from_database_format(value, for_editor=True) # else: # print(self.converter) translated_value = expand_db_html(value) return super(TinyMCERichTextArea, self).render(name, translated_value, attrs)
class ServicesPage(Page): subpage_types = [] max_count = 1 # Replace wrapped rich-text div RichText.__html__ = lambda self: expand_db_html(self.source) content_panels = Page.content_panels + [ MultiFieldPanel( [InlinePanel("services_list", label="Service"), ], heading="Services", ) ]
def richtext(value): if isinstance(value, RichText): # passing a RichText value through the |richtext filter should have no effect return value elif value is None: html = '' else: if isinstance(value, str): html = expand_db_html(value) else: raise TypeError("'richtext' template filter received an invalid value; expected string, got {}.".format(type(value))) return mark_safe('<div class="rich-text">' + html + '</div>')
def richtext(value): if isinstance(value, RichText): # passing a RichText value through the |richtext filter should have no effect return value elif value is None: html = '' else: if isinstance(value, str): html = expand_db_html(value) else: raise TypeError("'richtext' template filter received an invalid value; expected string, got {}.".format(type(value))) return mark_safe('<div class="rich-text">' + html + '</div>')
def try_expand_db_html(parsed_item): """ expand_db_html errors out if not used on a string. becuase this process is so complicated, we wrap it in some error handiling so we can debug/catch an exception if someone adds a data schema later that causes problems """ try: return expand_db_html(parsed_item) except Exception as e: print('Streamfield API Exception!', e) print(traceback.format_exc()) return parsed_item
def richtext(value): if isinstance(value, RichText): # passing a RichText value through the |richtext filter should have no effect return value elif value is None: html = '' else: if isinstance(value, str): html = expand_db_html(value) else: raise TypeError( "'richtext' template filter received an invalid value; expected string, got {}." .format(type(value))) return render_to_string('wagtailcore/shared/richtext.html', {'html': html})
class AboutPage(Page): subpage_types = [] max_count = 1 about_content = StreamField([ ('subheading', blocks.RichTextBlock(icon="title", features=['h2'])), ('paragraph', blocks.RichTextBlock(icon="pilcrow", features=['p', 'link', 'bold', 'italic'])), ], null=True) # Replace wrapped rich-text div RichText.__html__ = lambda self: expand_db_html(self.source) content_panels = Page.content_panels + [StreamFieldPanel('about_content')]
def test_expand_html_escaping_end_to_end(self, get_embed): get_embed.return_value = Embed( url='http://www.youtube.com/watch/', max_width=None, type='video', html='test html', title='test title', author_name='test author name', provider_name='test provider name', thumbnail_url='htto://test/thumbnail.url', width=1000, height=1000, ) result = expand_db_html('<p>1 2 <embed embedtype="media" url="https://www.youtube.com/watch?v=O7D-1RG-VRk&t=25" /> 3 4</p>') self.assertIn('test html', result) get_embed.assert_called_with('https://www.youtube.com/watch?v=O7D-1RG-VRk&t=25')
def accessible_links(html): """ Makes footer links with surrounding text accessible to screen readers by adding an aria-label attribute containing the full text of the footer item to the link. """ soup = BeautifulSoup(expand_db_html(html), 'html.parser') for p in soup.find_all('p'): if p.find_all('a'): for child in p.children: if child.name == 'a': if child.string != p.text: child['aria-label'] = p.text else: if child.name != 'span': child = child.wrap(soup.new_tag('span')) child['aria-hidden'] = 'true' return str(soup).replace(u'\xa0', ' ')
def get_field_value(instance, field_name: str): """ Returns the value of a given field on an object of a StreamField. Different types of objects require different ways to access the values. """ if isinstance(instance, StructValue): return instance[field_name] elif isinstance(instance.value, RichText): # Allow custom markup for RichText return render_to_string( "wagtailcore/richtext.html", {"html": expand_db_html(instance.value.source)}) elif isinstance(instance.value, stream_block.StreamValue): stream_data = dict(instance.value.stream_data) return stream_data[field_name] else: return instance.value[field_name]
def item_extra_kwargs(self, item): """ Returns an extra keyword arguments dictionary that is used with the 'add_item' call of the feed generator. Add the fields of the item, to be used by the custom feed generator. """ if use_feed_image: feed_image = item.feed_image if feed_image: image_complete_url = urljoin( self.get_site_url(), feed_image.file.url ) else: image_complete_url = "" content_field = getattr(item, self.item_content_field) try: content = expand_db_html(content_field) except: content = content_field.__html__() soup = BeautifulSoup(content, 'html.parser') # Remove style attribute to remove large botton padding for div in soup.find_all("div", {'class': 'responsive-object'}): del div['style'] # Add site url to image source for img_tag in soup.findAll('img'): if img_tag.has_attr('src'): img_tag['src'] = urljoin(self.get_site_url(), img_tag['src']) fields_to_add = { 'content': soup.prettify(formatter="html"), } if use_feed_image: fields_to_add['image'] = image_complete_url else: fields_to_add['image'] = "" return fields_to_add
class NewsPage(Page): parent_page_type =[ 'news.NewsIndexPage' ] subpage_types = [] date = models.DateField("Post date") news_image = models.ForeignKey( 'wagtailimages.Image', null=True, blank=False, on_delete=models.SET_NULL ) # Replace wrapped rich-text div RichText.__html__ = lambda self: expand_db_html(self.source) news_content = StreamField([ ('paragraph', blocks.RichTextBlock(icon="pilcrow", features=['p','link', 'bold', 'italic', 'ol', 'ul'])), ('image', ImageChooserBlock(icon="image")), ('quote', blocks.StructBlock([ ('source', blocks.CharBlock(classname="full", help_text='The source of where that quote came from.')), ('quote_text', blocks.CharBlock( classname="full", help_text='Add quote.')), ], icon='openquote'), ), ('embedded_video', EmbedBlock(icon="media")), ], null=True) content_panels = Page.content_panels + [ FieldPanel('date'), ImageChooserPanel('news_image'), StreamFieldPanel('news_content'), ] def first_paragraph(self): for block in self.news_content: if block.block_type == 'paragraph': return block.value
def test_expand_db_html_with_linktype(self): html = '<a id="1" linktype="document">foo</a>' result = expand_db_html(html) self.assertEqual(result, '<a>foo</a>')
def test_expand_db_html_with_embed(self, get_embed): from wagtail.embeds.models import Embed get_embed.return_value = Embed(html='test html') html = '<embed embedtype="media" url="http://www.youtube.com/watch" />' result = expand_db_html(html) self.assertIn('test html', result)
def resolve_description_html(self, info): return expand_db_html(self.description)
def resolve_body_html(self, info): return expand_db_html(self.content)
def serialize(value): return expand_db_html(value)
def get_rich_text(self, page): return expand_db_html(page.rich_text)
def get_prep_value(self, value): return expand_db_html(value.source)
def get_wysiwyg(self, page): return expand_db_html(page.wysiwyg)
def test_expand_db_html_with_linktype(self): html = '<a id="1" linktype="document">foo</a>' result = expand_db_html(html) self.assertEqual(result, '<a>foo</a>')
def resolve_value(self, value): # Allow custom markup for RichText return render_to_string("wagtailcore/richtext.html", {"html": expand_db_html(self.value.source)})
def render(self, name, value, attrs=None): if value is None: translated_value = None else: translated_value = expand_db_html(value, for_editor=True) return super().render(name, translated_value, attrs)
def test_expand_db_html_no_linktype(self): html = '<a id="1">foo</a>' result = expand_db_html(html) self.assertEqual(result, '<a id="1">foo</a>')
def test_expand_db_html_no_linktype(self): html = '<a id="1">foo</a>' result = expand_db_html(html) self.assertEqual(result, '<a id="1">foo</a>')