Add basic word count and reading time
This commit is contained in:
parent
1a8821eaa8
commit
299a6342cc
2 changed files with 28 additions and 5 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
import math
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
|
||||||
from django.db import models
|
from django.db import models
|
||||||
|
@ -8,7 +9,7 @@ from wagtail.fields import StreamField
|
||||||
from wagtail.images import get_image_model_string
|
from wagtail.images import get_image_model_string
|
||||||
from wagtail.models import Page
|
from wagtail.models import Page
|
||||||
|
|
||||||
from .streamfield import get_blocks
|
from .streamfield import get_blocks, get_word_count
|
||||||
from .utils import TocEntry, get_table_of_contents
|
from .utils import TocEntry, get_table_of_contents
|
||||||
|
|
||||||
|
|
||||||
|
@ -53,11 +54,14 @@ class BaseContentMixin(models.Model):
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def reading_time(self) -> int:
|
def reading_time(self) -> int:
|
||||||
return 4
|
"""
|
||||||
|
https://help.medium.com/hc/en-us/articles/214991667-Read-time
|
||||||
|
"""
|
||||||
|
return int(math.ceil(self.word_count / 265))
|
||||||
|
|
||||||
@cached_property
|
@cached_property
|
||||||
def word_count(self) -> int:
|
def word_count(self) -> int:
|
||||||
return 1600
|
return get_word_count(self.body)
|
||||||
|
|
||||||
|
|
||||||
class ContentPage(BasePage, BaseContentMixin): # type: ignore[misc]
|
class ContentPage(BasePage, BaseContentMixin): # type: ignore[misc]
|
||||||
|
|
|
@ -1,13 +1,18 @@
|
||||||
|
from typing import Iterator
|
||||||
|
|
||||||
from django.utils import lorem_ipsum
|
from django.utils import lorem_ipsum
|
||||||
from django.utils.html import format_html_join
|
from django.utils.html import format_html_join, strip_tags
|
||||||
|
from django.utils.text import smart_split
|
||||||
from wagtail import blocks
|
from wagtail import blocks
|
||||||
from wagtail.embeds.blocks import EmbedBlock
|
from wagtail.embeds.blocks import EmbedBlock
|
||||||
|
|
||||||
|
IGNORE_WORDCOUNT_BLOCKS = (blocks.RawHTMLBlock, EmbedBlock)
|
||||||
|
|
||||||
|
|
||||||
class LoremBlock(blocks.StructBlock):
|
class LoremBlock(blocks.StructBlock):
|
||||||
paragraphs = blocks.IntegerBlock(min_value=1)
|
paragraphs = blocks.IntegerBlock(min_value=1)
|
||||||
|
|
||||||
def render(self, value: dict, context: dict) -> str:
|
def render(self, value: dict, context: dict | None = None) -> str:
|
||||||
return format_html_join(
|
return format_html_join(
|
||||||
"\n\n",
|
"\n\n",
|
||||||
"<p>{}</p>",
|
"<p>{}</p>",
|
||||||
|
@ -26,3 +31,17 @@ def get_blocks() -> list[tuple[str, blocks.BaseBlock]]:
|
||||||
("lorem", LoremBlock()),
|
("lorem", LoremBlock()),
|
||||||
("html", blocks.RawHTMLBlock()),
|
("html", blocks.RawHTMLBlock()),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def get_plain_text(value: blocks.StreamValue) -> Iterator[str]:
|
||||||
|
for block in value:
|
||||||
|
if isinstance(block.block_type, IGNORE_WORDCOUNT_BLOCKS):
|
||||||
|
continue
|
||||||
|
yield strip_tags(str(block))
|
||||||
|
|
||||||
|
|
||||||
|
def get_word_count(value: blocks.StreamValue) -> int:
|
||||||
|
count = 0
|
||||||
|
for chunk in get_plain_text(value):
|
||||||
|
count += len(list(smart_split(chunk)))
|
||||||
|
return count
|
||||||
|
|
Loading…
Reference in a new issue