1param([Parameter(Mandatory=$true)][string]$Root, [Parameter(Mandatory=$true)][string]$CloneHost, [switch]$Remote)
2Set-StrictMode -Version Latest
3$ErrorActionPreference = 'Stop'
4if (-not $Remote) { & "$PSScriptRoot\cold-current.ps1" -Root $Root -CloneHost $CloneHost }
5$app = New-Object -ComObject OneNote.Application
6$notebook = ''
7$ns = 'http://schemas.microsoft.com/office/onenote/2010/onenote'
8$tagDefinition = '<one:TagDef xmlns:one="' + $ns + '" index="0" type="0" symbol="3" fontColor="automatic" highlightColor="none" name="Native task"/>'
9try {
10 $app.OpenHierarchy((Join-Path $Root 'notebook'), '', [ref]$notebook, 0)
11 $section = ''
12 $app.OpenHierarchy('synthetic.one', $notebook, [ref]$section, 0)
13 if (-not $Remote) {
14 $cases = @(
15 @{ name = 'Split remote prefix'; operation = 'split'; change = 'prefix' },
16 @{ name = 'Split remote boundary'; operation = 'split'; change = 'boundary' },
17 @{ name = 'Split remote child'; operation = 'split'; change = 'child' },
18 @{ name = 'Split remote list'; operation = 'split'; change = 'list' },
19 @{ name = 'Split remote tag'; operation = 'split'; change = 'tag' },
20 @{ name = 'Split remote format'; operation = 'split'; change = 'format' },
21 @{ name = 'Split remote sibling'; operation = 'split'; change = 'sibling' },
22 @{ name = 'Join remote prefix'; operation = 'join'; change = 'prefix' },
23 @{ name = 'Join left boundary'; operation = 'join'; change = 'boundary' },
24 @{ name = 'Join right boundary'; operation = 'join'; change = 'right-boundary' },
25 @{ name = 'Join remote child'; operation = 'join'; change = 'child' },
26 @{ name = 'Join remote list'; operation = 'join'; change = 'list' },
27 @{ name = 'Join remote tag'; operation = 'join'; change = 'tag' },
28 @{ name = 'Join remote format'; operation = 'join'; change = 'format' },
29 @{ name = 'Join remote sibling'; operation = 'join'; change = 'sibling' },
30 @{ name = 'Join empty adoption'; operation = 'join'; change = 'adoption' }
31 )
32 foreach ($case in $cases) {
33 $page = ''
34 $app.CreateNewPage($section, [ref]$page, 0)
35 $left = if ($case.change -eq 'adoption') { '' } else { 'ab' + [char]::ConvertFromUtf32(0x1F980) + 'cd' }
36 $body = '<one:OE><one:T><![CDATA[<b>' + $left + '</b>]]></one:T></one:OE>'
37 if ($case.operation -eq 'join') { $body += '<one:OE><one:T><![CDATA[<b>Right</b>]]></one:T></one:OE>' }
38 $body += '<one:OE><one:T>Preserved sibling</one:T></one:OE>'
39 $xml = '<one:Page xmlns:one="' + $ns + '" ID="' + $page + '">' + $tagDefinition + '<one:Title><one:OE><one:T>' + $case.name + '</one:T></one:OE></one:Title><one:Outline><one:Position x="72" y="108"/><one:OEChildren>' + $body + '</one:OEChildren></one:Outline></one:Page>'
40 $app.UpdatePageContent($xml, [DateTime]::MinValue, 1, $true)
41 }
42 $cases | ConvertTo-Json -Depth 6 | Set-Content (Join-Path $Root 'cases.json') -Encoding UTF8
43 } else {
44 $cases = Get-Content (Join-Path $Root 'cases.json') -Raw | ConvertFrom-Json
45 $hierarchy = ''
46 $app.GetHierarchy($section, 4, [ref]$hierarchy, 1)
47 [xml]$tree = $hierarchy
48 $manager = New-Object Xml.XmlNamespaceManager($tree.NameTable)
49 $manager.AddNamespace('one', $ns)
50 foreach ($case in $cases) {
51 $page = @($tree.SelectNodes('//one:Page', $manager) | Where-Object { $_.GetAttribute('name') -eq $case.name })
52 if ($page.Count -ne 1) { throw ('Expected one native control page: ' + $case.name) }
53 $content = ''
54 $app.GetPageContent($page[0].GetAttribute('ID'), [ref]$content, 0, 1)
55 [xml]$xml = $content
56 $manager = New-Object Xml.XmlNamespaceManager($xml.NameTable)
57 $manager.AddNamespace('one', $ns)
58 $outline = $xml.SelectSingleNode('/one:Page/one:Outline/one:OEChildren', $manager)
59 $paragraphs = @($outline.SelectNodes('one:OE', $manager))
60 $left = $paragraphs[0]
61 $target = if ($case.operation -eq 'join') { $paragraphs[1] } else { $left }
62 switch ($case.change) {
63 'prefix' {
64 $text = $left.SelectSingleNode('one:T', $manager)
65 $text.InnerText = 'X' + $text.InnerText
66 if ($case.operation -eq 'join') {
67 $text = $target.SelectSingleNode('one:T', $manager)
68 $text.InnerText += 'Y'
69 }
70 }
71 'boundary' {
72 $text = $left.SelectSingleNode('one:T', $manager)
73 if ($case.operation -eq 'split') {
74 if (-not $text.InnerText.Contains('ab')) { throw 'The split boundary control lost its text' }
75 $text.InnerText = $text.InnerText.Replace('ab', 'abX')
76 } else { $text.InnerText += 'X' }
77 }
78 'right-boundary' {
79 $text = $target.SelectSingleNode('one:T', $manager)
80 $text.InnerText = 'X' + $text.InnerText
81 }
82 'child' {
83 $children = $xml.CreateElement('one', 'OEChildren', $ns)
84 $child = $xml.CreateElement('one', 'OE', $ns)
85 $text = $xml.CreateElement('one', 'T', $ns)
86 $text.InnerText = 'Native child'
87 [void]$child.AppendChild($text)
88 [void]$children.AppendChild($child)
89 [void]$target.AppendChild($children)
90 }
91 'list' {
92 $list = $xml.CreateElement('one', 'List', $ns)
93 $bullet = $xml.CreateElement('one', 'Bullet', $ns)
94 $bullet.SetAttribute('bullet', '3')
95 $bullet.SetAttribute('fontSize', '11')
96 [void]$list.AppendChild($bullet)
97 [void]$target.PrependChild($list)
98 }
99 'tag' {
100 if (-not $xml.SelectSingleNode('/one:Page/one:TagDef[@index="0"]', $manager)) {
101 $definition = $xml.CreateDocumentFragment()
102 $definition.InnerXml = $tagDefinition
103 [void]$xml.DocumentElement.InsertBefore($definition, $xml.SelectSingleNode('/one:Page/one:Title', $manager))
104 }
105 $tag = $xml.CreateElement('one', 'Tag', $ns)
106 foreach ($pair in @{ index='0'; completed='false'; disabled='false'; creationDate='2020-01-02T03:04:05.000Z' }.GetEnumerator()) { $tag.SetAttribute($pair.Key, $pair.Value) }
107 [void]$target.PrependChild($tag)
108 }
109 'format' {
110 $text = $target.SelectSingleNode('one:T', $manager)
111 $plain = if ($case.operation -eq 'join') { 'Right' } else { 'ab' + [char]::ConvertFromUtf32(0x1F980) + 'cd' }
112 $text.InnerText = '<i>' + $plain + '</i>'
113 }
114 'sibling' { $paragraphs[-1].SelectSingleNode('one:T', $manager).InnerText = 'Native sibling' }
115 'adoption' { $left.SelectSingleNode('one:T', $manager).InnerText = 'X' }
116 default { throw ('Unknown native control: ' + $case.change) }
117 }
118 $app.UpdatePageContent($xml.OuterXml, [DateTime]::MinValue, 1, $true)
119 }
120 }
121 $app.SyncHierarchy($notebook)
122} finally {
123 if ($notebook) { $app.CloseNotebook($notebook, $false) }
124 [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app)
125 $app = $null
126 [GC]::Collect()
127 [GC]::WaitForPendingFinalizers()
128}