Skip to content

Instantly share code, notes, and snippets.

@thecere
Created March 10, 2019 21:06
Show Gist options
  • Save thecere/02a9c047f089b916b41e62905b47ae62 to your computer and use it in GitHub Desktop.
Save thecere/02a9c047f089b916b41e62905b47ae62 to your computer and use it in GitHub Desktop.
// derived from https://github.com/scniro/react-codemirror2/blob/master/src/index.tsx
import React from 'react'
const SERVER_RENDERED = process.env.UIX_ENV == 'express'
let CodeMirror
if (!SERVER_RENDERED) {
CodeMirror = require('codemirror')
}
export class DiffView extends React.Component {
constructor(props) {
super(props)
this.ref = null
this.mergeview = null
this.leftEditor = null
this.editor = null
this.rightEditor = null
this.mounted = false
}
componentWillMount() {
if (SERVER_RENDERED) return
if (this.props.editorWillMount) {
this.props.editorWillMount()
}
}
createMergeView(options) {
// this kills the old ones
this.ref.innerHTML = ''
// ok, we play some games with text initializiation
// if we initialize with the real text contents, we get glitches in the "blue diff indicators"
// so we init with empty strings and use a additional setValue call on the subeditors later
let {value, origLeft, origRight, ...nonTextOptions} = options
if (origLeft !== undefined) {
nonTextOptions.origLeft = ''
}
if (origRight !== undefined) {
nonTextOptions.origRight = ''
}
this.mergeview = CodeMirror.MergeView(this.ref, {...nonTextOptions, value: ''})
// optional left or right
this.leftEditor = this.mergeview.leftOriginal()
this.rightEditor = this.mergeview.rightOriginal()
// center editor (can be writable)
this.editor = this.mergeview.editor()
this.editor.on('change', (cm, data) => {
if (!this.mounted) {
return
}
if (this.props.onChange) {
this.props.onChange(this.editor, data, this.editor.getValue())
}
})
this.hackCSS(this.props.height)
// ok, apply the init hack
if (value) {
this.editor.setValue(value)
}
if (this.leftEditor && origLeft) {
this.leftEditor.setValue(origLeft)
}
if (this.rightEditor && origRight) {
this.rightEditor.setValue(origRight)
}
if (this.props.editorDidMount) {
this.props.editorDidMount(this.editor, this.leftEditor, this.rightEditor)
}
this.mergeview.setShowDifferences(options.highlightDifferences)
}
componentDidMount() {
if (SERVER_RENDERED) return
this.createMergeView(this.props.options)
this.mounted = true
}
componentWillReceiveProps(nextProps) {
if (SERVER_RENDERED) return
if (this.props.height != nextProps.height || this.props.width != nextProps.width) {
this.hackCSS(nextProps.height)
}
let prevOpts = this.props.options
let nextOpts = nextProps.options
let resetOptions = ['collapseIdentical', 'lineWrapping', 'connect', 'ignoreWhitespace']
let reset = resetOptions.some(name => prevOpts[name] !== nextOpts[name])
if (reset) {
// full reset
this.createMergeView(nextOpts)
} else {
if (prevOpts.highlightDifferences != nextOpts.highlightDifferences) {
this.mergeview.setShowDifferences(nextOpts.highlightDifferences)
}
// XXX: handle all option changes with a reset?
if (prevOpts.origLeft != nextOpts.origLeft) {
this.leftEditor.setValue(nextOpts.origLeft)
//~ this.createMergeView(nextOpts)
}
if (prevOpts.value != nextOpts.value) {
this.editor.setValue(nextOpts.value)
//~ this.createMergeView(nextProps.options)
}
//~ let self = this.mergeview
//~ this.editor.operation(function() {
//~ merge.collapseIdenticalStretches(self, true);
//~ });
//~ this.mergeview.setOption('collapseIdentical', true)
}
}
componentWillUnmount() {
if (SERVER_RENDERED) return
this.mergeview = null
this.leftEditor = null
this.rightEditor = null
}
shouldComponentUpdate(nextProps, nextState) {
if (SERVER_RENDERED) return false
return true
}
hackCSS = height => {
if (!this.ref || SERVER_RENDERED) return
for (let e of this.ref.querySelectorAll('.codemirror-merge .CodeMirror')) {
e.style.height = `${height}px`
}
// http://dwwebs.com/notes-common/codemirror/doc/manual.html#refresh
for (let e of [this.editor, this.leftEditor, this.rightEditor]) {
if (e) {
e.refresh()
}
}
}
render() {
if (SERVER_RENDERED) return null
let {width, height} = this.props
let className = this.props.className
? `codemirror-merge ${this.props.className}`
: 'codemirror-merge'
return (
<div
className={className}
ref={self => (this.ref = self)}
style={{width, height, overflow: 'hidden'}}
/>
)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment