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