Julian Steinwachs
9 years ago
6 changed files with 746 additions and 1757 deletions
Binary file not shown.
@ -0,0 +1,216 @@ |
|||||||
|
var React = require('react'); |
||||||
|
var ContentEditable = require('react-wysiwyg'); |
||||||
|
var PostContentHelper = require('../common/PostContentHelper.js'); |
||||||
|
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js'); |
||||||
|
|
||||||
|
|
||||||
|
var ReactBootstrap = require('react-bootstrap') |
||||||
|
, Button = ReactBootstrap.Button |
||||||
|
, DropdownButton = ReactBootstrap.DropdownButton |
||||||
|
, MenuItem = ReactBootstrap.MenuItem |
||||||
|
, ButtonGroup = ReactBootstrap.ButtonGroup |
||||||
|
, OverlayTrigger = ReactBootstrap.OverlayTrigger |
||||||
|
, Popover = ReactBootstrap.Popover |
||||||
|
, Glyphicon = ReactBootstrap.Glyphicon |
||||||
|
, Grid = ReactBootstrap.Grid |
||||||
|
, Col = ReactBootstrap.Col |
||||||
|
, Row = ReactBootstrap.Row |
||||||
|
|
||||||
|
var escape = document.createElement('textarea') |
||||||
|
|
||||||
|
function escapeHTML(html) { |
||||||
|
escape.textContent = html; |
||||||
|
return escape.innerHTML; |
||||||
|
} |
||||||
|
|
||||||
|
module.exports = PostComposer = React.createClass({ |
||||||
|
mixins:[SafeStateChangeMixin], |
||||||
|
getInitialState: function(){ |
||||||
|
var editing = false |
||||||
|
var defaultValue = '' |
||||||
|
|
||||||
|
return { |
||||||
|
html: defaultValue, |
||||||
|
editing: true, |
||||||
|
placeholder: true, |
||||||
|
maxLength: 140, |
||||||
|
totalLength: defaultValue.length, |
||||||
|
queryMention: false, |
||||||
|
text: defaultValue |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
componentDidMount: function () { |
||||||
|
// Gives the window a callback to call before the next repaint.
|
||||||
|
window.requestAnimationFrame(this.checkCursor) |
||||||
|
}, |
||||||
|
|
||||||
|
checkCursor: function (timestamp) { |
||||||
|
var self = this |
||||||
|
var selection = window.getSelection() |
||||||
|
|
||||||
|
|
||||||
|
if (this.state.editing && selection.focusNode) { |
||||||
|
|
||||||
|
var node = selection |
||||||
|
.getRangeAt(0) |
||||||
|
.commonAncestorContainer |
||||||
|
.parentNode |
||||||
|
|
||||||
|
if (node.className === 'show-dropdown') { |
||||||
|
// you could use the node to determine its position,
|
||||||
|
// and show the dropdown inline, too.
|
||||||
|
this.setStateSafe({ queryMention : node.textContent }) |
||||||
|
} else if (this.state.queryMention) { |
||||||
|
this.setStateSafe({ queryMention: false }) |
||||||
|
} |
||||||
|
|
||||||
|
} else if (this.state.queryMention) { |
||||||
|
this.setStateSafe({ queryMention: false }) |
||||||
|
} |
||||||
|
|
||||||
|
window.requestAnimationFrame(self.checkCursor) |
||||||
|
}, |
||||||
|
|
||||||
|
render: function(){ |
||||||
|
|
||||||
|
var isValid = (this.state.maxLength >= this.state.totalLength) |
||||||
|
&& (this.state.totalLength > 0) |
||||||
|
|
||||||
|
return ( |
||||||
|
<div> |
||||||
|
<div>{this.state.error}</div> |
||||||
|
<ContentEditable |
||||||
|
ref='editable' |
||||||
|
tagName='div' |
||||||
|
html={this.state.html} |
||||||
|
placeholder={this.state.placeholder} |
||||||
|
placeholderText='write' |
||||||
|
onKeyPress={this.onKeyPress} |
||||||
|
preventStyling |
||||||
|
noLinebreaks |
||||||
|
onChange={this.onChange} |
||||||
|
editing={this.state.editing} |
||||||
|
style={{"outline": "none"}} |
||||||
|
/> |
||||||
|
<Row> |
||||||
|
<Col xs={9} md={9}> |
||||||
|
</Col> |
||||||
|
<Col xs={1} md={1}> |
||||||
|
<Button disabled id="content-length"> |
||||||
|
{this.state.maxLength - this.state.totalLength} |
||||||
|
</Button> |
||||||
|
</Col> |
||||||
|
<Col xs={2} md={2}> |
||||||
|
<Button disabled={!isValid} onClick={this.handleSubmit}> |
||||||
|
Twist |
||||||
|
</Button> |
||||||
|
</Col> |
||||||
|
</Row> |
||||||
|
</div> |
||||||
|
); |
||||||
|
/*<div> |
||||||
|
Show autocomplete? {this.state.queryMention ? 'Yes ' + this.state.queryMention : 'No'} |
||||||
|
</div>*/ |
||||||
|
}, |
||||||
|
|
||||||
|
handleSubmit: function(){ |
||||||
|
this.props.onSubmit(this.state.text); |
||||||
|
}, |
||||||
|
|
||||||
|
autofocus: function () { |
||||||
|
if (this.state.editing) { |
||||||
|
this.refs.editable.autofocus() |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
onChange: function(text, setPlaceholder) { |
||||||
|
// in order to render the updated html,
|
||||||
|
// you need to pass it as a prop to contentEditable.
|
||||||
|
// This gives you increased flexibility.
|
||||||
|
if (setPlaceholder) { |
||||||
|
this.setState({ |
||||||
|
placeholder: true, |
||||||
|
html: '', |
||||||
|
totalLength: 0, |
||||||
|
text: '' |
||||||
|
}) |
||||||
|
} else { |
||||||
|
|
||||||
|
var copy = text.slice(0, this.state.maxLength) |
||||||
|
|
||||||
|
var parsedContent = PostContentHelper.parseContent(copy); |
||||||
|
|
||||||
|
//console.log(copy,parsedContent);
|
||||||
|
|
||||||
|
var output = ""; |
||||||
|
|
||||||
|
parsedContent.map(function(item,index){ |
||||||
|
//console.log(item.raw)
|
||||||
|
switch(item.type) { |
||||||
|
case "mention": |
||||||
|
output+=('<a class="text-muted" href="#/profile/"'+item.raw.substr(1)+'">'+item.raw+'</a>'); |
||||||
|
break; |
||||||
|
case "hashtag": |
||||||
|
output+=('<a class="text-muted" href="#/hashtag/"'+item.raw.substr(1)+'">'+item.raw+'</a>'); |
||||||
|
break; |
||||||
|
case "url": |
||||||
|
output+=('<a class="text-primary" href="'+item.raw+'" target="_blank">'+item.raw+'</a>'); |
||||||
|
break; |
||||||
|
case "email": |
||||||
|
output+=('<span class="text-primary">'+item.raw+'</span>'); |
||||||
|
break; |
||||||
|
default: |
||||||
|
output+=(item.raw); |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
var rules = [ |
||||||
|
{regex: /\[([^\[]+)\]\(([^\)]+)\)/g, |
||||||
|
replacement: '<span class="ghost">[</span><a>$1</a><span class="ghost">]($2)</span>'}, // hyperlink
|
||||||
|
{regex: /(\s?)(\*)(.*?)(\*)(\s?)/g, |
||||||
|
replacement: '$1<span class="ghost">*</span><b>$3</b><span class="ghost">*</span>$5'}, // emphasis
|
||||||
|
{regex: /(\s?)(\~)(.*?)(\~)(\s?)/g, |
||||||
|
replacement: '$1<span class="ghost">~</span><i>$3</i><span class="ghost">~</span>$5'}, // emphasis
|
||||||
|
{regex: /(\s?)(\-)(.*?)(\-)(\s?)/g, |
||||||
|
replacement: '$1<span class="ghost">-</span><del>$3</del><span class="ghost">-</span>$5'}, // emphasis
|
||||||
|
{regex: /(\s?)(\_)(.*?)(\_)(\s?)/g, |
||||||
|
replacement: '$1<span class="ghost">_</span><u>$3</u><span class="ghost">_</span>$5'}, // emphasis
|
||||||
|
] |
||||||
|
|
||||||
|
rules.forEach(function (rule) { |
||||||
|
output = output.replace(rule.regex, rule.replacement); |
||||||
|
}); |
||||||
|
|
||||||
|
console.log(text.slice(0, this.state.maxLength),output) |
||||||
|
|
||||||
|
// text overflow
|
||||||
|
if (text.length > this.state.maxLength) { |
||||||
|
var overflow = '<span style="text-decoration: line-through;">' + |
||||||
|
text.slice(this.state.maxLength) + |
||||||
|
'</span>' |
||||||
|
output = output + overflow |
||||||
|
} |
||||||
|
|
||||||
|
this.setState({ |
||||||
|
placeholder: false, |
||||||
|
html: output, |
||||||
|
totalLength: text.length, |
||||||
|
text: copy |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
}, |
||||||
|
|
||||||
|
enableEditing: function(){ |
||||||
|
var editing = !this.state.editing |
||||||
|
// set your contenteditable field into editing mode.
|
||||||
|
this.setState({ editing: editing }); |
||||||
|
if (editing) { |
||||||
|
this.refs.editable.autofocus() |
||||||
|
this.refs.editable.setCursorToEnd() |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
}); |
@ -1,4 +1,4 @@ |
|||||||
var PostContentHelper = require("../build-buffer/common/PostContentHelper.js"); |
var PostContentHelper = require("../build-buffer/common/PostContentHelper.js"); |
||||||
|
|
||||||
|
|
||||||
console.log(PostContentHelper.parseContent("asd http:// <u")); |
console.log(PostContentHelper.parseContent("https://github.com/lmatteis/peer-tweet")); |
Loading…
Reference in new issue