Add unique ID to headings
The `name` field on the `paragraph` type contains a unique ID for the paragraph. It's not guaranteed to be there, on images for example like in the `fd8d091ab8ef` post, but it's there for everything else I can find. This enables deep linking. There's no way to get to the deep link other than opening up the web console. I wanted to link every heading, but you can actually have links in part of a heading so that's not tenable. Maybe a "permalink" link next to every heading?
This commit is contained in:
parent
761e4ef170
commit
cef1bc256d
11 changed files with 67 additions and 17 deletions
|
@ -8,6 +8,7 @@ describe EmbeddedConverter do
|
|||
store = GistStore.new
|
||||
paragraph = PostResponse::Paragraph.from_json <<-JSON
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "",
|
||||
"type": "IFRAME",
|
||||
"href": null,
|
||||
|
@ -44,6 +45,7 @@ describe EmbeddedConverter do
|
|||
store = GistStore.new
|
||||
paragraph = PostResponse::Paragraph.from_json <<-JSON
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "",
|
||||
"type": "IFRAME",
|
||||
"href": null,
|
||||
|
@ -73,6 +75,7 @@ describe EmbeddedConverter do
|
|||
store = GistStore.new
|
||||
paragraph = PostResponse::Paragraph.from_json <<-JSON
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "",
|
||||
"type": "IFRAME",
|
||||
"href": null,
|
||||
|
|
|
@ -12,6 +12,7 @@ describe GistScanner do
|
|||
)
|
||||
paragraphs = [
|
||||
PostResponse::Paragraph.new(
|
||||
name: "ab12",
|
||||
text: "Check out this gist:",
|
||||
type: PostResponse::ParagraphType::P,
|
||||
markups: [] of PostResponse::Markup,
|
||||
|
@ -20,6 +21,7 @@ describe GistScanner do
|
|||
metadata: nil
|
||||
),
|
||||
PostResponse::Paragraph.new(
|
||||
name: "ab13",
|
||||
text: "",
|
||||
type: PostResponse::ParagraphType::IFRAME,
|
||||
markups: [] of PostResponse::Markup,
|
||||
|
@ -45,6 +47,7 @@ describe GistScanner do
|
|||
)
|
||||
paragraphs = [
|
||||
PostResponse::Paragraph.new(
|
||||
name: "ab12",
|
||||
text: "",
|
||||
type: PostResponse::ParagraphType::IFRAME,
|
||||
markups: [] of PostResponse::Markup,
|
||||
|
@ -78,6 +81,7 @@ describe GistScanner do
|
|||
)
|
||||
paragraphs = [
|
||||
PostResponse::Paragraph.new(
|
||||
name: "ab12",
|
||||
text: "",
|
||||
type: PostResponse::ParagraphType::IFRAME,
|
||||
markups: [] of PostResponse::Markup,
|
||||
|
@ -86,6 +90,7 @@ describe GistScanner do
|
|||
metadata: nil
|
||||
),
|
||||
PostResponse::Paragraph.new(
|
||||
name: "ab13",
|
||||
text: "",
|
||||
type: PostResponse::ParagraphType::IFRAME,
|
||||
markups: [] of PostResponse::Markup,
|
||||
|
|
|
@ -8,6 +8,7 @@ describe PageConverter do
|
|||
paragraph_json = <<-JSON
|
||||
[
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "#{title}",
|
||||
"type": "H3",
|
||||
"markups": [],
|
||||
|
@ -28,6 +29,7 @@ describe PageConverter do
|
|||
it "sets the author" do
|
||||
post_json = <<-JSON
|
||||
{
|
||||
"name": "ab12",
|
||||
"title": "This is a story",
|
||||
"createdAt": 0,
|
||||
"creator": {
|
||||
|
@ -52,6 +54,7 @@ describe PageConverter do
|
|||
it "sets the publish date/time" do
|
||||
post_json = <<-JSON
|
||||
{
|
||||
"name": "ab12",
|
||||
"title": "This is a story",
|
||||
"createdAt": 1000,
|
||||
"creator": {
|
||||
|
@ -77,6 +80,7 @@ describe PageConverter do
|
|||
paragraph_json = <<-JSON
|
||||
[
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "#{title}",
|
||||
"type": "H3",
|
||||
"markups": [],
|
||||
|
@ -85,6 +89,7 @@ describe PageConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "Content",
|
||||
"type": "P",
|
||||
"markups": [],
|
||||
|
@ -117,6 +122,7 @@ def default_post_json(
|
|||
)
|
||||
<<-JSON
|
||||
{
|
||||
"name": "ab12",
|
||||
"title": "#{title}",
|
||||
"createdAt": 1628974309758,
|
||||
"creator": {
|
||||
|
|
|
@ -8,6 +8,7 @@ describe ParagraphConverter do
|
|||
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
|
||||
[
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "Title",
|
||||
"type": "H3",
|
||||
"markups": [],
|
||||
|
@ -17,7 +18,7 @@ describe ParagraphConverter do
|
|||
}
|
||||
]
|
||||
JSON
|
||||
expected = [Heading3.new(children: [Text.new(content: "Title")] of Child)]
|
||||
expected = [Heading3.new(children: [Text.new(content: "Title")] of Child, identifier: "ab12")]
|
||||
|
||||
result = ParagraphConverter.new.convert(paragraphs, gist_store)
|
||||
|
||||
|
@ -29,6 +30,7 @@ describe ParagraphConverter do
|
|||
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
|
||||
[
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "inline code",
|
||||
"type": "P",
|
||||
"markups": [
|
||||
|
@ -66,6 +68,7 @@ describe ParagraphConverter do
|
|||
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
|
||||
[
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "One",
|
||||
"type": "ULI",
|
||||
"markups": [],
|
||||
|
@ -74,6 +77,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab13",
|
||||
"text": "Two",
|
||||
"type": "ULI",
|
||||
"markups": [],
|
||||
|
@ -82,6 +86,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab14",
|
||||
"text": "Not a list item",
|
||||
"type": "P",
|
||||
"markups": [],
|
||||
|
@ -109,6 +114,7 @@ describe ParagraphConverter do
|
|||
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
|
||||
[
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "One",
|
||||
"type": "OLI",
|
||||
"markups": [],
|
||||
|
@ -117,6 +123,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab13",
|
||||
"text": "Two",
|
||||
"type": "OLI",
|
||||
"markups": [],
|
||||
|
@ -125,6 +132,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab14",
|
||||
"text": "Not a list item",
|
||||
"type": "P",
|
||||
"markups": [],
|
||||
|
@ -151,6 +159,7 @@ describe ParagraphConverter do
|
|||
gist_store = GistStore.new
|
||||
paragraph = PostResponse::Paragraph.from_json <<-JSON
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "Image by someuser",
|
||||
"type": "IMG",
|
||||
"markups": [
|
||||
|
@ -197,6 +206,7 @@ describe ParagraphConverter do
|
|||
paragraphs = Array(PostResponse::Paragraph).from_json <<-JSON
|
||||
[
|
||||
{
|
||||
"name": "ab12",
|
||||
"text": "text",
|
||||
"type": "H2",
|
||||
"markups": [],
|
||||
|
@ -205,6 +215,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab13",
|
||||
"text": "text",
|
||||
"type": "H3",
|
||||
"markups": [],
|
||||
|
@ -213,6 +224,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab14",
|
||||
"text": "text",
|
||||
"type": "H4",
|
||||
"markups": [],
|
||||
|
@ -221,6 +233,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab15",
|
||||
"text": "text",
|
||||
"type": "P",
|
||||
"markups": [],
|
||||
|
@ -229,6 +242,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab16",
|
||||
"text": "text",
|
||||
"type": "PRE",
|
||||
"markups": [],
|
||||
|
@ -237,6 +251,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab17",
|
||||
"text": "text",
|
||||
"type": "BQ",
|
||||
"markups": [],
|
||||
|
@ -245,6 +260,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab18",
|
||||
"text": "text",
|
||||
"type": "PQ",
|
||||
"markups": [],
|
||||
|
@ -253,6 +269,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab19",
|
||||
"text": "text",
|
||||
"type": "ULI",
|
||||
"markups": [],
|
||||
|
@ -261,6 +278,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab20",
|
||||
"text": "text",
|
||||
"type": "OLI",
|
||||
"markups": [],
|
||||
|
@ -269,6 +287,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab21",
|
||||
"text": "text",
|
||||
"type": "IMG",
|
||||
"markups": [],
|
||||
|
@ -281,6 +300,7 @@ describe ParagraphConverter do
|
|||
}
|
||||
},
|
||||
{
|
||||
"name": "ab22",
|
||||
"text": "",
|
||||
"type": "IFRAME",
|
||||
"markups": [],
|
||||
|
@ -296,6 +316,7 @@ describe ParagraphConverter do
|
|||
"metadata": null
|
||||
},
|
||||
{
|
||||
"name": "ab23",
|
||||
"text": "Mixtape",
|
||||
"type": "MIXTAPE_EMBED",
|
||||
"href": null,
|
||||
|
@ -317,9 +338,9 @@ describe ParagraphConverter do
|
|||
]
|
||||
JSON
|
||||
expected = [
|
||||
Heading1.new([Text.new("text")] of Child),
|
||||
Heading2.new([Text.new("text")] of Child),
|
||||
Heading3.new([Text.new("text")] of Child),
|
||||
Heading1.new([Text.new("text")] of Child, identifier: "ab12"),
|
||||
Heading2.new([Text.new("text")] of Child, identifier: "ab13"),
|
||||
Heading3.new([Text.new("text")] of Child, identifier: "ab14"),
|
||||
Paragraph.new([Text.new("text")] of Child),
|
||||
Preformatted.new([Text.new("text")] of Child),
|
||||
BlockQuote.new([Text.new("text")] of Child), # BQ
|
||||
|
|
|
@ -184,13 +184,13 @@ describe PageContent do
|
|||
nodes: [
|
||||
Heading1.new(children: [
|
||||
Text.new(content: "Title!"),
|
||||
] of Child),
|
||||
] of Child, identifier: "ab12"),
|
||||
] of Child
|
||||
)
|
||||
|
||||
html = PageContent.new(page: page).render_to_string
|
||||
|
||||
html.should eq %(<h1>Title!</h1>)
|
||||
html.should eq %(<h1 id="ab12">Title!</h1>)
|
||||
end
|
||||
|
||||
it "renders an H3" do
|
||||
|
@ -201,13 +201,13 @@ describe PageContent do
|
|||
nodes: [
|
||||
Heading2.new(children: [
|
||||
Text.new(content: "Title!"),
|
||||
] of Child),
|
||||
] of Child, identifier: "ab12"),
|
||||
] of Child
|
||||
)
|
||||
|
||||
html = PageContent.new(page: page).render_to_string
|
||||
|
||||
html.should eq %(<h2>Title!</h2>)
|
||||
html.should eq %(<h2 id="ab12">Title!</h2>)
|
||||
end
|
||||
|
||||
it "renders an H4" do
|
||||
|
@ -218,13 +218,13 @@ describe PageContent do
|
|||
nodes: [
|
||||
Heading3.new(children: [
|
||||
Text.new(content: "In Conclusion..."),
|
||||
] of Child),
|
||||
] of Child, identifier: "ab12"),
|
||||
] of Child
|
||||
)
|
||||
|
||||
html = PageContent.new(page: page).render_to_string
|
||||
|
||||
html.should eq %(<h3>In Conclusion...</h3>)
|
||||
html.should eq %(<h3 id="ab12">In Conclusion...</h3>)
|
||||
end
|
||||
|
||||
it "renders an image" do
|
||||
|
|
|
@ -16,15 +16,15 @@ class ParagraphConverter
|
|||
when PostResponse::ParagraphType::H2
|
||||
paragraph = paragraphs.shift
|
||||
children = MarkupConverter.convert(paragraph.text, paragraph.markups)
|
||||
node = Heading1.new(children: children)
|
||||
node = Heading1.new(children: children, identifier: paragraph.name || "")
|
||||
when PostResponse::ParagraphType::H3
|
||||
paragraph = paragraphs.shift
|
||||
children = MarkupConverter.convert(paragraph.text, paragraph.markups)
|
||||
node = Heading2.new(children: children)
|
||||
node = Heading2.new(children: children, identifier: paragraph.name || "")
|
||||
when PostResponse::ParagraphType::H4
|
||||
paragraph = paragraphs.shift
|
||||
children = MarkupConverter.convert(paragraph.text, paragraph.markups)
|
||||
node = Heading3.new(children: children)
|
||||
node = Heading3.new(children: children, identifier: paragraph.name || "")
|
||||
when PostResponse::ParagraphType::IFRAME
|
||||
paragraph = paragraphs.shift
|
||||
node = EmbeddedConverter.convert(paragraph, gist_store)
|
||||
|
|
|
@ -27,6 +27,7 @@ class MediumClient
|
|||
content {
|
||||
bodyModel {
|
||||
paragraphs {
|
||||
name
|
||||
text
|
||||
type
|
||||
href
|
||||
|
|
|
@ -93,15 +93,15 @@ class PageContent < BaseComponent
|
|||
end
|
||||
|
||||
def render_child(node : Heading1)
|
||||
h1 { render_children(node.children) }
|
||||
h1(id: node.identifier) { render_children(node.children) }
|
||||
end
|
||||
|
||||
def render_child(node : Heading2)
|
||||
h2 { render_children(node.children) }
|
||||
h2(id: node.identifier) { render_children(node.children) }
|
||||
end
|
||||
|
||||
def render_child(node : Heading3)
|
||||
h3 { render_children(node.children) }
|
||||
h3(id: node.identifier) { render_children(node.children) }
|
||||
end
|
||||
|
||||
def render_child(child : Image)
|
||||
|
|
|
@ -41,12 +41,24 @@ module Nodes
|
|||
end
|
||||
|
||||
class Heading1 < Container
|
||||
getter identifier : String
|
||||
|
||||
def initialize(@children : Children, @identifier : String)
|
||||
end
|
||||
end
|
||||
|
||||
class Heading2 < Container
|
||||
getter identifier : String
|
||||
|
||||
def initialize(@children : Children, @identifier : String)
|
||||
end
|
||||
end
|
||||
|
||||
class Heading3 < Container
|
||||
getter identifier : String
|
||||
|
||||
def initialize(@children : Children, @identifier : String)
|
||||
end
|
||||
end
|
||||
|
||||
class ListItem < Container
|
||||
|
|
|
@ -32,6 +32,7 @@ class PostResponse
|
|||
end
|
||||
|
||||
class Paragraph < Base
|
||||
property name : String?
|
||||
property text : String?
|
||||
property type : ParagraphType
|
||||
property markups : Array(Markup)
|
||||
|
@ -40,6 +41,7 @@ class PostResponse
|
|||
property metadata : Metadata?
|
||||
|
||||
def initialize(
|
||||
@name : String,
|
||||
@text : String?,
|
||||
@type : ParagraphType,
|
||||
@markups : Array(Markup),
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
module Scribe
|
||||
VERSION = "2022-11-06"
|
||||
VERSION = "2023-03-25"
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue