diff --git a/lepiter/46lrihou08u2u8wikuobvkk0y.lepiter b/lepiter/2tayi32k6bk6g9hvxydicueq0.lepiter similarity index 62% rename from lepiter/46lrihou08u2u8wikuobvkk0y.lepiter rename to lepiter/2tayi32k6bk6g9hvxydicueq0.lepiter index 70edf3748..a5fef49d0 100644 --- a/lepiter/46lrihou08u2u8wikuobvkk0y.lepiter +++ b/lepiter/2tayi32k6bk6g9hvxydicueq0.lepiter @@ -4,43 +4,6 @@ "children" : { "__type" : "snippets", "items" : [ - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:02:11.546784+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:02:35.635444+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "75/YhULqDQC8M1m8AFj72w==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "{{gtTodo:label=Revise this tutorial to reflect the new, refactored hierarchy.}}" - }, { "__type" : "textSnippet", "children" : { @@ -60,7 +23,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:19:01.536895+01:00" + "dateAndTimeString" : "2025-02-12T10:59:44.663001+01:00" } }, "editEmail" : { @@ -71,12 +34,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:21:50.709546+01:00" + "dateAndTimeString" : "2025-02-12T10:59:44.663001+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "937NTtjpDQClXo5/DeapRg==" + "uidString" : "AkLlvFDqDQCBVf76ADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -93,7 +56,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:14:30.419277+01:00" + "dateAndTimeString" : "2025-02-12T10:59:44.662895+01:00" } }, "editEmail" : { @@ -104,12 +67,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:19:00.997662+01:00" + "dateAndTimeString" : "2025-02-12T10:59:44.662895+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "MI2kPtjpDQClNkwhDeapRg==" + "uidString" : "jEHlvFDqDQCBVPX6ADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -135,7 +98,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:39:29.361592+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.47428+01:00" } }, "editEmail" : { @@ -146,12 +109,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:39:57.374572+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.47428+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "Tpj8l9jpDQC807vVDeapRg==" + "uidString" : "zmkfvVDqDQCLF7JcADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -172,7 +135,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:22:06.80659+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474376+01:00" } }, "editEmail" : { @@ -183,12 +146,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:23:05.522794+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474376+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "2nzYWdjpDQCsx6zdDeapRg==" + "uidString" : "DmofvVDqDQCLGOsuADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -209,7 +172,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:23:02.785834+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474397+01:00" } }, "editEmail" : { @@ -220,12 +183,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:40:31.371566+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474397+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "eakuXdjpDQCuzkObDeapRg==" + "uidString" : "H2ofvVDqDQCLGTMAADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -246,7 +209,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:24:07.955323+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474401+01:00" } }, "editEmail" : { @@ -257,12 +220,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:24:21.930125+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474401+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "ihARYdjpDQCygqDbDeapRg==" + "uidString" : "I2ofvVDqDQCLGoN7ADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -288,7 +251,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:25:03.664892+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474412+01:00" } }, "editEmail" : { @@ -299,12 +262,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:25:03.664892+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474412+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "9yFjZNjpDQC1/NmdDeapRg==" + "uidString" : "LmofvVDqDQCLHLBGADOILw==" }, "string" : "3+4" } @@ -318,7 +281,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:22:43.706235+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474404+01:00" } }, "editEmail" : { @@ -329,12 +292,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:26:40.436211+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474404+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "74cLXNjpDQCug0+hDeapRg==" + "uidString" : "JmofvVDqDQCLGyzmADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -355,7 +318,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:22:43.920586+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474419+01:00" } }, "editEmail" : { @@ -366,12 +329,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:26:36.263234+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474419+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "IM0OXNjpDQCuiMiIDeapRg==" + "uidString" : "NGofvVDqDQCLHevsADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -388,7 +351,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:22:02.127779+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474173+01:00" } }, "editEmail" : { @@ -399,12 +362,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:22:06.504551+01:00" + "dateAndTimeString" : "2025-02-12T10:59:48.474173+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "sBaRWdjpDQCsgtdrDeapRg==" + "uidString" : "WGkfvVDqDQCLFky3ADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -430,81 +393,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:46:06.344613+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:17:12.372203+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "tRamr9jpDQCFihsLDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "The implementation consists of three collaborating classes, {{gtClass:name=LeBlockQuoteSnippet}}, {{gtClass:name=LeBlockQuoteSnippetViewModel}}, and {{gtClass:name=LeBlockQuoteSnippetElement}}, which we will look at in detail further below. " - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:58:19.463154+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:58:19.463154+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "cpdY29jpDQCTEwpMDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "Instead of using MVC (Model-View-Controller) pattern, these classes follow the *MVVM* pattern — [Model–view–viewmodel](https://en.wikipedia.org/wiki/Model%2Dview%2Dviewmodel). " - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:58:33.680196+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.400892+01:00" } }, "editEmail" : { @@ -515,17 +404,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:59:20.032179+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.400892+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "hYYx3NjpDQCTb86SDeapRg==" + "uidString" : "6BFMvVDqDQCUj/nSADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "The *model* represents the domain model, holding the state of the snippet and all behavior related to the state. In this case, {{gtClass:name=LeBlockQuoteSnippet}} holds the actual content of the literal text block." + "string" : "A snippet implementation consists of three collaborating classes, a *model*, a *view* and a *view model*, following the *MVVM* pattern — [Model–view–viewmodel](https://en.wikipedia.org/wiki/Model%2Dview%2Dviewmodel). The *model* represents the domain model, holding the state of the snippet and all behavior related to the state. The *view model* holds and manages the state that is needed for the visual representation of the snippet in a page. Finally, the *view* is the element that provides the interactive display of the snippet. It is updated when the view model updates, and conversely, UI events that update the view are propagated to the view model. " }, { "__type" : "textSnippet", @@ -541,7 +430,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:20:05.245371+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.400999+01:00" } }, "editEmail" : { @@ -552,17 +441,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:29:32.061961+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.400999+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "9YZU1trpDQCzdzSMDeapRg==" + "uidString" : "KxJMvVDqDQCUkE6cADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "Snippet model classes are direct or indirect subclasses of {{gtClass:name=LeSnippet}}:" + "string" : "Snippet model classes are all direct or indirect subclasses of {{gtClass:name=LeSnippet}}. In this case, a {{gtClass:name=LeBlockQuoteSnippet}} is a particular kind of *textual* snippet, so we define it as a subclass of {{gtClass:name=LePlainTextSnippet}}, an abstract superclass of pure textual (not code) snippets. As a model class, {{gtClass:name=LeBlockQuoteSnippet}} holds the actual content of the literal text block, as illustrated in this diagram at the left." }, { "__type" : "elementSnippet", @@ -578,7 +467,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:27:39.421077+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401013+01:00" } }, "editEmail" : { @@ -589,15 +478,15 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-10T10:00:18.111946+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401013+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "HbNm8drpDQC2iJTPDeapRg==" + "uidString" : "ORJMvVDqDQCUkfOzADOILw==" }, - "code" : "LeBlockQuoteSnippetUMLExamples new blockQuoteSnippetClassHierarchyWithAssociationsAndLabels", - "elementHeight" : 413, + "code" : "LeBlockQuoteSnippetUMLExamples new blockQuoteSnippetClassHierarchyWithPositions", + "elementHeight" : 296, "codeHeight" : 50, "codeVisible" : false }, @@ -615,7 +504,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:58:41.377623+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401022+01:00" } }, "editEmail" : { @@ -626,17 +515,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T17:57:47.86231+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401022+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "DrGG3NjpDQCTdux+DeapRg==" + "uidString" : "QBJMvVDqDQCUkoHtADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "The *view model* holds and manages the state that is needed for the visual representation of the snippet in a page. These are all subclasses of {{gtClass:name=LeSnippetViewModel}}. In this case, {{gtClass:name=LeBlockQuoteSnippetViewModel}} just needs to track the state of the text in the model, and it also tracks the `textCoderViewModel` of the view." + "string" : "Snippet view model classes are all subclasses of {{gtClass:name=LeSnippetViewModel}}. In this case, {{gtClass:name=LeBlockQuoteSnippetViewModel}} subclasses {{gtClass:name=LePlainTextCoderSnippetViewModel}} and tracks the state of the text within a separate `textCoderViewModel`." }, { "__type" : "textSnippet", @@ -652,7 +541,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:31:01.544875+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401039+01:00" } }, "editEmail" : { @@ -663,17 +552,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T17:58:30.494881+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401039+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "bNxy/drpDQC4/WoIDeapRg==" + "uidString" : "UBJMvVDqDQCUkwHjADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "The *view* is the element that provides the interactive display of the snippet. It is updated when the view model updates, and conversely, UI events that update the view are propagated to the view model. Snippet views all subclass {{gtClass:name=LeSnippetElement}}. In this case, {{gtClass:name=LeBlockQuoteSnippetElement}} is a composite element holding the {{gtClass:name=GtTextualCoderEditorElement}} instance in which the block text is edited." + "string" : "Snippet views all subclass {{gtClass:name=LeSnippetElement}}. In this case, {{gtClass:name=LeBlockQuoteSnippetElement}} subclasses {{gtClass:name=LePlainTextCoderSnippetElement}}, which provides a basic `editorElement` for editing text, an instance of {{gtClass:name=GtTextualCoderEditorElement}}. " }, { "__type" : "textSnippet", @@ -689,7 +578,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:13:02.978615+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401042+01:00" } }, "editEmail" : { @@ -700,12 +589,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:17:44.220719+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401042+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "fT8pvdrpDQCjCWWLDeapRg==" + "uidString" : "UxJMvVDqDQCUlP6jADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -726,7 +615,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:55:13.077437+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401045+01:00" } }, "editEmail" : { @@ -737,12 +626,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:19:09.493337+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401045+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "lAo7t9jpDQCHTSJBDeapRg==" + "uidString" : "VhJMvVDqDQCUlbIlADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -763,7 +652,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:40:41.4042+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401047+01:00" } }, "editEmail" : { @@ -774,12 +663,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:41:45.447477+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.401047+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "HeRHnNjpDQC/QxnSDeapRg==" + "uidString" : "WBJMvVDqDQCUlrT7ADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -796,7 +685,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:21:52.115292+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.400762+01:00" } }, "editEmail" : { @@ -807,12 +696,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:17:02.92353+01:00" + "dateAndTimeString" : "2025-02-12T10:59:51.400762+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "9FD4WNjpDQCsRzGeDeapRg==" + "uidString" : "XhFMvVDqDQCUjrDaADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -843,7 +732,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:41:57.352471+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377726+01:00" } }, "editEmail" : { @@ -854,12 +743,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:01:24.356419+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377726+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "LrGJJNvpDQCHndrQDeapRg==" + "uidString" : "B355vVDqDQCeCSnWADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" @@ -880,7 +769,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:35:45.39878+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377744+01:00" } }, "editEmail" : { @@ -891,23 +780,96 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:01:50.882907+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377744+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "ACFeDtvpDQCBMBqjDeapRg==" + "uidString" : "En55vVDqDQCeCqW5ADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, "string" : "There are several methods to implement. We'll get to these step by step." - }, + } + ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377621+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377621+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "x315vVDqDQCeCKFOADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" + }, + "string" : "**(1)** Define a subclass of {{gtClass:name=LeSnippet}}. " + }, + { + "__type" : "textSnippet", + "children" : { + "__type" : "snippets", + "items" : [ { - "__type" : "pharoSnippet", + "__type" : "textSnippet", "children" : { "__type" : "snippets", - "items" : [ ] + "items" : [ + { + "__type" : "pharoSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377758+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377758+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "In55vVDqDQCeDUeXADOILw==" + }, + "code" : "(LeBlockQuoteSnippet new string: 'hello') text" + } + ] }, "createEmail" : { "__type" : "email", @@ -917,7 +879,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:35:17.443513+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.37775+01:00" } }, "editEmail" : { @@ -928,14 +890,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:01:32.80693+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.37775+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "IpGzDNvpDQCAWV1RDeapRg==" + "uidString" : "GH55vVDqDQCeDLHGADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" }, - "code" : "LePlainTextSnippet allMethods select: #isAbstract" + "string" : "We inherit all the state we need from {{gtClass:name=LePlainTextSnippet}}, namely a `text` slot, which is initialized to an instance of {{gtClass:name=BlRunRopedText}}." } ] }, @@ -947,7 +912,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:34:55.212342+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377747+01:00" } }, "editEmail" : { @@ -958,17 +923,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:41:49.638608+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377747+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "s1lgC9vpDQC/uKeFDeapRg==" + "uidString" : "FX55vVDqDQCeCxnfADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(1)** Define a subclass of {{gtClass:name=LeSnippet}}. " + "string" : "**(2)** Define and initialize any needed state. Define any accessors needed to recreate an instance with its state from plain strings." }, { "__type" : "textSnippet", @@ -976,10 +941,45 @@ "__type" : "snippets", "items" : [ { - "__type" : "commentSnippet", + "__type" : "textSnippet", "children" : { "__type" : "snippets", - "items" : [ ] + "items" : [ + { + "__type" : "pharoSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377775+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377775+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "MX55vVDqDQCeEEGEADOILw==" + }, + "code" : "(LeBlockQuoteSnippet new\r\tstring: 'Literal text';\r\tyourself) storeString" + } + ] }, "createEmail" : { "__type" : "email", @@ -989,7 +989,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:02:44.632223+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377772+01:00" } }, "editEmail" : { @@ -1000,15 +1000,56 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:03:08.339842+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377772+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "Y3jRh0LqDQC9mrAjAFj72w==" + "uidString" : "Ln55vVDqDQCeD505ADOILw==" }, - "string" : "CONTINUE EDITING HERE" - }, + "paragraphStyle" : { + "__type" : "textStyle" + }, + "string" : "We also inherit {{gtMethod:name=LeBlockQuoteSnippet>>#storeOn:}}, which works out of the box for our new snippet:" + } + ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377767+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377767+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "KX55vVDqDQCeDg++ADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" + }, + "string" : "**(3)** Implement `#storeOn:` to generate Smalltalk code which, when evaluated, creates a copy of this snippet." + }, + { + "__type" : "textSnippet", + "children" : { + "__type" : "snippets", + "items" : [ { "__type" : "textSnippet", "children" : { @@ -1023,7 +1064,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:53:37.356744+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377781+01:00" } }, "editEmail" : { @@ -1034,17 +1075,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:53:37.356744+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377781+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "oOhCTtvpDQCUWnDdDeapRg==" + "uidString" : "N355vVDqDQCeEqGFADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "{{gtClass:name=LeTextualSnippet}} requires us to implement {{gtMethod:name=LeTextualSnippet>>#text}}, so we follow the example of {{gtClass:name=LeTextSnippet}} by defining a slot `text`, and accessors {{gtMethod:name=LeBlockQuoteSnippet>>#text}} and {{gtMethod:name=LeBlockQuoteSnippet>>#text:}}. " + "string" : "Snippets belong to Lepiter pages, which are (normally) stored in a Lepiter database as JSON files. (There are also transient databases that exist only in memory, but the more usual case if for databases to be persisted to the file system.) To support this, we must specify how to map the snippet to its JSON representation (and back)." }, { "__type" : "textSnippet", @@ -1060,7 +1101,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:47:11.948772+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377784+01:00" } }, "editEmail" : { @@ -1071,17 +1112,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:53:37.36131+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377784+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "Xw5KN9vpDQCKuk+rDeapRg==" + "uidString" : "On55vVDqDQCeEyeuADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "The `text` slot should be an instance of {{gtClass:name=BlRunRopedText}}, so we also implement {{gtMethod:name=LeBlockQuoteSnippet>>#string:}} so we can initialize the text from a plain string. This will be needed later when we create a block quote snippet from a string representation." + "string" : "We inherit {{gtMethod:name=LePlainTextSnippet class>>#leJsonV4AttributeMapping}}, and since we add no new state, this works out of the box." }, { "__type" : "textSnippet", @@ -1097,7 +1138,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:55:25.780116+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377787+01:00" } }, "editEmail" : { @@ -1108,649 +1149,23 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:56:01.222302+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377787+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "Uf5aU9vpDQCVvcf9DeapRg==" + "uidString" : "PX55vVDqDQCeFDJSADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "Note that we inherit {{gtMethod:name=LeTextualSnippet>>#string}}, which returns the string representation of a textual snippet's text." + "string" : "On the other hand, we have to implement {{gtMethod:name=LeBlockQuoteSnippet class>>#leJsonV4Name}} to return a name — `#blockQuoteSnippet` — for this kind of snippet in the string representation." }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:56:54.785578+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:57:04.285827+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "WnAHWtvpDQCZlXgkDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "We also implement {{gtMethod:name=LeBlockQuoteSnippet>>#contentAsString}}, which is needed by the custom view {{gtMethod:name=LeSnippets>>#gtSnippetsFor:}}." - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:32:13.130398+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:02:57.222458+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "Zyi3AdvpDQC7UZUTDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "**(2)** Define and initialize any needed state. Define any accessors needed to recreate an instance with its state from plain strings." - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:53:02.113058+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:54:53.034529+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "vVcRTNvpDQCUMvd9DeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "We implement {{gtMethod:name=LeBlockQuoteSnippet>>#storeOn:}} to generate a snippet from its string contents." - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:44:01.888975+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:53:17.612869+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "aPj1K9vpDQCJG8aNDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "**(3)** Implement `#storeOn:` to generate Smalltalk code which, when evaluated, creates a copy of this snippet." - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:57:54.637943+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:11:59.01782+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "y7WYXdvpDQCaJb+IDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "Snippets belong to Lepiter pages, which are (normally) stored in a Lepiter database as JSON files. (There are also transient databases that exist only in memory, but the more usual case if for databases to be persisted to the file system.) To support this, we must specify how to map the snippet to its JSON representation (and back)." - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:12:06.364622+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:12:18.805051+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "mwJdkNvpDQCosQ+CDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "Here, for example, is the JSON representation of this page:" - }, - { - "__type" : "pharoSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:08:22.653537+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:21:21.74495+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "2ncHg9vpDQCnWmP0DeapRg==" - }, - "code" : "(thisSnippet database monitor \r\tpageFileReference: thisSnippet page) contents" - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:59:54.979128+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:07:03.431008+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "z/nEZNvpDQChFc1TDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "We implement {{gtMethod:name=LeBlockQuoteSnippet class>>#leJsonV4AttributeMapping}}, which simply adds the mapping `#string -> #string` to the inherited mapping. This will map the value of the string slot to the JSON `\"string\"` attribute." - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:07:07.838961+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:08:17.207118+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "IOORftvpDQClRVT9DeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "We also implement {{gtMethod:name=LeBlockQuoteSnippet class>>#leJsonV4Name}} to return a name for this kind of snippet in the string representation." - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ - { - "__type" : "pharoSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:13:27.142934+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:13:35.102422+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "hJctldvpDQCr5frrDeapRg==" - }, - "code" : "LeJsonV4 cleanUniqueInstance." - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:12:47.571646+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:13:24.48246+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "JsjRktvpDQCp/LX0DeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "*NB:* To register the new mapping, we must update the singleton that stores all the mappings:" - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ - { - "__type" : "pharoSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:13:35.39599+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:16:32.517605+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "doqrldvpDQCr9knqDeapRg==" - }, - "code" : "LeJsonV4 cleanUniqueInstance uniqueInstance \r\tnewReader mappings\r\t\tincludesKey: LeBlockQuoteSnippet" - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:16:45.482954+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:17:03.289264+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "rwUAodvpDQCsa0ZkDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "We can verify that a mapping now exists:" - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:57:37.089675+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T14:57:51.545129+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "a/GMXNvpDQCZ2uvKDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "**(4)** Override the *class* methods `leJsonV4AttributeMapping` and `leJsonV4Name` to specify what state should be mapped to the JSON representation." - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:20:54.061623+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:22:50.41492+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "EmhBrdvpDQCtzE2XDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "We implement {{gtMethod:name=LeBlockQuoteSnippet class>>#contextMenuItemSpecification}} and {{gtMethod:name=LeBlockQuoteSnippet class>>#description}}." - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:17:11.51256+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:19:51.318707+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "sTaNotvpDQCtbpheDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "**(5)** Implement the boilerplate *class* methods `contextMenuItemSpecification` and `description` to include this snippet type in the contextual menu for Lepiter pages." - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ { "__type" : "textSnippet", "children" : { "__type" : "snippets", "items" : [ - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:28:21.348137+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:28:39.574826+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "Qhh6ytvpDQC5rp78DeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "The following classes currently return `false`." - }, { "__type" : "pharoSnippet", "children" : { @@ -1765,7 +1180,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:25:08.562854+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377796+01:00" } }, "editEmail" : { @@ -1776,14 +1191,14 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:28:10.750976+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377796+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "gG38vtvpDQC3DXjGDeapRg==" + "uidString" : "RX55vVDqDQCeFgJWADOILw==" }, - "code" : "(LeSnippet allSubclasses reject: #isAbstract)\r\tselect: [ :c | c new canMoveToAnotherDatabase not ]" + "code" : "LeJsonV4 cleanUniqueInstance." } ] }, @@ -1795,7 +1210,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:23:46.088658+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.37779+01:00" } }, "editEmail" : { @@ -1806,23 +1221,58 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:25:06.703652+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.37779+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "9fcRutvpDQCxx8+WDeapRg==" + "uidString" : "QH55vVDqDQCeFcKdADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "If a snippet has dependencies on files or attachments that are associated with the database of its page, then that page cannot be trivially moved to another database without breaking. If the necessary logic is not implement, this method should return `false`." + "string" : "*NB:* To register the new mapping, we must update the singleton that stores all the mappings:" }, { "__type" : "textSnippet", "children" : { "__type" : "snippets", - "items" : [ ] + "items" : [ + { + "__type" : "pharoSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377804+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377804+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "Tn55vVDqDQCeGCC9ADOILw==" + }, + "code" : "LeJsonV4 cleanUniqueInstance uniqueInstance \r\tnewReader mappings\r\t\tincludesKey: LeBlockQuoteSnippet" + } + ] }, "createEmail" : { "__type" : "email", @@ -1832,7 +1282,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:23:08.300569+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.3778+01:00" } }, "editEmail" : { @@ -1843,98 +1293,58 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:29:03.772511+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.3778+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "Yl7Rt9vpDQCxJd8ADeapRg==" + "uidString" : "Sn55vVDqDQCeF2AlADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "In our case, there are no such dependencies, so {{gtMethod:name=LeBlockQuoteSnippet>>#canMoveToAnotherDatabase}} simply returns true." + "string" : "We can verify that a mapping now exists:" }, { "__type" : "textSnippet", "children" : { "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:33:05.416736+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:35:35.45713+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "W6No29vpDQCBnAdtDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "We also an example page containing the snippet to {{gtClass:name=MovingPagesExamples}} for testing. We define {{gtMethod:name=MovingPagesExamples>>#blockQuoteSnippetPage}}, making sure to set its method category to `*GToolkit-Demo-Snippets`, so it will be an extension method from the new snippet's package, so as not to introduce a dependency from the Lepiter core package to our package. When we are done we can check that the tests pass, especially {{gtMethod:name=MovingPagesExamples>>#moveAllPages}}. " - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:17:26.035748+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:23:39.880464+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "wtFqo9vpDQCthRy2DeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "**(6)** Implement `canMoveToAnotherDatabase` to return `true` if there are no dependencies to files in the database." - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] + "items" : [ + { + "__type" : "pharoSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377812+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377812+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "VX55vVDqDQCeGvmCADOILw==" + }, + "code" : "LeJsonV4 uniqueInstance\r\tserializePretty: (LeBlockQuoteSnippet new\r\t\t\tstring: 'hello';\r\t\t\tyourself)" + } + ] }, "createEmail" : { "__type" : "email", @@ -1944,7 +1354,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:29:20.633502+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377809+01:00" } }, "editEmail" : { @@ -1955,17 +1365,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:29:40.271922+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377809+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "sbcCztvpDQC7yVXeDeapRg==" + "uidString" : "Un55vVDqDQCeGZRqADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We trivially return `self new` in {{gtMethod:name=LeBlockQuoteSnippet class>>#empty}}" + "string" : "and we can serialize a block snippet like this:" } ] }, @@ -1977,7 +1387,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:17:27.915617+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377778+01:00" } }, "editEmail" : { @@ -1988,17 +1398,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:29:14.855236+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377778+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "vYCHo9vpDQCtjDEIDeapRg==" + "uidString" : "NH55vVDqDQCeEVJaADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(7)** Implement required factory method `empty` to return a basic instance." + "string" : "**(4)** Override the *class* methods `leJsonV4AttributeMapping` and `leJsonV4Name` to specify what state should be mapped to the JSON representation." }, { "__type" : "textSnippet", @@ -2019,7 +1429,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:30:53.17476+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377819+01:00" } }, "editEmail" : { @@ -2030,17 +1440,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:32:09.075173+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377819+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "wsiG09vpDQC9XYpADeapRg==" + "uidString" : "XH55vVDqDQCeHOvEADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We define {{gtClass:name=LeBlockQuoteSnippetViewModel}} (see next section), and implement {{gtMethod:name=LeBlockQuoteSnippet>>#asSnippetViewModel}} to return an instance of the view model initialized with this object (`self`) as its snippet model." + "string" : "We implement {{gtMethod:name=LeBlockQuoteSnippet class>>#contextMenuItemSpecification}} and {{gtMethod:name=LeBlockQuoteSnippet class>>#description}}." } ] }, @@ -2052,7 +1462,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:29:56.173791+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377816+01:00" } }, "editEmail" : { @@ -2063,17 +1473,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:30:29.203244+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377816+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "rgQh0NvpDQC80NHUDeapRg==" + "uidString" : "WX55vVDqDQCeG8q7ADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(8)** Define the View Model class, and use it to implement `asSnippetViewModel` to return an instance of the view model holding all the state needed to create the view." + "string" : "**(5)** Implement the boilerplate *class* methods `contextMenuItemSpecification` and `description` to include this snippet type in the contextual menu for Lepiter pages." }, { "__type" : "textSnippet", @@ -2084,7 +1494,79 @@ "__type" : "textSnippet", "children" : { "__type" : "snippets", - "items" : [ ] + "items" : [ + { + "__type" : "textSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377833+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377833+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "a355vVDqDQCeHzoNADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" + }, + "string" : "The following classes currently return `false`." + }, + { + "__type" : "pharoSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377837+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377837+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "b355vVDqDQCeIEPgADOILw==" + }, + "code" : "(LeSnippet allSubclasses reject: #isAbstract)\r\tselect: [ :c | c new canMoveToAnotherDatabase not ]" + } + ] }, "createEmail" : { "__type" : "email", @@ -2094,7 +1576,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:53:53.274692+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.37783+01:00" } }, "editEmail" : { @@ -2105,20 +1587,20 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:04:14.167611+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.37783+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "3XDJJdzpDQCdPpd/Dtc83A==" + "uidString" : "aH55vVDqDQCeHkvbADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "The specific list will depend on where in the class hierarchy the snippet class is defined. We check for any remaining abstract methods as follows:" + "string" : "If a snippet has dependencies on files or attachments that are associated with the database of its page, then that page cannot be trivially moved to another database without breaking. If the necessary logic is not implement, this method should return `false`." }, { - "__type" : "pharoSnippet", + "__type" : "textSnippet", "children" : { "__type" : "snippets", "items" : [ ] @@ -2131,7 +1613,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:38:32.663549+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.37784+01:00" } }, "editEmail" : { @@ -2142,14 +1624,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:38:38.230682+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.37784+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "Qwfq7tvpDQCKXgVvDeapRg==" + "uidString" : "cn55vVDqDQCeIVwzADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" }, - "code" : "LeBlockQuoteSnippet allMethods select: #isAbstract" + "string" : "We inherit this method from {{gtMethod:name=LeTextualSnippet>>#canMoveToAnotherDatabase}}, and do not need to change it." }, { "__type" : "textSnippet", @@ -2165,7 +1650,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:39:41.297734+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377845+01:00" } }, "editEmail" : { @@ -2176,23 +1661,96 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:54:45.01621+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377845+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "yk0B89vpDQCLjqM6DeapRg==" + "uidString" : "dn55vVDqDQCeIh5rADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We still have to implement abstract methods `asPreviewElement`, `appendText:source:`, `updateText:source:`, `asToolElement` and `asPhlowTool`. We can adapt the implementations from {{gtClass:name=LeTextSnippet}}. " - }, + "string" : "We do, however, need to add a test case of an example page containing the snippet to the example class {{gtClass:name=MovingPagesExamples}} for testing. We define {{gtMethod:name=MovingPagesExamples>>#blockQuoteSnippetPage}}, making sure to set its method category to `*GToolkit-Demo-Snippets`, so it will be an extension method from the new snippet's package, so as not to introduce a dependency from the Lepiter core package to our package. When we are done we can check that the tests pass, especially {{gtMethod:name=MovingPagesExamples>>#moveAllPages}}. " + } + ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377822+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377822+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "X355vVDqDQCeHZxMADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" + }, + "string" : "**(6)** Possibly implement `canMoveToAnotherDatabase` to return `true` if there are no dependencies to files in the database." + }, + { + "__type" : "textSnippet", + "children" : { + "__type" : "snippets", + "items" : [ { "__type" : "textSnippet", "children" : { "__type" : "snippets", - "items" : [ ] + "items" : [ + { + "__type" : "pharoSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377856+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377856+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "gX55vVDqDQCeJbz3ADOILw==" + }, + "code" : "LeBlockQuoteSnippet empty" + } + ] }, "createEmail" : { "__type" : "email", @@ -2202,7 +1760,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:36:04.963671+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377853+01:00" } }, "editEmail" : { @@ -2213,17 +1771,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:54:34.384412+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377853+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "Mu7829vpDQCBoVdTDeapRg==" + "uidString" : "fn55vVDqDQCeJGY7ADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We can now verify that all abstract methods are implemented." + "string" : "Again, we inherit {{gtMethod:name=LeBlockQuoteSnippet class>>#empty}}, and do not need to change anything:" } ] }, @@ -2235,7 +1793,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:38:52.934041+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377849+01:00" } }, "editEmail" : { @@ -2246,56 +1804,18 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T15:39:12.733755+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377849+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "v1Qf8NvpDQCKccLyDeapRg==" + "uidString" : "en55vVDqDQCeIzhRADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(9)** Implement any remaining abstract methods." - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:34:59.865176+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:35:35.325556+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "amvsh9jpDQC7HQMuDeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "# Implementing the Model" - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ + "string" : "**(7)** Implement required factory method `empty` to return a basic instance." + }, { "__type" : "textSnippet", "children" : { @@ -2315,7 +1835,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:04:43.288817+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377862+01:00" } }, "editEmail" : { @@ -2326,17 +1846,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:16:58.280271+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377862+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "g9+HTNzpDQCinKmhDtc83A==" + "uidString" : "h355vVDqDQCeJ75vADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We define {{gtClass:name=LeBlockQuoteSnippetViewModel}} as a subclass of {{gtClass:name=LeTextualSnippetViewModel}}. " + "string" : "We define {{gtClass:name=LeBlockQuoteSnippetViewModel}} (see next section), and implement {{gtMethod:name=LeBlockQuoteSnippet>>#asSnippetViewModel}} to return an instance of the view model initialized with this object (`self`) as its snippet model." } ] }, @@ -2348,7 +1868,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:04:26.605842+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377859+01:00" } }, "editEmail" : { @@ -2359,17 +1879,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:04:42.063571+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377859+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "R06JS9zpDQCiY4btDtc83A==" + "uidString" : "hH55vVDqDQCeJhByADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(1)** Define a subclass of {{gtClass:name=LeSnippetViewModel}}(or one of its subclasses)." + "string" : "**(8)** Define the View Model class, and use it to implement the required method `asSnippetViewModel` to return an instance of the view model holding all the state needed to create the view." }, { "__type" : "textSnippet", @@ -2390,7 +1910,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:19:27.734205+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377872+01:00" } }, "editEmail" : { @@ -2401,23 +1921,96 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:25:07.246045+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377872+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "om15e9zpDQCka0InDtc83A==" + "uidString" : "kX55vVDqDQCeKaGMADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We inherit the `snippetModel` slot from {{gtClass:name=LeAbstractSnippetViewModel}} (via the trait {{gtClass:name=TLeWithSnippetModel}}), so we trivially define `LeBlockQuoteSnippetViewModel>>#text` to return the `text` of our model." - }, + "string" : "We implement {{gtMethod:name=LeBlockQuoteSnippet>>#acceptVisitor:}} to simply apply `visitTextSnippet:`. If we want to take special action, we will have to add a new `visit` method, and possibly adapt the existing visitors. See the trait {{gtClass:name=TLeModelVisitor}}. " + } + ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377864+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377864+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "in55vVDqDQCeKIasADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" + }, + "string" : "**(9)** Implement `acceptVisitor:`. This is needed for any utilities that visit the pages of a Lepiter database, such as the HTML export facility." + }, + { + "__type" : "textSnippet", + "children" : { + "__type" : "snippets", + "items" : [ { "__type" : "textSnippet", "children" : { "__type" : "snippets", - "items" : [ ] + "items" : [ + { + "__type" : "pharoSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377886+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377886+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "n355vVDqDQCeLIOXADOILw==" + }, + "code" : "LeBlockQuoteSnippet allMethods select: #isAbstract" + } + ] }, "createEmail" : { "__type" : "email", @@ -2427,7 +2020,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:21:45.792539+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377883+01:00" } }, "editEmail" : { @@ -2438,17 +2031,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:25:10.732668+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377883+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "cAp6idzpDQCqL3ZrDtc83A==" + "uidString" : "nH55vVDqDQCeK19bADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We also define a slot `textEditorModel` to represent the state for the view's editor, with accessors, and an initialization method `LeBlockQuoteSnippetViewModel>>#initializeTextEditorModel`. " + "string" : "The specific list will depend on where in the class hierarchy the snippet class is defined. We check for any remaining abstract methods as follows:" }, { "__type" : "textSnippet", @@ -2464,7 +2057,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:22:13.546356+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377891+01:00" } }, "editEmail" : { @@ -2475,17 +2068,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-11T18:25:14.092722+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377891+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "F4Yhi9zpDQCqUEzNDtc83A==" + "uidString" : "pH55vVDqDQCeLVyJADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "*NB:* in this method we listen for announcements that the text has changed, and notify our dependents that the snippet has changed via `LeBlockQuoteSnippetViewModel>>#announceTextChanged`." + "string" : "There are no remaining abstract methods left to implement, so we are done here." } ] }, @@ -2497,7 +2090,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:04:43.501441+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377875+01:00" } }, "editEmail" : { @@ -2508,18 +2101,56 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:17:44.437716+01:00" + "dateAndTimeString" : "2025-02-12T10:59:54.377875+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "wx2LTNzpDQCioP+KDtc83A==" + "uidString" : "lH55vVDqDQCeKi2cADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(2)** Define accessors for any state needed to maintain the view. Typically these will simply forward to the `snippetModel`." - }, + "string" : "**(10)** Implement any remaining abstract methods." + } + ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377457+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:54.377457+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "IX15vVDqDQCeB6ECADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" + }, + "string" : "# Implementing the Model" + }, + { + "__type" : "textSnippet", + "children" : { + "__type" : "snippets", + "items" : [ { "__type" : "textSnippet", "children" : { @@ -2539,7 +2170,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:24:23.86438+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890393+01:00" } }, "editEmail" : { @@ -2550,17 +2181,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:24:58.649275+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890393+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "jwLmktzpDQCtemrnDtc83A==" + "uidString" : "IdWfvVDqDQCnoASGADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We implement {{gtMethod:name=LeBlockQuoteSnippetViewModel>>#snippetElementClass}} to return the view class (next section)." + "string" : "We define {{gtClass:name=LeBlockQuoteSnippetViewModel}} as a subclass of {{gtClass:name=LePlainTextCoderSnippetViewModel}}. This class provides the scaffolding needed to subscribe to the snippet model, and to update the view model when there are changes." } ] }, @@ -2572,7 +2203,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:04:43.705337+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890306+01:00" } }, "editEmail" : { @@ -2583,17 +2214,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:25:28.674293+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890306+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "QDqOTNzpDQCipIFHDtc83A==" + "uidString" : "59SfvVDqDQCnn6UwADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(3)** Implement the abstract method `snippetElementClass` to return the class of the GUI element class for this snippet." + "string" : "**(1)** Define a subclass of {{gtClass:name=LeSnippetViewModel}}(or one of its subclasses)." }, { "__type" : "textSnippet", @@ -2614,7 +2245,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:26:52.71161+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890417+01:00" } }, "editEmail" : { @@ -2625,51 +2256,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:27:18.754588+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890417+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "yD/Fm9zpDQCxIi5PDtc83A==" + "uidString" : "M9WfvVDqDQCnonTgADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "As before, we can check if any abstract methods remain to be implemented:" - }, - { - "__type" : "pharoSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:27:20.140778+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:27:27.823121+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "oMlnndzpDQCysejZDtc83A==" - }, - "code" : "LeBlockQuoteSnippetViewModel allMethods select: #isAbstract" + "string" : "We inherit `textCoder` and `textCoderViewModel`, but we still have to initialize them." }, { "__type" : "textSnippet", @@ -2685,7 +2282,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:26:47.963398+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.89042+01:00" } }, "editEmail" : { @@ -2696,17 +2293,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:54:39.794241+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.89042+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "2ct8m9zpDQCxDdbaDtc83A==" + "uidString" : "NtWfvVDqDQCno1FtADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We implement {{gtMethod:name=LeBlockQuoteSnippetViewModel>>#moveCursorAt:}} with the help of our `textEditorModel`. This is needed to support the arrow keys moving up and down within a page between snippets." + "string" : "We define {{gtMethod:name=LeBlockQuoteSnippetViewModel>>#initializeTextCoderViewModel}} to define the text coder model and view model that we will need for the view." } ] }, @@ -2718,7 +2315,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:26:02.952008+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890414+01:00" } }, "editEmail" : { @@ -2729,56 +2326,18 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:26:17.56188+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890414+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "bfrNmNzpDQCvc68PDtc83A==" + "uidString" : "L9WfvVDqDQCnoQPvADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(4)** Implement any remaining abstract methods." - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:35:36.142746+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:35:38.846213+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "yfkVitjpDQC8UVI2DeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "# Implementing the View Model" - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ + "string" : "**(2)** Define accessors for any state needed to maintain the view. Typically these will simply forward to the `snippetModel`." + }, { "__type" : "textSnippet", "children" : { @@ -2798,7 +2357,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:28:35.457461+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890426+01:00" } }, "editEmail" : { @@ -2809,17 +2368,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:30:07.477629+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890426+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "MgjlodzpDQCzXqKVDtc83A==" + "uidString" : "O9WfvVDqDQCnpTBmADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We define {{gtClass:name=LeBlockQuoteSnippetElement}} as a subclass of {{gtClass:name=LeTextualSnippetElement}}, which serves as a base element for textual snippets." + "string" : "We implement {{gtMethod:name=LeBlockQuoteSnippetViewModel>>#snippetElementClass}} to return the view class (next section)." } ] }, @@ -2831,7 +2390,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:28:07.735355+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890423+01:00" } }, "editEmail" : { @@ -2842,17 +2401,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:29:05.233042+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890423+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "cQU+oNzpDQCzR4h1Dtc83A==" + "uidString" : "ONWfvVDqDQCnpNyqADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(1)** Define a subclass of {{gtClass:name=LeSnippetElement}} (or one of its subclasses)." + "string" : "**(3)** Implement the abstract method `snippetElementClass` to return the class of the GUI element class for this snippet." }, { "__type" : "textSnippet", @@ -2863,7 +2422,42 @@ "__type" : "textSnippet", "children" : { "__type" : "snippets", - "items" : [ ] + "items" : [ + { + "__type" : "pharoSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:56.890439+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:56.890439+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "SdWfvVDqDQCnqJvIADOILw==" + }, + "code" : "LeBlockQuoteSnippetViewModel allMethods select: #isAbstract" + } + ] }, "createEmail" : { "__type" : "email", @@ -2873,7 +2467,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:32:21.877382+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890431+01:00" } }, "editEmail" : { @@ -2884,17 +2478,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:33:30.007098+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890431+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "0a07pdzpDQC0voaBDtc83A==" + "uidString" : "QNWfvVDqDQCnpzlTADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We need a text editor for the literal block, so we define {{gtMethod:name=LeBlockQuoteSnippetElement>>#initializeEditorElement}} to initialize a `editorElement` slot to a {{gtClass:name=BrEditor}} instance, and set its background to a very light gray." + "string" : "As before, we can check if any abstract methods remain to be implemented:" }, { "__type" : "textSnippet", @@ -2910,7 +2504,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:33:30.387966+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890446+01:00" } }, "editEmail" : { @@ -2921,17 +2515,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:34:42.286266+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890446+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "AlB5s9zpDQC6V9xvDtc83A==" + "uidString" : "T9WfvVDqDQCnqXZPADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We implement the required method {{gtMethod:name=LeTextualSnippetElement>>#editor}} to return this element." + "string" : "There is nothing left to implement, so we are done here." } ] }, @@ -2943,7 +2537,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:31:39.960008+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890428+01:00" } }, "editEmail" : { @@ -2954,18 +2548,56 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:31:49.287632+01:00" + "dateAndTimeString" : "2025-02-12T10:59:56.890428+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "oU/krNzpDQC2zQ30Dtc83A==" + "uidString" : "PtWfvVDqDQCnpp7uADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(2)** Define and initialize the snippet element. Implement the required method {{gtMethod:name=LeSnippetElement>>#snippetContent}} to return this element." - }, + "string" : "**(4)** Implement any remaining abstract methods." + } + ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:56.890173+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:56.890173+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "W9SfvVDqDQCnnhpIADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" + }, + "string" : "# Implementing the View Model" + }, + { + "__type" : "textSnippet", + "children" : { + "__type" : "snippets", + "items" : [ { "__type" : "textSnippet", "children" : { @@ -2975,42 +2607,7 @@ "__type" : "textSnippet", "children" : { "__type" : "snippets", - "items" : [ - { - "__type" : "commentSnippet", - "children" : { - "__type" : "snippets", - "items" : [ ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:38:14.335072+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:39:07.297848+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "gv9lxNzpDQCCSQ5GDtc83A==" - }, - "string" : "Do we really need *both* a text editor model *and* a BlText `text` object? " - } - ] + "items" : [ ] }, "createEmail" : { "__type" : "email", @@ -3020,7 +2617,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:35:52.584939+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862011+01:00" } }, "editEmail" : { @@ -3031,17 +2628,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:38:07.900544+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862011+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "chHzu9zpDQC8ts0FDtc83A==" + "uidString" : "Ay3NvVDqDQCxHEUOADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "In our case, ff the view model changes, we need to bind the editor element to the new editor text model. We override {{gtMethod:name=LeBlockQuoteSnippetElement>>#onSnippetViewModelChanged}} to update the editor element and bind it to the new text editor model and text object." + "string" : "We define {{gtClass:name=LeBlockQuoteSnippetElement}} as a subclass of {{gtClass:name=LePlainTextCoderSnippetElement}}, which serves as a base element for text-based snippets, and includes an instance of {{gtClass:name=GtTextualCoderEditorElement}} as its `editorElement`." } ] }, @@ -3053,7 +2650,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:34:42.760365+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.861878+01:00" } }, "editEmail" : { @@ -3064,17 +2661,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:37:12.076528+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.861878+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "kZXJt9zpDQC7oJnaDtc83A==" + "uidString" : "wyzNvVDqDQCxGznHADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(3)** Listen to changes in the view model by overriding `onSnippetViewModelChanged`." + "string" : "**(1)** Define a subclass of {{gtClass:name=LeSnippetElement}} (or one of its subclasses)." }, { "__type" : "textSnippet", @@ -3095,7 +2692,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:39:43.162054+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862029+01:00" } }, "editEmail" : { @@ -3106,17 +2703,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:40:15.337752+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862029+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "g2OxydzpDQCEo2qEDtc83A==" + "uidString" : "Dy3NvVDqDQCxHqUBADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We don't need any tools, so we implement {{gtMethod:name=LeBlockQuoteSnippetElement>>#snippetToolbar}} to return `nil`." + "string" : "We inherit and override {{gtMethod:name=LeBlockQuoteSnippetElement>>#initializeEditorElement}} to set the editor elements background to a very light gray, and to use a code font." } ] }, @@ -3128,7 +2725,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:28:41.490426+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862026+01:00" } }, "editEmail" : { @@ -3139,56 +2736,18 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:39:30.487942+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862026+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "QhVBotzpDQCzjzt7Dtc83A==" + "uidString" : "DC3NvVDqDQCxHdc/ADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "**(4)** Implement the required method {{gtMethod:name=LeSnippetElement>>#snippetToolbar}} to return the element representing the toolbar to appear below the content. Return `nil` if this is not needed." - } - ] - }, - "createEmail" : { - "__type" : "email", - "emailString" : "" - }, - "createTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:35:31.182126+01:00" - } - }, - "editEmail" : { - "__type" : "email", - "emailString" : "" - }, - "editTime" : { - "__type" : "time", - "time" : { - "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:35:31.969827+01:00" - } - }, - "uid" : { - "__type" : "uid", - "uidString" : "wEfKidjpDQC8Kti6DeapRg==" - }, - "paragraphStyle" : { - "__type" : "textStyle" - }, - "string" : "# Implementing the View" - }, - { - "__type" : "textSnippet", - "children" : { - "__type" : "snippets", - "items" : [ + "string" : "**(2)** Define and initialize the snippet element. " + }, { "__type" : "textSnippet", "children" : { @@ -3208,7 +2767,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:25:47.085979+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862035+01:00" } }, "editEmail" : { @@ -3219,20 +2778,20 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T17:04:56.330397+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862035+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "N6/5ZtjpDQC3WCjbDeapRg==" + "uidString" : "FS3NvVDqDQCxIMXbADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "• If you navigate to another snippet, undo and redo keyboard shortcuts won't apply to the latest changes in the block quote." + "string" : "There is nothing left to do." }, { - "__type" : "textSnippet", + "__type" : "pharoSnippet", "children" : { "__type" : "snippets", "items" : [ ] @@ -3245,7 +2804,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T17:00:18.658636+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862054+01:00" } }, "editEmail" : { @@ -3256,17 +2815,14 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T17:04:59.418224+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862054+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "bJJVE93pDQCsB1iRBchtig==" - }, - "paragraphStyle" : { - "__type" : "textStyle" + "uidString" : "Ky3NvVDqDQCxIcAKADOILw==" }, - "string" : "• Keyboard shortcuts for indentation also do not work." + "code" : "LeBlockQuoteSnippetElement allMethods select: #isAbstract" } ] }, @@ -3278,7 +2834,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:58:06.258798+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862033+01:00" } }, "editEmail" : { @@ -3289,17 +2845,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T17:04:53.558934+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.862033+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "/0xxC93pDQCm78GjBchtig==" + "uidString" : "Ei3NvVDqDQCxHyEkADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "We now have a mostly functional block quote snippet. Still missing is support for keyboard shortcuts:" + "string" : "**(4)** Implement any remaining abstract methods." } ] }, @@ -3311,7 +2867,44 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:25:39.313667+01:00" + "dateAndTimeString" : "2025-02-12T10:59:59.86175+01:00" + } + }, + "editEmail" : { + "__type" : "email", + "emailString" : "" + }, + "editTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T10:59:59.86175+01:00" + } + }, + "uid" : { + "__type" : "uid", + "uidString" : "ICzNvVDqDQCxGjgSADOILw==" + }, + "paragraphStyle" : { + "__type" : "textStyle" + }, + "string" : "# Implementing the View" + }, + { + "__type" : "textSnippet", + "children" : { + "__type" : "snippets", + "items" : [ ] + }, + "createEmail" : { + "__type" : "email", + "emailString" : "" + }, + "createTime" : { + "__type" : "time", + "time" : { + "__type" : "dateAndTime", + "dateAndTimeString" : "2025-02-12T11:00:02.78656+01:00" } }, "editEmail" : { @@ -3322,17 +2915,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T16:58:05.551946+01:00" + "dateAndTimeString" : "2025-02-12T11:00:02.78656+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "WBaDZtjpDQC3BG8aDeapRg==" + "uidString" : "G835vVDqDQC6kpqoADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "# Pending" + "string" : "Now we are basically done. Don't forget, however, if we need to do anything special in visitors, we will have to change {{gtMethod:name=LeBlockQuoteSnippet>>#acceptVisitor:}}, introduce a new `visitBlockQuoteSnippet:` method for all visitors in the trait {{gtClass:name=TLeModelVisitor}}, and eventually update selected visitors to override the default implementation." } ] }, @@ -3344,7 +2937,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:13:18.76247+01:00" + "dateAndTimeString" : "2025-02-12T10:59:20.072945+01:00" } }, "editEmail" : { @@ -3355,15 +2948,15 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T11:13:18.76247+01:00" + "dateAndTimeString" : "2025-02-12T10:59:20.072945+01:00" } }, "pageType" : { "__type" : "namedPage", - "title" : "How to implement a new snippet class" + "title" : "How to implement a new snippet class " }, "uid" : { "__type" : "uuid", - "uuid" : "622d5f3a-d8e9-0d00-a3fe-99870de6a946" + "uuid" : "080a6ebb-50ea-0d00-a52f-efd40033882f" } } \ No newline at end of file diff --git a/lepiter/6k9vwu4iqoe6r1g3or2plhse3.lepiter b/lepiter/6k9vwu4iqoe6r1g3or2plhse3.lepiter index c579aff2f..40348b349 100644 --- a/lepiter/6k9vwu4iqoe6r1g3or2plhse3.lepiter +++ b/lepiter/6k9vwu4iqoe6r1g3or2plhse3.lepiter @@ -14538,7 +14538,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T17:03:59.915841+01:00" + "dateAndTimeString" : "2025-02-12T10:58:37.139524+01:00" } }, "editEmail" : { @@ -14549,17 +14549,17 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T17:04:04.877087+01:00" + "dateAndTimeString" : "2025-02-12T10:58:49.908146+01:00" } }, "uid" : { "__type" : "uid", - "uidString" : "Y7CFIN3pDQCvTWaSBchtig==" + "uidString" : "oObeuFDqDQCjKGPzADOILw==" }, "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "[[How to implement a new snippet class]]" + "string" : "[[How to implement a new snippet class ]]" } ] }, @@ -17518,7 +17518,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2024-10-03T13:29:00.870538+02:00" + "dateAndTimeString" : "2025-02-12T10:58:10.830414+01:00" } }, "uid" : { @@ -17528,7 +17528,7 @@ "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "[[Experemental Development]] " + "string" : "[[Experimental Development]] " }, { "__type" : "textSnippet", diff --git a/lepiter/e5aw30djc0oyppnc0xoxrd2wj.lepiter b/lepiter/e5aw30djc0oyppnc0xoxrd2wj.lepiter index b7f52bea1..c0ec94a43 100644 --- a/lepiter/e5aw30djc0oyppnc0xoxrd2wj.lepiter +++ b/lepiter/e5aw30djc0oyppnc0xoxrd2wj.lepiter @@ -659,7 +659,7 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2025-02-06T17:02:24.958912+01:00" + "dateAndTimeString" : "2025-02-12T10:57:27.048269+01:00" } }, "uid" : { @@ -669,7 +669,7 @@ "paragraphStyle" : { "__type" : "textStyle" }, - "string" : "For more details on implementing snippets, see [[How to implement a new snippet class]]." + "string" : "For more details on implementing snippets, see [[How to implement a new snippet class BROKEN]]." } ] }, diff --git a/lepiter/evkv84bc1s1z6y6cxcr369m6z.lepiter b/lepiter/evkv84bc1s1z6y6cxcr369m6z.lepiter index e5598008f..0da751333 100644 --- a/lepiter/evkv84bc1s1z6y6cxcr369m6z.lepiter +++ b/lepiter/evkv84bc1s1z6y6cxcr369m6z.lepiter @@ -62,12 +62,12 @@ "__type" : "time", "time" : { "__type" : "dateAndTime", - "dateAndTimeString" : "2024-10-03T13:29:00.821491+02:00" + "dateAndTimeString" : "2025-02-12T10:58:05.079162+01:00" } }, "pageType" : { "__type" : "namedPage", - "title" : "Experemental Development" + "title" : "Experimental Development" }, "uid" : { "__type" : "uuid",