Skip to content

Commit

Permalink
Typescriptify Phase V πŸ§žβ€β™‚οΈπŸ§žβ€β™€οΈ (#744)
Browse files Browse the repository at this point in the history
* Revert package updatez for now πŸ₯Ί

* [WIP] Migrate Editor to ts! πŸ§žβ€β™‚οΈ

* More editor related migration πŸ§žβ€β™€οΈπŸ˜²

* Migrates post to TS!! πŸš΄β€β™€οΈ

* More editor migration! πŸ₯‰

* Cleanup types for section parents πŸ‘©β€πŸ‘¦

* Migrate mutation handler + UI!! πŸ₯‰

* EVENT MANAGER MIGRATION! πŸ₯…

* Enable noImplicitAny πŸ‘©β€βš–οΈ
  • Loading branch information
ZeeJab authored Oct 1, 2020
1 parent d27f98d commit 974a8e9
Show file tree
Hide file tree
Showing 58 changed files with 1,261 additions and 845 deletions.
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,10 @@
"@rollup/plugin-commonjs": "^15.0.0",
"@rollup/plugin-node-resolve": "^9.0.0",
"@rollup/plugin-typescript": "^5.0.2",
"@typescript-eslint/eslint-plugin": "^4.0.1",
"@typescript-eslint/parser": "^4.0.1",
"conventional-changelog-cli": "^2.1.0",
"eslint": "^7.8.1",
"@typescript-eslint/eslint-plugin": "^3.6.1",
"@typescript-eslint/parser": "^3.6.1",
"conventional-changelog-cli": "^2.0.34",
"eslint": "^7.4.0",
"eslint-config-prettier": "^6.11.0",
"jquery": "^3.5.1",
"jsdoc": "^3.6.5",
Expand All @@ -67,8 +67,8 @@
"rollup-plugin-serve": "^1.0.4",
"saucie": "^3.3.3",
"testem": "^3.2.0",
"tslib": "^2.0.1",
"typescript": "^4.0.2"
"tslib": "^2.0.0",
"typescript": "^3.9.3"
},
"prettier": {
"arrowParens": "avoid",
Expand Down
4 changes: 2 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ function commonPlugins() {

export default args => [
{
input: 'src/js/index.js',
input: 'src/js/index.ts',
plugins: commonPlugins(),
output: {
file: 'dist/mobiledoc.js',
Expand All @@ -34,7 +34,7 @@ export default args => [
}
},
{
input: 'src/js/index.js',
input: 'src/js/index.ts',
plugins: commonPlugins(),
output: {
file: 'dist/mobiledoc.cjs',
Expand Down
54 changes: 38 additions & 16 deletions src/js/editor/edit-history.js β†’ src/js/editor/edit-history.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,34 @@
import mobiledocParsers from 'mobiledoc-kit/parsers/mobiledoc'
import FixedQueue from 'mobiledoc-kit/utils/fixed-queue'
import Post from '../models/post'
import Section from '../models/_section'
import mobiledocParsers from '../parsers/mobiledoc'
import FixedQueue from '../utils/fixed-queue'
import { Option } from '../utils/types'
import Editor from './editor'
import PostEditor, { EditAction } from './post'
import { Mobiledoc } from '../renderers/mobiledoc'

function findLeafSectionAtIndex(post: Post, index: number) {
let section: Section

function findLeafSectionAtIndex(post, index) {
let section
post.walkAllLeafSections((_section, _index) => {
if (index === _index) {
section = _section
}
})
return section
return section!
}

export class Snapshot {
constructor(takenAt, editor, editAction = null) {
takenAt: number
editor: Editor
editAction: Option<EditAction>
mobiledoc: Mobiledoc
range!: {
head: [number, number]
tail: [number, number]
}

constructor(takenAt: number, editor: Editor, editAction: Option<EditAction> = null) {
this.mobiledoc = editor.serialize()
this.editor = editor
this.editAction = editAction
Expand All @@ -32,28 +48,34 @@ export class Snapshot {
}
}

getRange(post) {
getRange(post: Post) {
if (this.range) {
let { head, tail } = this.range
let [headLeafSectionIndex, headOffset] = head
let [tailLeafSectionIndex, tailOffset] = tail
let headSection = findLeafSectionAtIndex(post, headLeafSectionIndex)
let tailSection = findLeafSectionAtIndex(post, tailLeafSectionIndex)

head = headSection.toPosition(headOffset)
tail = tailSection.toPosition(tailOffset)
let headPosition = headSection.toPosition(headOffset)
let tailPosition = tailSection.toPosition(tailOffset)

return head.toRange(tail)
return headPosition.toRange(tailPosition)
}
}

groupsWith(groupingTimeout, editAction, takenAt) {
groupsWith(groupingTimeout: number, editAction: Option<EditAction>, takenAt: number) {
return editAction !== null && this.editAction === editAction && this.takenAt + groupingTimeout > takenAt
}
}

export default class EditHistory {
constructor(editor, queueLength, groupingTimeout) {
editor: Editor
_undoStack: FixedQueue<Snapshot>
_redoStack: FixedQueue<Snapshot>
_pendingSnapshot: Option<Snapshot>
_groupingTimeout: number

constructor(editor: Editor, queueLength: number, groupingTimeout: number) {
this.editor = editor
this._undoStack = new FixedQueue(queueLength)
this._redoStack = new FixedQueue(queueLength)
Expand All @@ -69,7 +91,7 @@ export default class EditHistory {
}
}

storeSnapshot(editAction = null) {
storeSnapshot(editAction: Option<EditAction> = null) {
let now = Date.now()
// store pending snapshot
let pendingSnapshot = this._pendingSnapshot
Expand All @@ -84,7 +106,7 @@ export default class EditHistory {
this._pendingSnapshot = new Snapshot(now, this.editor, editAction)
}

stepBackward(postEditor) {
stepBackward(postEditor: PostEditor) {
// Throw away the pending snapshot
this._pendingSnapshot = null

Expand All @@ -95,7 +117,7 @@ export default class EditHistory {
}
}

stepForward(postEditor) {
stepForward(postEditor: PostEditor) {
let snapshot = this._redoStack.pop()
if (snapshot) {
this._undoStack.push(new Snapshot(Date.now(), this.editor))
Expand All @@ -104,7 +126,7 @@ export default class EditHistory {
postEditor.cancelSnapshot()
}

_restoreFromSnapshot(snapshot, postEditor) {
_restoreFromSnapshot(snapshot: Snapshot, postEditor: PostEditor) {
let { mobiledoc } = snapshot
let { editor } = this
let { builder, post } = editor
Expand Down
117 changes: 71 additions & 46 deletions src/js/editor/edit-state.js β†’ src/js/editor/edit-state.ts
Original file line number Diff line number Diff line change
@@ -1,16 +1,35 @@
import { contains, isArrayEqual, objectToSortedKVArray } from 'mobiledoc-kit/utils/array-utils'
import Range from 'mobiledoc-kit/utils/cursor/range'
import { contains, isArrayEqual, objectToSortedKVArray } from '../utils/array-utils'
import Range from '../utils/cursor/range'
import { Option, Dict } from '../utils/types'
import Editor from './editor'
import { Cloneable } from '../models/_cloneable'
import Section from '../models/_section'
import Markup from '../models/markup'
import { TagNameable } from '../models/_tag-nameable'
import { getSectionAttributes } from '../models/_attributable'

interface EditStateState {
range: Range
activeMarkups: Markup[]
activeSections: Section[]
activeSectionTagNames: string[]
activeSectionAttributes: Dict<string[]>
}

/**
* Used by {@link Editor} to manage its current state (cursor, active markups
* and active sections).
* @private
*/
export default class EditState {
constructor(editor) {
editor: Option<Editor>
state: Option<EditStateState>
prevState: Option<EditStateState>

constructor(editor: Editor) {
this.editor = editor

let defaultState = {
let defaultState: EditStateState = {
range: Range.blankRange(),
activeMarkups: [],
activeSections: [],
Expand All @@ -21,7 +40,7 @@ export default class EditState {
this.prevState = this.state = defaultState
}

updateRange(newRange) {
updateRange(newRange: Range) {
this.prevState = this.state
this.state = this._readState(newRange)
}
Expand All @@ -34,11 +53,10 @@ export default class EditState {
/**
* @return {Boolean}
*/
rangeDidChange() {
let {
state: { range },
prevState: { range: prevRange },
} = this
rangeDidChange(): boolean {
const { state, prevState } = this
const { range } = state!
const { range: prevRange } = prevState!

return !prevRange.isEqual(range)
}
Expand All @@ -47,8 +65,10 @@ export default class EditState {
* @return {Boolean} Whether the input mode (active markups or active section tag names)
* has changed.
*/
inputModeDidChange() {
let { state, prevState } = this
inputModeDidChange(): boolean {
const state = this.state!
const prevState = this.prevState!

return (
!isArrayEqual(state.activeMarkups, prevState.activeMarkups) ||
!isArrayEqual(state.activeSectionTagNames, prevState.activeSectionTagNames) ||
Expand All @@ -62,29 +82,29 @@ export default class EditState {
/**
* @return {Range}
*/
get range() {
return this.state.range
get range(): Range {
return this.state!.range
}

/**
* @return {Section[]}
*/
get activeSections() {
return this.state.activeSections
get activeSections(): Section[] {
return this.state!.activeSections
}

/**
* @return {Object}
*/
get activeSectionAttributes() {
return this.state.activeSectionAttributes
get activeSectionAttributes(): Dict<string[]> {
return this.state!.activeSectionAttributes
}

/**
* @return {Markup[]}
*/
get activeMarkups() {
return this.state.activeMarkups
get activeMarkups(): Markup[] {
return this.state!.activeMarkups
}

/**
Expand All @@ -93,16 +113,16 @@ export default class EditState {
* in this case the editor needs to track that it has an active "b" markup
* and apply it to the next text the user types.
*/
toggleMarkupState(markup) {
toggleMarkupState(markup: Markup) {
if (contains(this.activeMarkups, markup)) {
this._removeActiveMarkup(markup)
} else {
this._addActiveMarkup(markup)
}
}

_readState(range) {
let state = {
_readState(range: Range): EditStateState {
let state: Partial<EditStateState> = {
range,
activeMarkups: this._readActiveMarkups(range),
activeSections: this._readActiveSections(range),
Expand All @@ -111,53 +131,58 @@ export default class EditState {
// need to map their tagNames now (and compare to mapped tagNames later).
// In addition, to catch changes from ul -> ol, we keep track of the
// un-nested tag names (otherwise we'd only see li -> li change)
state.activeSectionTagNames = state.activeSections.map(s => {
return s.isNested ? s.parent.tagName : s.tagName
state.activeSectionTagNames = state.activeSections!.map(s => {
return s.isNested ? ((s.parent as unknown) as TagNameable).tagName : ((s as unknown) as TagNameable).tagName
})
state.activeSectionAttributes = this._readSectionAttributes(state.activeSections)
return state
state.activeSectionAttributes = this._readSectionAttributes(state.activeSections!)

return state as EditStateState
}

_readActiveSections(range) {
let { head, tail } = range
let {
editor: { post },
} = this
_readActiveSections(range: Range) {
const { head, tail } = range
const { editor } = this
const { post } = editor!

if (range.isBlank) {
return []
} else {
return post.sections.readRange(head.section, tail.section)
return post.sections.readRange(head.section as Cloneable<Section>, tail.section as Cloneable<Section>)
}
}

_readActiveMarkups(range) {
let {
editor: { post },
} = this
_readActiveMarkups(range: Range) {
const { editor } = this
const { post } = editor!

return post.markupsInRange(range)
}

_readSectionAttributes(sections) {
return sections.reduce((sectionAttributes, s) => {
let attributes = s.isNested ? s.parent.attributes : s.attributes
Object.keys(attributes || {}).forEach(attrName => {
_readSectionAttributes(sections: Section[]) {
return sections.reduce<Dict<string[]>>((sectionAttributes, s) => {
let attributes: Dict<string> = getSectionAttributes(s)

Object.keys(attributes).forEach(attrName => {
let camelizedAttrName = attrName.replace(/^data-md-/, '')
let attrValue = attributes[attrName]

sectionAttributes[camelizedAttrName] = sectionAttributes[camelizedAttrName] || []

if (!contains(sectionAttributes[camelizedAttrName], attrValue)) {
sectionAttributes[camelizedAttrName].push(attrValue)
}
})

return sectionAttributes
}, {})
}

_removeActiveMarkup(markup) {
let index = this.state.activeMarkups.indexOf(markup)
this.state.activeMarkups.splice(index, 1)
_removeActiveMarkup(markup: Markup) {
let index = this.state!.activeMarkups.indexOf(markup)
this.state!.activeMarkups.splice(index, 1)
}

_addActiveMarkup(markup) {
this.state.activeMarkups.push(markup)
_addActiveMarkup(markup: Markup) {
this.state!.activeMarkups.push(markup)
}
}
Loading

0 comments on commit 974a8e9

Please sign in to comment.