Skip to content

Commit

Permalink
1465 extract selected content command (#1475)
Browse files Browse the repository at this point in the history
* ExtractContentCommand
#1465

* Copy or move selected content to new page
#1465
  • Loading branch information
stevencohn authored Jul 12, 2024
1 parent b36c42b commit 27463fc
Show file tree
Hide file tree
Showing 20 changed files with 558 additions and 99 deletions.
10 changes: 10 additions & 0 deletions OneMore/AddInCommands.cs
Original file line number Diff line number Diff line change
Expand Up @@ -248,6 +248,11 @@ public async Task CrawlWebPageCmd(IRibbonControl control)
=> await factory.Run<CrawlWebPageCommand>();


[Command("ribCopyPageContentButton_Label", Keys.None, "ribPageMenu")]
public async Task CopyPageContentCmd(IRibbonControl control)
=> await factory.Run<CopyPageContentCommand>();


[Command("ribCreatePagesButton_Label", Keys.None, "ribPageMenu")]
public async Task CreatePagesCmd(IRibbonControl control)
=> await factory.Run<CreatePagesCommand>();
Expand Down Expand Up @@ -576,6 +581,11 @@ public async Task MovePageBottomCmd(IRibbonControl control)
=> await factory.Run<MovePageCommand>(false);


[Command("ribMovePageContentButton_Label", Keys.None, "ribPageMenu")]
public async Task MovePageContentCmd(IRibbonControl control)
=> await factory.Run<MovePageContentCommand>();


[Command("ribMovePageTopButton_Label", Keys.None, "ribPageMenu")]
public async Task MovePageTopCmd(IRibbonControl control)
=> await factory.Run<MovePageCommand>(true);
Expand Down
24 changes: 8 additions & 16 deletions OneMore/Commands/File/RunPluginCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -410,27 +410,19 @@ private async Task CreatePage(OneNote one, XElement childRoot)

await one.Update(child);

section = await one.GetSection();
var editor = new SectionEditor(section);

if (plugin.AsChildPage)
{
// get current section again after new page is created
section = await one.GetSection();

var parentElement = section.Elements(page.Namespace + "Page")
.First(e => e.Attribute("ID").Value == page.PageId);

var childElement = section.Elements(page.Namespace + "Page")
.First(e => e.Attribute("ID").Value == pageId);

if (childElement != parentElement.NextNode)
if (editor.MovePageToParent(pageId, page.PageId))
{
// move new page immediately after its original in the section
childElement.Remove();
parentElement.AddAfterSelf(childElement);
one.UpdateHierarchy(section);
}

var level = int.Parse(parentElement.Attribute("pageLevel").Value);
childElement.Attribute("pageLevel").Value = (level + 1).ToString();

}
else if (editor.MovePageAfterAnchor(pageId, page.PageId))
{
one.UpdateHierarchy(section);
}

Expand Down
85 changes: 5 additions & 80 deletions OneMore/Commands/Page/DuplicatePageCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@
namespace River.OneMoreAddIn.Commands
{
using River.OneMoreAddIn.Models;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Xml.Linq;

Expand Down Expand Up @@ -40,88 +38,15 @@ public override async Task Execute(params object[] args)
page = new Page(page.Root); // reparse to refresh PageId

var section = await one.GetSection(sectionId);
SetUniquePageTitle(ns, section, page);

await one.Update(page);

MovePageAfterOriginal(one, ns, section, page, originalId);

await one.NavigateTo(page.PageId, string.Empty);
}


private void SetUniquePageTitle(XNamespace ns, XElement section, Page page)
{
// start by extracting just name part without tag
// note that page.Title gets plain text

var match = Regex.Match(page.Title, $@"([^(]+)(?:\s*\((\d+)\))?");
var title = match.Groups[1].Success ? match.Groups[1].Value.Trim() : page.Title;

// match all pages in section on <name>[(tag)]

var regex = new Regex($@"{title}(?:\s*\((\d+)\))?");

// this will also include the current page so should result in a max value
var index = section.Elements(ns + "Page")
.Select(e => regex.Match(e.Attribute("name").Value))
.Where(m => m.Success)
.Max(m => m.Groups[1].Success ? int.Parse(m.Groups[1].Value) : 0) + 1;

// get the sytlized content so we can update the tag in place

var run = page.Root.Elements(ns + "Title")
.Elements(ns + "OE")
.Elements(ns + "T")
.LastOrDefault(e => !string.IsNullOrWhiteSpace(e.GetCData().Value));

if (run == null)
{
// shouldn't happen?
page.Title = $"{page.Title} ({index})";
return;
}

var wrapper = run.GetCData().GetWrapper();
var node = wrapper.Nodes().Last();

var text = node.NodeType == System.Xml.XmlNodeType.Text
? (XText)node
: ((XElement)node).Nodes().OfType<XText>().Last();

regex = new Regex(@"\(\d+\)\s*$");
if (regex.IsMatch(text.Value))
{
text.Value = regex.Replace(text.Value, $"({index})");
}
else
{
text.Value = $"{text.Value} ({index})";
}
var editor = new SectionEditor(section);
editor.SetUniquePageTitle(page);

page.Title = wrapper.GetInnerXml();
}


private void MovePageAfterOriginal(
OneNote one, XNamespace ns, XElement section, Page page, string originalId)
{
var original = section.Elements(ns + "Page")
.FirstOrDefault(e => e.Attribute("ID").Value == originalId);
await one.Update(page);

if (original != null)
if (editor.MovePageAfterAnchor(page.PageId, originalId))
{
var entry = section.Elements(ns + "Page")
.FirstOrDefault(e => e.Attribute("ID").Value == page.PageId);

if (entry != null)
{
entry.Remove();
entry.SetAttributeValue("pageLevel", original.Attribute("pageLevel").Value);
original.AddAfterSelf(entry);

one.UpdateHierarchy(section);
}
one.UpdateHierarchy(section);
}
}
}
Expand Down
100 changes: 100 additions & 0 deletions OneMore/Commands/Page/ExtractContentCommand.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
//************************************************************************************************
// Copyright © 2024 Steven M Cohn. All rights reserved.
//************************************************************************************************

namespace River.OneMoreAddIn.Commands
{
using River.OneMoreAddIn.Models;
using System.Threading.Tasks;


#region Wrappers
internal class CopyPageContentCommand : ExtractContentCommand
{
public CopyPageContentCommand() : base() { }
public override Task Execute(params object[] args)
{
return base.Execute(false);
}
}
internal class MovePageContentCommand : ExtractContentCommand
{
public MovePageContentCommand() : base() { }
public override Task Execute(params object[] args)
{
return base.Execute(true);
}
}
#endregion Wrappers

/// <summary>
/// Copy or move selected content from the current page into a new page, providing a
/// quick and easy way to arbitrarily split up a page into mutliple subpages or extract
/// portions of a page into new subpages.
/// </summary>
internal class ExtractContentCommand : Command
{
public ExtractContentCommand()
{
}


public override async Task Execute(params object[] args)
{
bool move = (bool)args[0];

await using var one = new OneNote(out var page, out _, OneNote.PageDetail.All);

var editor = new PageEditor(page);
var content = await editor.ExtractSelectedContent();
if (!content.HasElements)
{
return;
}

var sectionEditor = new SectionEditor(await one.GetSection());

// current page is the initial anchor
var anchorID = sectionEditor.FindLastIndexedPageIDByTitle(page.Title);

// make target page...

// create a page in this section to capture heading content
one.CreatePage(one.CurrentSectionId, out var targetID);
var target = await one.GetPage(targetID);
target.Title = page.Title; // temp

// refresh the editor
sectionEditor = new SectionEditor(await one.GetSection());
sectionEditor.SetUniquePageTitle(target);

var container = target.EnsureContentContainer();
container.Add(content.Elements());

var map = target.MergeQuickStyles(page);
target.ApplyStyleMapping(map, container);

await one.Update(target);

// place the page in index-order after the source page...

if (anchorID is not null)
{
// refresh the editor
sectionEditor = new SectionEditor(await one.GetSection());
if (sectionEditor.MovePageAfterAnchor(target.PageId, anchorID))
{
one.UpdateHierarchy(sectionEditor.Section);
}
}

if (move)
{
// update the source page, removing the moved content
await one.Update(page);
}

//await one.NavigateTo(page.PageId);
}
}
}
1 change: 0 additions & 1 deletion OneMore/Commands/Page/WordCountCommand.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ namespace River.OneMoreAddIn.Commands
{
using Chinese;
using River.OneMoreAddIn.Models;
using River.OneMoreAddIn.UI;
using System.Linq;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
Expand Down
2 changes: 0 additions & 2 deletions OneMore/Models/PageEditor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -148,8 +148,6 @@ public async Task<XElement> ExtractSelectedContent(XElement targetOutline = null
// IMPORTANT: Within an OE, no more than exactly one OEContent element
// can be selected at a time!



var paragraphs = targetOutline is null
? page.Root.Elements(ns + "Outline").Descendants(ns + "OE")
: targetOutline.Descendants(ns + "OE");
Expand Down
Loading

0 comments on commit 27463fc

Please sign in to comment.