-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This commit adds basic support for parsing the text ranges in the notification blocks. This essentially means that we are introducing styling on the note content, though that styling is severaly limited at this point. The algorithm for building the formatting uses a form of a topological sort of the text ranges, then recursively breaks down the remaining text in the string for each interval. This builds an object specifying special properties of the range and which nests according to the ranges. ```js const block = { text: 'Math is fun!', ranges: [ { indices: [ 0, 11 ], type: 'blockquote' }, { indices: [ 0, 4 ], type: 'b' } ] } // --> turns into... const tree = [ { type: 'blockquote', children: [ { type: 'b', children: [ 'Math' ] }, ' is fun!' ] } ] ``` The view layer can take this plain object and translate it according to the goal: the app currently turns this into a React component hierarchy. It's worth noting that ranges that aren't understood by the app default to a textblock that gets surrounded by a span with a CSS class corresponding to the `type` of the node.
- Loading branch information
Showing
19 changed files
with
266 additions
and
22 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
import { | ||
complement, | ||
compose, | ||
flip, | ||
init, | ||
isEmpty, | ||
propOr, | ||
tail | ||
} from 'ramda'; | ||
|
||
const notEmpty = complement( isEmpty ); | ||
|
||
const rangeSort = ( { indices: [ aStart, aEnd ] }, { indices: [ bStart, bEnd ] } ) => { | ||
if ( aStart === 0 && aEnd === 0 && bEnd !== 0 ) return -1; | ||
|
||
if ( aStart < bStart ) return -1; | ||
if ( bStart < aStart ) return 1; | ||
|
||
return bEnd - aEnd; | ||
}; | ||
|
||
const encloses = | ||
( { indices: [ innerStart, innerEnd ] } ) => | ||
( { indices: [ outerStart, outerEnd ] = [ 0, 0 ]} ) => | ||
( innerStart !== 0 && innerEnd !== 0 ) && | ||
( outerStart <= innerStart && outerEnd >= innerEnd ); | ||
|
||
const addRange = ( ranges, range ) => { | ||
const parent = ranges.find( encloses( range ) ); | ||
|
||
if ( ! parent ) return [ ...ranges, range ]; | ||
|
||
return [ | ||
...init( ranges ), | ||
{ ...parent, children: addRange( parent.children, range ) } | ||
]; | ||
}; | ||
|
||
const commentNode = ( { id: commentId, post_id: postId, site_id: siteId } ) => | ||
( { type: 'comment', commentId, postId, siteId } ); | ||
|
||
const linkNode = ( { url } ) => | ||
( { type: 'link', url } ); | ||
|
||
const postNode = ( { id: postId, site_id: siteId } ) => | ||
( { type: 'post', postId, siteId } ); | ||
|
||
const siteNode = ( { id: siteId } ) => | ||
( { type: 'site', siteId } ); | ||
|
||
const typedNode = ( { type } ) => | ||
( { type } ); | ||
|
||
const userNode = ( { id } ) => | ||
( { type: 'user', id } ); | ||
|
||
const inferNode = range => { | ||
const { type, url } = range; | ||
|
||
if ( type ) return typedNode( range ); | ||
|
||
if ( url ) return linkNode( range ); | ||
|
||
return range; | ||
}; | ||
|
||
const nodeMappings = flip( propOr( inferNode ) )( { | ||
comment: commentNode, | ||
post: postNode, | ||
site: siteNode, | ||
user: userNode | ||
} ); | ||
|
||
const newNode = ( text, range = {} ) => ( { | ||
...nodeMappings( range.type )( range ), | ||
children: [ { type: 'text', text } ] | ||
} ); | ||
|
||
const joinResults = ( [ reduced, remainder, ] ) => | ||
reduced.length | ||
? reduced.concat( remainder ).filter( notEmpty ) | ||
: remainder.length ? [ remainder ] : []; | ||
|
||
const parse = ( [ prev, text, offset ], nextRange ) => { | ||
const { indices: [ start, end ] } = nextRange; | ||
const offsetStart = start - offset; | ||
const offsetEnd = end - offset; | ||
|
||
const preText = ( offsetStart > 0 ) ? [ text.slice( 0, offsetStart ) ] : []; | ||
|
||
const children = joinResults( | ||
nextRange | ||
.children | ||
.reduce( parse, [ [], text.slice( offsetStart, offsetEnd ), start ] ) | ||
); | ||
|
||
const parsed = Object.assign( | ||
newNode( text.slice( offsetStart, offsetEnd ), nextRange ), | ||
children.length && { children } | ||
); | ||
|
||
return [ [ ...prev, ...preText, parsed ], text.slice( offsetEnd ), end ]; | ||
}; | ||
|
||
export const parseBlock = block => | ||
block.ranges | ||
? joinResults( | ||
block.ranges | ||
.map( o => ( { ...o, children: [] } ) ) | ||
.sort( rangeSort ) | ||
.reduce( addRange, [] ) | ||
.reduce( parse, [ [], block.text, 0 ] ) ) | ||
: [ newNode( block ) ]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
import React from 'react'; | ||
import { | ||
flip, | ||
head, | ||
propOr, | ||
tap | ||
} from 'ramda'; | ||
|
||
import CommentBlock from './comment-block'; | ||
import LinkBlock from './link-block'; | ||
import PostBlock from './post-block'; | ||
import SiteBlock from './site-block'; | ||
import TypedBlock from './typed-block'; | ||
import UserBlock from './user-block'; | ||
|
||
const blockMapping = flip( propOr( TypedBlock ) )( { | ||
comment: CommentBlock, | ||
link: LinkBlock, | ||
post: PostBlock, | ||
site: SiteBlock, | ||
user: UserBlock | ||
} ); | ||
|
||
export const addKey = ( element, key ) => | ||
React.cloneElement( element, { key } ); | ||
|
||
const reduceTree = ( elements, node ) => { | ||
if ( 'string' === typeof node ) { | ||
return [ ...elements, <span>{ node }</span> ]; | ||
} | ||
|
||
const Element = blockMapping( node.type ); | ||
|
||
if ( ! node.children ) { | ||
return [ | ||
...elements, | ||
<Element { ...node } /> | ||
]; | ||
} | ||
|
||
const firstChild = head( node.children ); | ||
if ( 1 === node.children.length && 'string' === typeof firstChild ) { | ||
return [ | ||
...elements, | ||
<Element { ...node }>{ firstChild }</Element> | ||
]; | ||
} | ||
|
||
const children = node | ||
.children | ||
.reduce( reduceTree, [] ); | ||
|
||
return [ | ||
...elements, | ||
<Element { ...node }>{ children.map( addKey ) }</Element> | ||
]; | ||
}; | ||
|
||
export const parseBlockTree = tree => { | ||
return ( | ||
<span> | ||
{ tree.reduce( reduceTree, [] ).map( addKey ) } | ||
</span> | ||
); | ||
}; | ||
|
||
export default parseBlockTree; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import React from 'react'; | ||
|
||
require( './comment-block.scss' ); | ||
|
||
export const CommentBlock = ( { children, CommentId, siteId } ) => | ||
<span className="text-range comment">{ children }</span>; | ||
|
||
export default CommentBlock; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.text-range.comment { | ||
font-style: italic; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
import React from 'react'; | ||
|
||
export const LinkBlock = ( { url, children } ) => | ||
<a href={ url }>{ children }</a>; | ||
|
||
export default LinkBlock; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import React from 'react'; | ||
|
||
require( './post-block.scss' ); | ||
|
||
export const PostBlock = ( { children, postId, siteId } ) => | ||
<span className="text-range post">{ children }</span>; | ||
|
||
export default PostBlock; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.text-range.post { | ||
font-style: italic; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import React from 'react'; | ||
|
||
require( './site-block.scss' ); | ||
|
||
export const SiteBlock = ( { children, siteId } ) => | ||
<span className="text-range site">{ children }</span>; | ||
|
||
export default SiteBlock; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.text-range.site { | ||
font-weight: bold; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import React from 'react'; | ||
|
||
require( './typed-block.scss' ); | ||
|
||
export const TypedBlock = ( { children, type } ) => | ||
<span className={ `text-range typed type-${ type }` }>{ children }</span>; | ||
|
||
export default TypedBlock; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
@import "~styles/color.scss"; | ||
|
||
.text-range.typed { | ||
&.type-match { | ||
color: $blue-medium; | ||
font-weight: bold; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import React from 'react'; | ||
|
||
require( './user-block.scss' ); | ||
|
||
export const UserBlock = ( { children, id } ) => | ||
<span className="text-range user">{ children }</span>; | ||
|
||
export default UserBlock; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
.text-range.user { | ||
font-weight: bold; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -32,6 +32,5 @@ | |
|
||
.subject:not(.excerpt) { | ||
color: $gray-dark; | ||
font-weight: bold; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters