tag management works now

This commit is contained in:
or-else
2018-03-04 18:11:56 -08:00
parent dac21cf807
commit b7a4efa6b6
2 changed files with 162 additions and 35 deletions
+1
View File
@@ -1382,6 +1382,7 @@ ul.tabbar li.active > a:after {
padding: 0 0.15rem 0 0.15rem; padding: 0 0.15rem 0 0.15rem;
margin-left: 0.1rem; margin-left: 0.1rem;
margin-right: 0.1rem; margin-right: 0.1rem;
margin-bottom: 0.1rem;
border-radius: 0.15rem; border-radius: 0.15rem;
display: inline-block; display: inline-block;
align-self: flex-start; align-self: flex-start;
+161 -35
View File
@@ -286,6 +286,23 @@
return undefined; return undefined;
} }
// Deep-shallow compare two arrays.
function arrayEqual(a, b) {
// Compare lengths first.
if (a.length != b.length) {
return false;
}
// Order of elements is ignored.
a.sort();
b.sort();
for (var i = 0, l = a.length; i < l; i++) {
if (a[i] !== b[i]) {
return false;
}
}
return true;
}
// Convert a number of bytes to human-readable format. // Convert a number of bytes to human-readable format.
function bytesToHumanSize(bytes) { function bytesToHumanSize(bytes) {
if (!bytes || bytes == 0) { if (!bytes || bytes == 0) {
@@ -795,9 +812,12 @@
componentWillReceiveProps: function(newProps) { componentWillReceiveProps: function(newProps) {
this.setState({ this.setState({
sortedChips: this.sortChips(newProps.chips, newProps.required), sortedChips: this.sortChips(newProps.chips, newProps.required),
chipIndex: this.indexChips(newProps.chips), chipIndex: this.indexChips(newProps.chips)
input: ''
}); });
if (newProps.chips.length > this.props.chips.length) {
// Chip added: clear input.
this.setState({input: ''});
}
}, },
// Map chip index to user name // Map chip index to user name
@@ -1296,6 +1316,7 @@
<EditAccountView <EditAccountView
login={this.props.login} login={this.props.login}
onSubmit={this.props.onUpdateAccount} onSubmit={this.props.onUpdateAccount}
onUpdateTags={this.props.onUpdateAccountTags}
onCancel={this.props.onCancel} onCancel={this.props.onCancel}
onError={this.props.onError} /> : onError={this.props.onError} /> :
@@ -1364,7 +1385,7 @@
avatar: null, avatar: null,
login: undefined, login: undefined,
password: undefined, password: undefined,
tagInput: '', previousOnTags: undefined,
tags: [] tags: []
}; };
}, },
@@ -1377,12 +1398,20 @@
address: Tinode.getCurrentUserID(), address: Tinode.getCurrentUserID(),
auth: defacs.auth, auth: defacs.auth,
anon: defacs.anon, anon: defacs.anon,
tags: me.tags() tags: me.tags(),
previousOnTags: me.onTagsUpdated,
showTagManager: false
}); });
me.onTagsUpdated = this.tnNewTags;
}, },
componentWillUnmount: function() { componentWillUnmount: function() {
// Not needed? var me = Tinode.getMeTopic();
me.onTagsUpdated = this.state.previousOnTags;
},
tnNewTags: function(tags) {
this.setState({tags: tags});
}, },
handleFullNameUpdate: function(fn) { handleFullNameUpdate: function(fn) {
@@ -1398,34 +1427,30 @@
this.props.onSubmit(null, vcard(this.state.fullName, img)); this.props.onSubmit(null, vcard(this.state.fullName, img));
}, },
handleTagInput: function(text) { handleShowTagManager: function() {
// Check if user entered ',', ' ' or ';' this.setState({showTagManager: true});
if (text.length > 0) { },
var last = text[text.length-1];
if (last == ',' || last == ' ' || last == ';') { handleHideTagManager: function() {
this.handleAddTag(text.substr(0, text.length-1)); this.setState({showTagManager: false});
} },
handleTagsUpdated: function(tags) {
this.setState({showTagManager: false});
// Check if tags have actually changed.
if (arrayEqual(this.state.tags.slice(0), tags.slice(0))) {
return;
} }
}, this.props.onUpdateTags(tags);
handleAddTag: function(tag) {
var tags = this.state.tags.slice(0);
tags.push(tag);
this.setState({tags: tags});
},
handleRemoveTag: function(tag, index) {
var tags = this.state.tags.slice(0);
tags.splice(index, 1);
this.setState({tags: tags});
}, },
render: function() { render: function() {
var tags = []; var tags = [];
var instance = this;
this.state.tags.map(function(tag) { this.state.tags.map(function(tag) {
tags.push({user: tag}); tags.push(<span className="badge" key={tags.length}>{tag}</span>);
}); });
if (tags.length == 0) { if (tags.length == 0) {
tags = <i>none</i>; tags = <i>No tags defined. Add some.</i>;
} }
return ( return (
<div id="edit-account" className="panel-form"> <div id="edit-account" className="panel-form">
@@ -1468,22 +1493,114 @@
</div> </div>
</div> </div>
<div className="hr" /> <div className="hr" />
<div className="panel-form-column"> {this.state.showTagManager ?
<div><label className="small">Tags (user discovery):</label></div> <TagManager
<ChipInput tags={this.state.tags}
chips={tags} onSubmit={this.handleTagsUpdated}
avatarDisabled={true} onCancel={this.handleHideTagManager} />
prompt="Add tags" :
onEnter={this.handleAddTag} <div className="panel-form-column">
onChipRemoved={this.handleRemoveTag} <div><label className="small">Tags (user discovery):</label></div>
filterFunc={this.handleTagInput} /> <a href="#" className="flat-button" onClick={this.handleShowTagManager}>
</div> <i className="material-icons">edit</i> Manage tags
</a>
<span>{tags}</span>
</div>
}
</div> </div>
); );
} }
}); });
/* END EditAccount */ /* END EditAccount */
/* BEGIN TagManager: edit topic or user tags */
var TagManager = React.createClass({
getInitialState: function() {
return {
tags: this.wrapTags(this.props.tags),
tagInput: '',
noTagsMessage: 'Add some tags'
};
},
wrapTags: function(tags) {
var wrapped = [];
tags.map(function(tag) {
wrapped.push({user: tag});
});
return wrapped;
},
unwrapTags: function(tags) {
var unwrapped = [];
tags.map(function(tag) {
unwrapped.push(tag.user);
});
return unwrapped;
},
handleTagInput: function(text) {
this.setState({tagInput: text});
// Check if user entered ',', ' ' or ';'
if (text.length > 0) {
var last = text[text.length-1];
if (last == ',' || last == ' ' || last == ';') {
this.handleAddTag(text.substr(0, text.length-1));
}
}
},
handleAddTag: function(tag) {
tag = tag.trim();
if (tag.length > 0) {
var tags = this.state.tags.slice(0);
tags.push({user: tag});
this.setState({tags: tags, tagInput: ''});
}
},
handleRemoveTag: function(tag, index) {
var tags = this.state.tags.slice(0);
tags.splice(index, 1);
this.setState({tags: tags});
},
handleSubmit: function() {
var tags = this.unwrapTags(this.state.tags);
var inp = this.state.tagInput.trim();
if (inp.length > 0) {
tags.push(inp);
}
this.props.onSubmit(tags);
},
handleCancel: function() {
this.props.onCancel();
},
render: function() {
return (
<div id="tag-manager">
<div className="panel-form-row">
<label className="small">Tags (user discovery)</label>
</div>
<ChipInput
chips={this.state.tags}
avatarDisabled={true}
prompt={this.state.noTagsMessage}
onEnter={this.handleAddTag}
onChipRemoved={this.handleRemoveTag}
filterFunc={this.handleTagInput} />
<div id="tag-manager-buttons" className="panel-form-row">
<button className="blue" onClick={this.handleSubmit}>OK</button>
<button className="white" onClick={this.handleCancel}>Cancel</button>
</div>
</div>
);
}
});
/* END TagManager */
/* BEGIN Contact list (list of topics) */ /* BEGIN Contact list (list of topics) */
/* A single topic */; /* A single topic */;
var Contact = React.createClass({ var Contact = React.createClass({
@@ -3607,6 +3724,14 @@
}); });
} }
}, },
handleUpdateAccountTagsRequest: function(tags) {
var instance = this;
Tinode.getMeTopic().setMeta({tags: tags}).catch(function(err) {
instance.handleError(err.message, "err");
});
},
// User chose Settings menu item. // User chose Settings menu item.
handleSettings: function() { handleSettings: function() {
this.setState({sidePanelSelected: this.state.myUserId ? 'edit-account' : 'settings'}); this.setState({sidePanelSelected: this.state.myUserId ? 'edit-account' : 'settings'});
@@ -3825,6 +3950,7 @@
onLoginRequest={this.handleLoginRequest} onLoginRequest={this.handleLoginRequest}
onCreateAccount={this.handleNewAccountRequest} onCreateAccount={this.handleNewAccountRequest}
onUpdateAccount={this.handleUpdateAccountRequest} onUpdateAccount={this.handleUpdateAccountRequest}
onUpdateAccountTags={this.handleUpdateAccountTagsRequest}
onTopicSelected={this.handleTopicSelected} onTopicSelected={this.handleTopicSelected}
onCreateTopic={this.handleNewTopicRequest} onCreateTopic={this.handleNewTopicRequest}
onNewTopic={this.handleNewTopic} onNewTopic={this.handleNewTopic}