Browse Source

dont user broken wysiwyg post editor

master
Julian Steinwachs 9 years ago
parent
commit
e8a2ad40b8
  1. 2105
      build/app-bundle.js
  2. 12
      docker/settings.json
  3. BIN
      fonts/passwordsP2P.pdf
  4. 156
      jsx/common/PostComposer.js
  5. 216
      jsx/common/PostComposer_WYSIWYG_Broken.js
  6. 2
      tests/PostContentTest.js

2105
build/app-bundle.js

File diff suppressed because it is too large Load Diff

12
docker/settings.json

@ -1,14 +1,16 @@
{ {
"Server": "Server":
{ {
"ssl_key_file": "insert/path/to/your/server-key-file", "ssl_key_file": "/certs/privkey.pem",
"ssl_certificate_file": "insert/path/to/your/ssl-certificate", "ssl_certificate_file": "/ecerts/cert.pem",
"enable_https": false, "ssl_chain_file": "/certs/chain.pem",
"ssl_fullchain_file": "/certs/fullchain.pem",
"enable_https": true,
"https_port": 443, "https_port": 443,
"http_port": 8080 "http_port": 0
}, },
"RPC": "RPC":
{ {
"host": "localhost", "host": "localhost",

BIN
fonts/passwordsP2P.pdf

Binary file not shown.

156
jsx/common/PostComposer.js

@ -1,5 +1,4 @@
var React = require('react'); var React = require('react');
var ContentEditable = require('react-wysiwyg');
var PostContentHelper = require('../common/PostContentHelper.js'); var PostContentHelper = require('../common/PostContentHelper.js');
var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js'); var SafeStateChangeMixin = require('../common/SafeStateChangeMixin.js');
@ -16,83 +15,31 @@ var ReactBootstrap = require('react-bootstrap')
, Col = ReactBootstrap.Col , Col = ReactBootstrap.Col
, Row = ReactBootstrap.Row , Row = ReactBootstrap.Row
var escape = document.createElement('textarea')
function escapeHTML(html) {
escape.textContent = html;
return escape.innerHTML;
}
module.exports = PostComposer = React.createClass({ module.exports = PostComposer = React.createClass({
mixins:[SafeStateChangeMixin], mixins:[SafeStateChangeMixin],
getInitialState: function(){ getInitialState: function(){
var editing = false
var defaultValue = '' var defaultValue = ''
return { return {
html: defaultValue,
editing: true,
placeholder: true,
maxLength: 140, maxLength: 140,
totalLength: defaultValue.length, totalLength: defaultValue.length,
queryMention: false,
text: defaultValue 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(){ render: function(){
var isValid = (this.state.maxLength >= this.state.totalLength) var isValid = (this.state.maxLength >= this.state.totalLength)
&& (this.state.totalLength > 0) && (this.state.totalLength > 0)
return ( return (
<div> <div className="form-group">
<div>{this.state.error}</div> <textarea
<ContentEditable className="form-control"
ref='editable' placeholder = "write something..."
tagName='div' onChange={this.handleChange}
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> <Row>
<Col xs={9} md={9}> <Col xs={9} md={9}>
@ -119,98 +66,15 @@ module.exports = PostComposer = React.createClass({
this.props.onSubmit(this.state.text); this.props.onSubmit(this.state.text);
}, },
autofocus: function () { handleChange: function(e) {
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 = ""; var newText = e.target.value;
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({ this.setState({
placeholder: false, totalLength: newText.length,
html: output, text: newText
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()
}
}
}); });

216
jsx/common/PostComposer_WYSIWYG_Broken.js

@ -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()
}
}
});

2
tests/PostContentTest.js

@ -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…
Cancel
Save