Christoph Thiede uploaded a new version of CollectionsTests to project The Trunk:
http://source.squeak.org/trunk/CollectionsTests-ct.357.mcz
==================== Summary ====================
Name: CollectionsTests-ct.357
Author: ct
Time: 6 May 2021, 10:10:49.328835 pm
UUID: 4127e94a-ff43-c34b-937d-0760d63c4226
Ancestors: CollectionsTests-nice.354
Adds test for Collections-ct.945 (empty end tag </img>).
=============== Diff against CollectionsTests-nice.354 ===============
Item was added:
+ ----- Method: HtmlReadWriterTest>>test17EmptyEndImgTag (in category 'tests') -----
+ test17EmptyEndImgTag
+ "Empty end tags are disallowed in XHTML but required in HTML5."
+
+ self convertHtml: 'a<img></img>z'.
+ self assert: ({$a. Character value: 1. $z} as: String) equals: text string.
+ self assert: (RunArray new: 3 withAll: #()) equals: text runs!
Christoph Thiede uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-ct.945.mcz
==================== Summary ====================
Name: Collections-ct.945
Author: ct
Time: 6 May 2021, 10:08:28.643835 pm
UUID: 4a526dd8-6418-c44f-aa41-3de63a54b393
Ancestors: Collections-mt.943
Makes HtmlReadWriter robust against HTML5 void tags. As opposed to XHTML tags, they need to be closed manually.
In the past, HTML strings such as the following failed with an "error: this stack is empty":
'<img src="code://Form fromDisplay: World bounds"></img>' asTextFromHtml
This problem is now solved by ignoring void tags in #processEndTag:.
=============== Diff against Collections-mt.943 ===============
Item was added:
+ ----- Method: HtmlReadWriter>>isVoidTag: (in category 'testing') -----
+ isVoidTag: aTag
+
+ ^ self voidTags includes: aTag!
Item was changed:
----- Method: HtmlReadWriter>>processEndTag: (in category 'reading') -----
processEndTag: aTag
| index tagName |
index := count - offset.
tagName := aTag copyFrom: 3 to: aTag size - 1.
+
-
(self isTagIgnored: tagName) ifTrue: [^ self].
+ (self isVoidTag: tagName) ifTrue: [^ self].
tagName = 'code' ifTrue: [self mapCloseCodeTag].
tagName = 'pre' ifTrue: [self breakLines: true].
+
-
self processRunStackTop.
+
-
runStack pop.
+ runStack top at: 2 put: index + 1!
- runStack top at: 2 put: index + 1.!
Item was removed:
- ----- Method: HtmlReadWriter>>processEndTagEagerly: (in category 'reading') -----
- processEndTagEagerly: aTag
- "Not all tags need an end tag. Simulate that here."
-
- (aTag beginsWith: '<img')
- ifTrue: [^ self processEndTag: '</img>'].!
Item was changed:
----- Method: HtmlReadWriter>>processStartTag: (in category 'reading') -----
processStartTag: aTag
+ | tagName index |
+ tagName := (aTag copyWithoutAll: '</>') copyUpTo: Character space.
+ (self isTagIgnored: tagName) ifTrue: [^ self].
+
- | index |
- (self isTagIgnored: aTag) ifTrue: [^ self].
-
index := count - offset.
+
+ tagName = 'br' ifTrue: [
-
- aTag = '<br>' ifTrue: [
self addCharacter: Character cr.
^ self].
+
+ tagName = 'img' ifTrue: [
-
- (aTag beginsWith: '<img') ifTrue: [
self addString: Character startOfHeader asString.
offset := offset + 1.
index := index - 1].
+ self processRunStackTop.
+ "To add all attributes before the next tag adds some."
- self processRunStackTop. "To add all attributes before the next tag adds some."
-
"Copy attr list and add new attr."
+ runStack push: {
+ runStack top first copy
+ addAll: (self mapTagToAttribute: aTag);
+ yourself.
+ index + 1.
+ index + 1}.
+
+ "For void tags such as <img>, we should simulate the closing tag because in case of HTML5 there won't be any."
+ (self isVoidTag: tagName) ifTrue: [self processEndTag: tagName]!
- runStack push: ({runStack top first copy addAll: (self mapTagToAttribute: aTag); yourself. index + 1 . index + 1}).
-
- "For tags such as <img>, we should simulate the closing tag because there won't be any."
- self processEndTagEagerly: aTag.!
Item was added:
+ ----- Method: HtmlReadWriter>>voidTags (in category 'accessing') -----
+ voidTags
+ "Tags that are empty and won't be closed in HTML5."
+
+ ^ #(#img)!
Christoph Thiede uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-ct.944.mcz
==================== Summary ====================
Name: Collections-ct.944
Author: ct
Time: 6 May 2021, 7:19:19.626252 pm
UUID: ff2ccbdf-62a6-9040-ba1a-5c7ae932a1c9
Ancestors: Collections-mt.943
Fixes a slip in HtmlReadWriter when encountering an empty CSS value.
Note that according to W3C, empty CSS values are not permitted, but let's not make our converter fail for such a trivial reason, in particular since I met such a tag in the wild. Also, the check already exists anyway. :-)
=============== Diff against Collections-mt.943 ===============
Item was changed:
----- Method: HtmlReadWriter>>mapContainerTag: (in category 'mapping') -----
mapContainerTag: aTag
| result styleStart styleEnd styleAttributes |
result := OrderedCollection new.
styleStart := (aTag findString: 'style="' ) + 7.
styleStart <= 7 ifTrue: [^#()].
styleEnd := (aTag findString: '"' startingAt: styleStart) - 1.
styleAttributes := (aTag copyFrom: styleStart to: styleEnd) subStrings: ';'.
styleAttributes do: [:ea | |keyValue key value|
keyValue := (ea subStrings: ':') collect: [:s | s withBlanksTrimmed].
key := keyValue first asLowercase.
- value := keyValue second.
keyValue size = 2 ifTrue: [
+ value := keyValue second.
key = 'color' ifTrue: [result add: (TextColor color: (Color fromString: value))].
(key beginsWith: 'font') ifTrue: [
(value includesSubstring: 'bold')
ifTrue: [result add: TextEmphasis bold].
(value includesSubstring: 'italic')
ifTrue: [result add: TextEmphasis italic]]]].
^ result!
Christoph Thiede uploaded a new version of Collections to project The Trunk:
http://source.squeak.org/trunk/Collections-ct.1035.mcz
==================== Summary ====================
Name: Collections-ct.1035
Author: ct
Time: 20 May 2023, 5:16:35.545462 pm
UUID: c36b5e22-b60e-7148-ba41-35c553fb023a
Ancestors: Collections-ct.1034
Adds SequenceableCollection>>groupsCollect: (analogously to #groupsDo: and #pairsCollect:). Especially useful for tests.
=============== Diff against Collections-ct.1034 ===============
Item was added:
+ ----- Method: SequenceableCollection>>groupsCollect: (in category 'enumerating') -----
+ groupsCollect: aBlock
+ "Evaluate aBlock with my elements taken n at a time, where n is the number of arguments of aBlock, and asnwer an Array with the results. Ignore any leftovers at the end."
+
+ | index argumentArray results numArgs endIndex |
+ numArgs := aBlock numArgs.
+ numArgs
+ caseOf: {
+ [ 0 ] -> [ ^self error: 'At least one block argument expected.' ].
+ [ 1 ] -> [ ^self collect: aBlock ].
+ [ 2 ] -> [ ^self pairsCollect: aBlock ] }
+ otherwise: [].
+ argumentArray := Array new: numArgs.
+ results := (Array new: self size // numArgs) writeStream.
+ index := 1.
+ endIndex := self size - numArgs + 1.
+ [ index <= endIndex ] whileTrue: [
+ argumentArray
+ replaceFrom: 1
+ to: numArgs
+ with: self
+ startingAt: index.
+ results nextPut: (aBlock valueWithArguments: argumentArray).
+ index := index + numArgs ].
+ ^ results contents!