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 $deadline = [DateTime]::UtcNow.AddSeconds(30)
47 do {
48 $app.GetHierarchy($section, 4, [ref]$hierarchy, 1)
49 [xml]$tree = $hierarchy
50 $manager = New-Object Xml.XmlNamespaceManager($tree.NameTable)
51 $manager.AddNamespace('one', $ns)
52 if (@($tree.SelectNodes('//one:Page', $manager)).Count -eq $cases.Count + 1) { break }
53 Start-Sleep -Milliseconds 200
54 } while ([DateTime]::UtcNow -lt $deadline)
55 $updates = Join-Path $Root 'remote-updates'
56 [void](New-Item -ItemType Directory -Path $updates -Force)
57 foreach ($case in @($cases)[4..15]) {
58 $page = @($tree.SelectNodes('//one:Page', $manager) | Where-Object { $_.GetAttribute('name') -eq $case.name })
59 if ($page.Count -ne 1) { throw ('Expected one native control page: ' + $case.name) }
60 $content = ''
61 $app.GetPageContent($page[0].GetAttribute('ID'), [ref]$content, 0, 1)
62 [xml]$xml = $content
63 $manager = New-Object Xml.XmlNamespaceManager($xml.NameTable)
64 $manager.AddNamespace('one', $ns)
65 $outline = $xml.SelectSingleNode('/one:Page/one:Outline/one:OEChildren', $manager)
66 $paragraphs = @($outline.SelectNodes('one:OE', $manager))
67 $left = $paragraphs[0]
68 $target = if ($case.operation -eq 'join') { $paragraphs[1] } else { $left }
69 switch ($case.change) {
70 'prefix' {
71 $text = $left.SelectSingleNode('one:T', $manager)
72 $text.InnerText = 'X' + $text.InnerText
73 if ($case.operation -eq 'join') {
74 $text = $target.SelectSingleNode('one:T', $manager)
75 $text.InnerText += 'Y'
76 }
77 }
78 'boundary' {
79 $text = $left.SelectSingleNode('one:T', $manager)
80 if ($case.operation -eq 'split') {
81 if (-not $text.InnerText.Contains('ab')) { throw 'The split boundary control lost its text' }
82 $text.InnerText = $text.InnerText.Replace('ab', 'abX')
83 } else { $text.InnerText += 'X' }
84 }
85 'right-boundary' {
86 $text = $target.SelectSingleNode('one:T', $manager)
87 $text.InnerText = 'X' + $text.InnerText
88 }
89 'child' {
90 $children = $xml.CreateElement('one', 'OEChildren', $ns)
91 $child = $xml.CreateElement('one', 'OE', $ns)
92 $text = $xml.CreateElement('one', 'T', $ns)
93 $text.InnerText = 'Native child'
94 [void]$child.AppendChild($text)
95 [void]$children.AppendChild($child)
96 [void]$target.AppendChild($children)
97 }
98 'list' {
99 $list = $xml.CreateElement('one', 'List', $ns)
100 $bullet = $xml.CreateElement('one', 'Bullet', $ns)
101 $bullet.SetAttribute('bullet', '3')
102 $bullet.SetAttribute('fontSize', '11')
103 [void]$list.AppendChild($bullet)
104 [void]$target.PrependChild($list)
105 }
106 'tag' {
107 if (-not $xml.SelectSingleNode('/one:Page/one:TagDef[@index="0"]', $manager)) {
108 $definition = $xml.CreateDocumentFragment()
109 $definition.InnerXml = $tagDefinition
110 [void]$xml.DocumentElement.PrependChild($definition)
111 }
112 $tag = $xml.CreateElement('one', 'Tag', $ns)
113 foreach ($pair in @{ index='0'; completed='false'; disabled='false'; creationDate='2020-01-02T03:04:05.000Z' }.GetEnumerator()) { $tag.SetAttribute($pair.Key, $pair.Value) }
114 [void]$target.PrependChild($tag)
115 }
116 'format' {
117 $text = $target.SelectSingleNode('one:T', $manager)
118 $plain = if ($case.operation -eq 'join') { 'Right' } else { 'ab' + [char]::ConvertFromUtf32(0x1F980) + 'cd' }
119 $text.InnerText = '<i>' + $plain + '</i>'
120 }
121 'sibling' { $paragraphs[-1].SelectSingleNode('one:T', $manager).InnerText = 'Native sibling' }
122 'adoption' { $left.SelectSingleNode('one:T', $manager).InnerText = 'X' }
123 default { throw ('Unknown native control: ' + $case.change) }
124 }
125 $xml.Save((Join-Path $updates ($case.name + '.xml')))
126 Write-Output ('Updating: ' + $case.name)
127 $app.UpdatePageContent($xml.OuterXml, [DateTime]::MinValue, 1, $true)
128 Write-Output ('Applied: ' + $case.name)
129 }
130 }
131 $app.SyncHierarchy($notebook)
132} finally {
133 if ($notebook) { $app.CloseNotebook($notebook, $false) }
134 [void][Runtime.InteropServices.Marshal]::FinalReleaseComObject($app)
135 $app = $null
136 [GC]::Collect()
137 [GC]::WaitForPendingFinalizers()
138}