Created
March 10, 2019 21:06
Revisions
-
thecere created this gist
Mar 10, 2019 .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 charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,172 @@ // 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'}} /> ) } }