Giter Site home page Giter Site logo

onenote-markdown's Introduction

onenote-markdown

Build Status Code coverage Dependencies status

This is a new prototype for building a markdown editor for OneNote, starting with the editor.

Documentation: https://github.com/dalyIsaac/onenote-markdown/wiki

Deployed web app: https://onenote-markdown.azurewebsites.net/

NOTE: NOT READY FOR USE

Why a new project?

The main reason is that the previous attempt wasn't written with full code coverage, and going back to rectify that was painful. There were also some fundamentally bad architectural decisions - like sending multitudes of unnecessary requests to the Microsoft Graph at once.

This attempt starts with building the editor first, instead of the Microsoft Graph interface. The editor is the most complex component, and thus should be a good starting point.

However, starting from scratch doesn't mean that the old project will be completely ignored - bits and pieces will provide "inspiration" when needed.

Link to old project: https://github.com/dalyIsaac/onenote-markdown-old

Prerequisites

Getting the source

Clone the repo

git clone https://github.com/dalyIsaac/onenote-markdown-prototype.git

Install the dependencies

cd onenote-markdown
npm install

Run dev build

npm start

Build production

npm build

Jest testing

npm test

Debugging in VSCode

Install the Chrome debugger

/vscode/launch.json

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "chrome",
            "request": "launch",
            "name": "Launch Chrome against localhost",
            "url": "http://localhost:3000",
            "webRoot": "${workspaceFolder}"
        },
        {
            "type": "chrome",
            "request": "attach",
            "name": "Attach to Chrome against localhost",
            "port": 9222,
            "url": "localhost:3000",
            "webRoot": "${workspaceFolder}"
        }
    ]
}

To attach to an existing Chrome instance, ensure that Chrome is launched from the command line as:

Windows

<path to chrome>/chrome.exe --remote-debugging-port=9222

macOS

/Applications/Google\ Chrome.app/Contents/MacOS/Google\ Chrome --remote-debugging-port=9222

Linux

google-chrome --remote-debugging-port=9222

onenote-markdown's People

Contributors

dalyisaac avatar dependabot[bot] avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

Forkers

jaylanliu flm143

onenote-markdown's Issues

The markdown compiler does not match inline styling as expected.

Case 1

Markdown:

{color:red}Red{color:Red} text{color:red}

Expected behavior:

<span style="color:red">Red</span> text{color:red}

image

Current behavior:

{color:red}Red{color:Red} text{color:red}

Case 2

Markdown:

{background-color:yellow}High{background-color:yellow}lighted{background-color:yellow}

Expected behavior:

<span style="background-color:yellow">High</span>lighted{background-color:yellow}

image

Current behavior:

{background-color:yellow}High<span style="background-color:yellow">lighted</span>

image

Object references aren't updated after a function call.

In the deleteNode function in src/page/tree/delete.ts, yIndex is defined as a number relating to the index of y in page.nodes, and and y is defined as a node in page.nodes, as seen in https://github.com/dalyIsaac/onenote-markdown-prototype/blob/515b7fd7bd11e6677fa48c1d4c5707307be8f0de/src/page/tree/delete.ts#L211-L237

Later, in the same function, https://github.com/dalyIsaac/onenote-markdown-prototype/blob/515b7fd7bd11e6677fa48c1d4c5707307be8f0de/src/page/tree/delete.ts#L280-L285

If page.nodes[yIndex] is updated to point to a new object, the reference for y will point to an old object.

Thus, in order to avoid variables not being updated, from now on do not use variables like y: Node, and rely on page.nodes[yIndex].

The downsides are that scenarios like https://github.com/dalyIsaac/onenote-markdown-prototype/blob/515b7fd7bd11e6677fa48c1d4c5707307be8f0de/src/page/tree/delete.ts#L324

become

if (page.nodes[page.nodes[x].parent].left === x) {

where xIndex: number is replaced by x: number, and x: Node is no longer used.

This is in a similar vein to #5.

Related files:

  • delete.ts
  • insert.ts
  • rotate.ts
  • tree.ts

Missing unit tests for editor inserting content.

Insertion of content:

  • Insertion inside content
  • Insertion inside a start tag
  • Insertion inside an end tag
  • Insertion between unrelated tags

Insertion of formatting:

  • Insertion inside content
  • Insertion inside a start tag
  • Insertion inside an end tag
  • Insertion between unrelated tags
  • Insertion of formatting around an object by selecting text

Switch replacement to the new insertion model

Currently replacement utilizes the old insertion model.

  • Migrate deletions to the new insertion model
  • Migrate replacement actions to use SelectionBoundary, rather than ContentLocations

Cannot insert a new line at the end of a `StructureNode`.

In Mozilla Firefox Version 67.0b6 (64-bit), attempting to insert a new line by pressing Enter at the end of or inside a StructureNode does not result in a new line being rendered. This behavior has not been replicated using Google Chrome (as of Version 75.0.3745.4 (Official Build) dev (64-bit), on Windows).

To Reproduce:

  1. Place the cursor at the end of, or inside a StructureNode
  2. Press the Enter key, to insert a new line

Expected behavior
A new StructureNode should be created inside the Redux state, and the cursor should be placed on a new line, inside the new StructureNode. If Enter was pressed inside an existing StructureNode, then the content after the selection inside the existing StructureNode should be placed inside the new StructureNode.

Browser: Mozilla Firefox Version 67.0b6 (64-bit)
OS: Windows 10 build 18362.1

Add the ability to delete text in the markdown.

  • Deletion on <p>C</p> resulting in an empty string should convert it to <br /> (Note, C is any random content). #63
  • Deleting single characters using the Backspace key #59
    • Fix for empty new lines
    • Fix for populated new lines
  • Deleting single characters using the Delete key #60
  • Selecting multiple text, and deleting #61
  • Selecting multiple text, and inputting new text #62

Updated insertion model

Currently insertion relies on having the globalOffset of the content - the offset of the content to insert in terms of the entire document. It uses this to

const nodePosition = findNodeAtOffset(page.content, content.globalOffset);

Since selection from the DOM now knows:

/**
* A boundary of a `StructureNode`, in regards to its constituent
* `ContentNode`s.
*/
export interface ContentBoundary {
/**
* The index of the `ContentNode` inside the `RedBlackTree`.
*/
nodeIndex: number;
/**
* The offset of the boundary of the `StructureNode` in regards to the
* `ContentNode`.
*/
nodeStartOffset: number;
}

and

/**
* Describes a `StructureNode` in relation to its `RedBlackTree`, and its
* constituent `ContentNode`s.
*/
interface StructureNodeProperties {
structureNodeIndex: number;
start: ContentBoundary;
end: ContentBoundary;
}
/**
* Describes a boundary for selection within the context of a `StructureNode`.
*/
interface SelectionBoundary extends StructureNodeProperties {
localOffset: number;
}
/**
* Describes the current editor selection.
*/
export interface EditorSelection {
anchor: SelectionBoundary;
focus: SelectionBoundary;
}

insertion should be able to occur with knowing the ContentNodes, and not knowing the globalOffset.

Work will progress as a branch off #64-web-components, and the commit 43424f6.

Multiple spaces are rendered as a single space.

Describe the bug
markdown-it removes extra spaces, as per the Markdown specification. However, it doesn't reflect the expected behavior for displaying the OneNote page.

In the back-end piece table, spaces are inserted. However, they're not rendered by markdown-it.

To Reproduce
Steps to reproduce the behavior:

  1. Load the sample OneNote space
  2. Insert two spaces

Expected behavior
Two spaces are inserted.

Reduce the amount of re-rendering done by React

Problem

At the moment, inputting new content into the editor causes a complete recompilation of OneNote HTML and Markdown. During the process of recompilation, React.createElement is used to create new React elements. However, this causes the virtual DOM to re-render the text node, which results in the position of the caret being lost. Currently, the Selection API is manually updated. However, during the process of Selection being updated, either:

  • The OneNote Markdown cannot be interacted with, due to the risk of user input occurring at the incorrect location in the document.
  • User input occurs at the incorrect location in the document.

Additionally, the caret noticeably strafes between the start of the OneNote Markdown and the expected caret location.

Proposed Solution

The proposed solution is to implement something like https://github.com/lovasoa/react-contenteditable (which is in turn based on https://stackoverflow.com/questions/22677931/react-js-onchange-event-for-contenteditable/27255103#27255103). This works by:

  1. If you put shouldComponentUpdate to avoid caret jumps, then the contenteditable never rerenders (at least on keystrokes)
  1. If the component never re-renders on key stroke, then React keeps an outdated virtual DOM for this contenteditable.

  2. If React keeps an outdated version of the contenteditable in its virtual DOM tree, then if you try to reset the contenteditable to the value outdated in the virtual DOM, then during the virtual DOM diff, React will compute that there are no changes to apply to the DOM!

(Courtesy of https://stackoverflow.com/questions/22677931/react-js-onchange-event-for-contenteditable/27255103#27255103).

The nature of the proposed solution means that each StructureNode should only be recompiled when an update occurs it specifically. This will prevent the entire OneNote Markdown from being re-rendered, improving performance.

Notes

The following should be investigated:

Error when I try to run dev build

when I run npm start in terminal, it show this

Failed to compile.

/Users/xxxxxxxx/onenote-markdown-prototype/src/globals.d.ts
TypeScript error in /Users/xxxxxx/onenote-markdown-prototype/src/globals.d.ts(4,12):
Subsequent property declarations must have the same type.  Property 'inputType' must be of type 'string', but here has type '"insertText" | "insertReplacementText" | "insertLineBreak" | "insertParagraph" | "insertOrderedList" | "insertUnorderedList" | "insertHorizontalRule" | "insertFromYank" | ... 37 more ... | "formatFontName"'.  TS2717

    2 |   readonly data: string | null;
    3 |   readonly dataTransfer: DataTransfer;
  > 4 |   readonly inputType:
      |            ^
    5 |   | "insertText"
    6 |   | "insertReplacementText"
    7 |   | "insertLineBreak"

also, when I try to cd onenote-markdown, it show flip not found because it is onenote-markdown-prototype on my Mac, I just change to cd onenote-markdown-prototype and it work

Inline HTML tags aren't rendered by React.

The below HTML does not render to "Superscript x2"

<p id="p:{28216e73-1f0a-05fd-25c5-a04844147e70}{29}" style="margin-top:0pt;margin-bottom:0pt">
    Superscript x<sup>2</sup>
</p>

Add the ability to insert text in the markdown.

Insertion of content:

  • Insertion inside content
  • Insertion inside a start tag
  • Insertion inside an end tag
  • Insertion between unrelated tags

Insertion of formatting:

  • Insertion inside content
  • Insertion inside a start tag
  • Insertion inside an end tag
  • Insertion between unrelated tags
  • Insertion of formatting around an object by selecting text

Unterminated tags written inside the markdown editor cause the application to break.

Repro steps

  1. Load the sample OneNote page
  2. Type {color:red}

Current behavior

React throws an error:

Invariant Violation: Objects are not valid as a React child (found: object with keys {node}). If you meant to render a collection of children, use an array instead.

Expected behavior

The unterminated tag is terminated automatically at the end of the StructureNode.

Deleting single characters using the Backspace key

Sub-section of #48

  • Delete a single character inside a StructureNode, and update the selection
  • Delete a single character at the start of a StructureNode, and update the selection
  • Delete a line when the selection is a <br />

Add the ability to insert new `StructureNode`s

Inserting newlines

OneNote HTML
Before single newline <p style="margin-top:0pt;margin-bottom:0pt">Before single newline</p>
Before two newlines <p style="margin-top:0pt;margin-bottom:0pt">Before two newlines</p>
<br />
Before three newlines <p style="margin-top:0pt;margin-bottom:0pt">Before three newlines</p>
<br />
<br />
Hello <p style="margin-top:0pt;margin-bottom:0pt">Hello</p>

Inserting new StructureNodes

Inserting a newline, then a tag should insert a new tag.

Splitting existing StructureNodes

Inserting a newline inside an existing StructureNode should create a new StructureNode. The content after the newline should be removed from the existing StructureNode, and placed inside the new StructureNode. All attributes of the old StructureNode, apart from the id, data-id, and tag should be copied to the new StructureNode.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.