Skip to content

Commit 3d1702e

Browse files
feat: Turtle.get/set_Style ( Fixes #254 )
Making get return all styles, and making set convert to CSS
1 parent 28ec8c9 commit 3d1702e

File tree

3 files changed

+135
-31
lines changed

3 files changed

+135
-31
lines changed

Types/Turtle/get_SVG.ps1

Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -52,33 +52,11 @@ $svgElement = @(
5252
"</defs>"
5353
}
5454

55-
if ($this.Keyframe.Count -or $this.Style) {
56-
$keyframe = $this.Keyframe
57-
"<style>"
58-
@(foreach ($keyframeName in $keyframe.Keys) {
59-
$keyframeKeyframes = $keyframe[$keyframeName]
60-
"@keyframes $keyframeName {"
61-
foreach ($percent in $keyframeKeyframes.Keys) {
62-
" $percent {"
63-
$props = $keyframeKeyframes[$percent]
64-
foreach ($prop in $props.Keys) {
65-
$value = $props.$prop
66-
" ${prop}: $value;"
67-
}
68-
" }"
69-
}
70-
"}"
71-
".$keyframeName {"
72-
" animation-name: $keyframeName;"
73-
" animation-duration: $($this.Duration.TotalSeconds)s;"
74-
" animation-iteration-count: infinite;"
75-
"}"
76-
}) -join [Environment]::NewLine
77-
if ($this.Style) {
78-
"$($this.Style -join (';' + [Environment]::NewLine))"
79-
}
80-
"</style>"
81-
}
55+
$style = $this.Style
56+
if ($style -is [xml]) {
57+
$style.OuterXml
58+
}
59+
8260

8361
# Declare any SVG animations
8462
if ($this.SVGAnimation) {$this.SVGAnimation}

Types/Turtle/get_Style.ps1

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,4 +14,66 @@ if (-not $this.'.style') {
1414
$this | Add-Member NoteProperty '.style' @() -Force
1515
}
1616

17+
$keyframe = $this.Keyframe
18+
$myVariables = $this.Variable
19+
$cssTypePattern = '^(?<type>\<[\w-].+?\>)[\:\=]?'
20+
$myCssVariables = foreach ($variableKey in $myVariables.Keys -match '^--') {
21+
$variableValue = $myVariables[$variableKey]
22+
if ($variableValue -match $cssTypePattern) {
23+
$variableValue = $variableValue -replace $cssTypePattern
24+
"@property $variableKey { syntax: '$(
25+
[Security.SecurityElement]::Escape($matches.type)
26+
)'; initial-value: $($variableValue -replace $cssTypePattern)}"
27+
}
28+
"$variableKey",':', $variableValue -join ''
29+
}
30+
$styleElementParts = @(
31+
if ($myCssVariables) {
32+
"#$($this.id)-path, #$($this.id)-text {"
33+
($myCssVariables -join (';' + [Environment]::NewLine + (' ' * 4)))
34+
"}"
35+
}
36+
foreach ($keyframeName in $keyframe.Keys) {
37+
$keyframeKeyframes = $keyframe[$keyframeName]
38+
"@keyframes $keyframeName {"
39+
foreach ($percent in $keyframeKeyframes.Keys) {
40+
" $percent {"
41+
$props = $keyframeKeyframes[$percent]
42+
foreach ($prop in $props.Keys) {
43+
$value = $props.$prop
44+
" ${prop}: $value;"
45+
}
46+
" }"
47+
}
48+
"}"
49+
".$keyframeName {"
50+
" animation-name: $keyframeName;"
51+
" animation-duration: $($this.Duration.TotalSeconds)s;"
52+
" animation-iteration-count: infinite;"
53+
"}"
54+
}
55+
if ($this.'.Style') {
56+
"$($this.'.Style' -join (';' + [Environment]::NewLine))"
57+
}
58+
)
59+
60+
if ($styleElementParts) {
61+
# Style elements are one of the only places where we can be reasonably certain there will not be child elements
62+
try {
63+
# so if we have an error with unescaped content
64+
return [xml]@("<style>"
65+
$styleElementParts -join [Environment]::NewLine
66+
"</style>")
67+
} catch {
68+
# catch it and escape the content
69+
return [xml]@(
70+
"<style>"
71+
[Security.SecurityElement]::Escape($styleElementParts -join [Environment]::NewLine)
72+
"</style>"
73+
)
74+
}
75+
} else {
76+
return ''
77+
}
78+
1779
return $this.'.style'

Types/Turtle/set_Style.ps1

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,12 +7,76 @@
77
These styles will be declared in a `<style>` element, just beneath a Turtle's `<svg>`
88
.EXAMPLE
99
turtle style '.myClass { color: #4488ff}' style
10+
.EXAMPLE
11+
turtle style abc
12+
.EXAMPLE
13+
turtle style "@import url('https://fonts.googleapis.com/css?family=Abel')" text 'Hello World' textattribute @{'font-family'='Abel';'font-size'='3em'} fill 'red' save ./t.png show
1014
#>
1115
param(
12-
[PSObject]
16+
[PSObject[]]
1317
$Style
1418
)
1519

16-
$styleList = $this.Style
17-
$styleList += $style
18-
$this | Add-Member NoteProperty '.style' $styleList -Force
20+
filter toCss {
21+
# Capture the input,
22+
$in = $_
23+
# know myself,
24+
$mySelf = $MyInvocation.MyCommand.ScriptBlock
25+
# and determine our depth
26+
$depth = 0
27+
# (with a little callstack peeking).
28+
foreach ($frame in Get-PSCallStack) {
29+
if ($frame.InvocationInfo.MyCommand.ScriptBlock -eq $mySelf) {
30+
$depth++
31+
}
32+
}
33+
# Always substract one so we don't indent the root.
34+
$depth--
35+
36+
if ($in -is [string]) {
37+
$in # Directly output strings
38+
} elseif ($in -is [Collections.IDictionary]) {
39+
# Join dictionaries by semicolons and indentation
40+
($in.GetEnumerator() | & $mySelf) -join (
41+
';' + [Environment]::NewLine + (' ' * 2 * $depth)
42+
)
43+
} elseif ($in.Key -and $in.Value) {
44+
# Key/value pairs containing dictionaries
45+
if ($in.Value -is [Collections.IDictionary]) {
46+
# become `selector { rules }`
47+
(
48+
"$($in.Key) {", (
49+
(' ' * 2) + ($in.Value | & $mySelf)
50+
) -join (
51+
[Environment]::NewLine + (' ' * 2 * $depth)
52+
)
53+
) + (
54+
[Environment]::NewLine + (' ' * 2 * ($depth - 1))
55+
) + '}'
56+
}
57+
elseif ($in.Value -is [TimeSpan]) {
58+
"$($in.Key):$($in.Value.TotalSeconds)s"
59+
}
60+
else {
61+
# Other key/value pairs are placed inline
62+
"$($in.Key):$($in.Value)"
63+
}
64+
}
65+
elseif ($in -is [PSObject]) {
66+
# turn non-dictionaries into dictionaries
67+
$inDictionary = [Ordered]@{}
68+
foreach ($property in $in.psobject.properties) {
69+
$inDictionary[$property.Name] = $in.($property.Name)
70+
}
71+
if ($inDictionary.Count) {
72+
# and recurse.
73+
$inDictionary | & $mySelf
74+
}
75+
}
76+
}
77+
78+
if (-not $this.'.style') {
79+
$this | Add-Member NoteProperty '.style' @() -Force
80+
}
81+
$this.'.style' += $style |toCss
82+

0 commit comments

Comments
 (0)