more work on #hash navigation
This commit is contained in:
+63
-31
@@ -262,7 +262,7 @@
|
|||||||
// path and arguments.
|
// path and arguments.
|
||||||
function parseUrlHash(hash) {
|
function parseUrlHash(hash) {
|
||||||
var parser = document.createElement('a');
|
var parser = document.createElement('a');
|
||||||
parser.href = '/' + location.hash.substr(1);
|
parser.href = '/' + hash.substr(1);
|
||||||
var params = {};
|
var params = {};
|
||||||
parser.search.substr(1).split("&").forEach(function(part) {
|
parser.search.substr(1).split("&").forEach(function(part) {
|
||||||
var item = part.split("=");
|
var item = part.split("=");
|
||||||
@@ -270,11 +270,11 @@
|
|||||||
params[decodeURIComponent(item[0])] = decodeURIComponent(item[1]);
|
params[decodeURIComponent(item[0])] = decodeURIComponent(item[1]);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return {path: parser.pathname, params: params};
|
return {path: parser.pathname.substr(1).split("/"), params: params};
|
||||||
}
|
}
|
||||||
|
|
||||||
function composeUrlHash(path, params) {
|
function composeUrlHash(path, params) {
|
||||||
var url = path;
|
var url = path.join("/");
|
||||||
var args = [];
|
var args = [];
|
||||||
for (var key in params) {
|
for (var key in params) {
|
||||||
if (params.hasOwnProperty(key)) {
|
if (params.hasOwnProperty(key)) {
|
||||||
@@ -284,7 +284,24 @@
|
|||||||
if (args.length > 0) {
|
if (args.length > 0) {
|
||||||
url += "?" + args.join("&");
|
url += "?" + args.join("&");
|
||||||
}
|
}
|
||||||
return url.
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
function addParamToHash(hash, key, value) {
|
||||||
|
var hash = parseUrlHash(hash);
|
||||||
|
if (!hash.params) {
|
||||||
|
hash.params = {};
|
||||||
|
}
|
||||||
|
hash.params[key] = value;
|
||||||
|
return composeUrlHash(hash.path, hash.params);
|
||||||
|
}
|
||||||
|
|
||||||
|
function removeParamFromHash(hash, key) {
|
||||||
|
var hash = parseUrlHash(hash);
|
||||||
|
if (hash.params) {
|
||||||
|
delete hash.params[key];
|
||||||
|
}
|
||||||
|
return composeUrlHash(hash.path, hash.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detect server address from the URL
|
// Detect server address from the URL
|
||||||
@@ -543,7 +560,7 @@
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<a href="#" onClick={this.props.onCancel}><i className="material-icons">close</i></a>
|
<a href="javascript:;" onClick={this.props.onCancel}><i className="material-icons">close</i></a>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1005,7 +1022,7 @@
|
|||||||
}
|
}
|
||||||
<span>{title}</span>
|
<span>{title}</span>
|
||||||
{this.props.onCancel && !this.props.required ?
|
{this.props.onCancel && !this.props.required ?
|
||||||
<a href="#" onClick={this.handleCancel} >×</a>
|
<a href="javascript:;" onClick={this.handleCancel} >×</a>
|
||||||
: <span className="spacer" />}
|
: <span className="spacer" />}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
@@ -1311,9 +1328,9 @@
|
|||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<a href="#" onClick={this.props.onSignUp}><i className="material-icons">person_add</i></a>
|
<a href="javascript:;" onClick={this.props.onSignUp}><i className="material-icons">person_add</i></a>
|
||||||
|
|
||||||
<a href="#" onClick={this.props.onSettings}><i className="material-icons">settings</i></a>
|
<a href="javascript:;" onClick={this.props.onSettings}><i className="material-icons">settings</i></a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1323,9 +1340,9 @@
|
|||||||
render: function() {
|
render: function() {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<a href="#" onClick={this.props.onNewTopic}><i className="material-icons">chat</i></a>
|
<a href="javascript:;" onClick={this.props.onNewTopic}><i className="material-icons">chat</i></a>
|
||||||
|
|
||||||
<a href="#" onClick={this.props.onSettings}><i className="material-icons">settings</i></a>
|
<a href="javascript:;" onClick={this.props.onSettings}><i className="material-icons">settings</i></a>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1590,7 +1607,7 @@
|
|||||||
onSubmit={this.handleTagsUpdated} />
|
onSubmit={this.handleTagsUpdated} />
|
||||||
<div className="hr" />
|
<div className="hr" />
|
||||||
<div className="panel-form-column">
|
<div className="panel-form-column">
|
||||||
<a href="#" className="red flat-button" onClick={this.props.onLogout}>
|
<a href="javascript:;" className="red flat-button" onClick={this.props.onLogout}>
|
||||||
<i className="material-icons">exit_to_app</i> Logout
|
<i className="material-icons">exit_to_app</i> Logout
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -1705,7 +1722,7 @@
|
|||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div>
|
<div>
|
||||||
<a href="#" className="flat-button" onClick={this.handleShowTagManager}>
|
<a href="javascript:;" className="flat-button" onClick={this.handleShowTagManager}>
|
||||||
<i className="material-icons">edit</i> Manage tags
|
<i className="material-icons">edit</i> Manage tags
|
||||||
</a>
|
</a>
|
||||||
<span>{tags}</span>
|
<span>{tags}</span>
|
||||||
@@ -1777,7 +1794,7 @@
|
|||||||
</div>
|
</div>
|
||||||
{this.props.showContextMenu ?
|
{this.props.showContextMenu ?
|
||||||
<span className="menuTrigger">
|
<span className="menuTrigger">
|
||||||
<a href="#" onClick={this.handleContextClick}>
|
<a href="javascript:;" onClick={this.handleContextClick}>
|
||||||
<i className="material-icons">expand_more</i>
|
<i className="material-icons">expand_more</i>
|
||||||
</a>
|
</a>
|
||||||
</span> : null}
|
</span> : null}
|
||||||
@@ -2195,13 +2212,13 @@
|
|||||||
<div className="flex-column">
|
<div className="flex-column">
|
||||||
<ul className="tabbar">
|
<ul className="tabbar">
|
||||||
<li className={this.state.tabSelected === "p2p" ? "active" : null}>
|
<li className={this.state.tabSelected === "p2p" ? "active" : null}>
|
||||||
<a href="#" data-id="p2p" onClick={this.handleTabClick}>1:1</a>
|
<a href="javascript:;" data-id="p2p" onClick={this.handleTabClick}>1:1</a>
|
||||||
</li>
|
</li>
|
||||||
<li className={this.state.tabSelected === "grp" ? "active" : null}>
|
<li className={this.state.tabSelected === "grp" ? "active" : null}>
|
||||||
<a href="#" data-id="grp" onClick={this.handleTabClick}>group</a>
|
<a href="javascript:;" data-id="grp" onClick={this.handleTabClick}>group</a>
|
||||||
</li>
|
</li>
|
||||||
<li className={this.state.tabSelected === "byId" ? "active" : null}>
|
<li className={this.state.tabSelected === "byId" ? "active" : null}>
|
||||||
<a href="#" data-id="byId" onClick={this.handleTabClick}>by id</a>
|
<a href="javascript:;" data-id="byId" onClick={this.handleTabClick}>by id</a>
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
{this.state.tabSelected === "grp" ?
|
{this.state.tabSelected === "grp" ?
|
||||||
@@ -2323,7 +2340,7 @@
|
|||||||
<input type="text" placeholder="List like email:alice@example.com, tel:17025550003..."
|
<input type="text" placeholder="List like email:alice@example.com, tel:17025550003..."
|
||||||
value={this.state.search} onChange={this.handleSearchChange}
|
value={this.state.search} onChange={this.handleSearchChange}
|
||||||
onKeyPress={this.handleKeyPress} required autoFocus />
|
onKeyPress={this.handleKeyPress} required autoFocus />
|
||||||
<a href="#" onClick={this.handleSearch}>
|
<a href="javascript:;" onClick={this.handleSearch}>
|
||||||
<i className="material-icons">search</i>
|
<i className="material-icons">search</i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -2728,6 +2745,7 @@
|
|||||||
this.props.onTopicTagsUpdate(this.props.topic, tags);
|
this.props.onTopicTagsUpdate(this.props.topic, tags);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
handleContextMenu: function(params) {
|
handleContextMenu: function(params) {
|
||||||
var instance = this;
|
var instance = this;
|
||||||
var topic = Tinode.getTopic(this.props.topic);
|
var topic = Tinode.getTopic(this.props.topic);
|
||||||
@@ -2900,12 +2918,12 @@
|
|||||||
</div>
|
</div>
|
||||||
<div className="panel-form-row">
|
<div className="panel-form-row">
|
||||||
{this.state.sharer ?
|
{this.state.sharer ?
|
||||||
<a href="#" className="flat-button" onClick={this.handleShowAddMembers}>
|
<a href="javascript:;" className="flat-button" onClick={this.handleShowAddMembers}>
|
||||||
<i className="material-icons">person_add</i> Add members
|
<i className="material-icons">person_add</i> Add members
|
||||||
</a>
|
</a>
|
||||||
: null}
|
: null}
|
||||||
{!this.state.owner ?
|
{!this.state.owner ?
|
||||||
<a href="#" className="red flat-button" onClick={this.handleLeave}>
|
<a href="javascript:;" className="red flat-button" onClick={this.handleLeave}>
|
||||||
<i className="material-icons">exit_to_app</i> Leave
|
<i className="material-icons">exit_to_app</i> Leave
|
||||||
</a>
|
</a>
|
||||||
: null}
|
: null}
|
||||||
@@ -2924,7 +2942,7 @@
|
|||||||
</div>
|
</div>
|
||||||
:
|
:
|
||||||
<div className="panel-form-row">
|
<div className="panel-form-row">
|
||||||
<a href="#" className="red flat-button" onClick={this.handleLeave}>
|
<a href="javascript:;" className="red flat-button" onClick={this.handleLeave}>
|
||||||
<i className="material-icons">exit_to_app</i> Leave
|
<i className="material-icons">exit_to_app</i> Leave
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -3024,7 +3042,7 @@
|
|||||||
timestamp={this.props.timestamp} received={this.props.received} />
|
timestamp={this.props.timestamp} received={this.props.received} />
|
||||||
</p>
|
</p>
|
||||||
<span className="menuTrigger">
|
<span className="menuTrigger">
|
||||||
<a href="#" onClick={this.handleContextClick}>
|
<a href="javascript:;" onClick={this.handleContextClick}>
|
||||||
<i className="material-icons">expand_more</i>
|
<i className="material-icons">expand_more</i>
|
||||||
</a>
|
</a>
|
||||||
</span>
|
</span>
|
||||||
@@ -3433,7 +3451,7 @@
|
|||||||
<div id="topic-view" className={this.props.hideSelf ? 'nodisplay' : null}>
|
<div id="topic-view" className={this.props.hideSelf ? 'nodisplay' : null}>
|
||||||
<div id="topic-caption-panel" className="caption-panel">
|
<div id="topic-caption-panel" className="caption-panel">
|
||||||
{this.props.displayMobile ?
|
{this.props.displayMobile ?
|
||||||
<a href="#" id="hide-message-view" onClick={this.handleBackNavigation}>
|
<a href="javascript:;" id="hide-message-view" onClick={this.handleBackNavigation}>
|
||||||
<i className="material-icons">arrow_back</i>
|
<i className="material-icons">arrow_back</i>
|
||||||
</a>
|
</a>
|
||||||
:
|
:
|
||||||
@@ -3453,7 +3471,7 @@
|
|||||||
<div id="topic-users" />
|
<div id="topic-users" />
|
||||||
}
|
}
|
||||||
<div>
|
<div>
|
||||||
<a href="#" onClick={this.handleContextClick}>
|
<a href="javascript:;" onClick={this.handleContextClick}>
|
||||||
<i className="material-icons">more_vert</i>
|
<i className="material-icons">more_vert</i>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@@ -3599,12 +3617,12 @@
|
|||||||
<div id="send-message-panel">
|
<div id="send-message-panel">
|
||||||
{this.props.disabled ?
|
{this.props.disabled ?
|
||||||
<i className="material-icons disabled">photo</i> :
|
<i className="material-icons disabled">photo</i> :
|
||||||
<a href="#" onClick={function(e) {instance.attachImage.click();}} title="Add image">
|
<a href="javascript:;" onClick={function(e) {instance.attachImage.click();}} title="Add image">
|
||||||
<i className="material-icons secondary">photo</i>
|
<i className="material-icons secondary">photo</i>
|
||||||
</a>}
|
</a>}
|
||||||
{this.props.disabled ?
|
{this.props.disabled ?
|
||||||
<i className="material-icons disabled">attach_file</i> :
|
<i className="material-icons disabled">attach_file</i> :
|
||||||
<a href="#" onClick={function(e) {instance.attachFile.click();}} title="Attach file">
|
<a href="javascript:;" onClick={function(e) {instance.attachFile.click();}} title="Attach file">
|
||||||
<i className="material-icons secondary">attach_file</i>
|
<i className="material-icons secondary">attach_file</i>
|
||||||
</a>}
|
</a>}
|
||||||
<textarea id="sendMessage" placeholder={prompt}
|
<textarea id="sendMessage" placeholder={prompt}
|
||||||
@@ -3613,7 +3631,7 @@
|
|||||||
autoFocus />
|
autoFocus />
|
||||||
{this.props.disabled ?
|
{this.props.disabled ?
|
||||||
<i className="material-icons disabled">send</i> :
|
<i className="material-icons disabled">send</i> :
|
||||||
<a href="#" onClick={this.handleSend} title="Send"><i className="material-icons">send</i></a>}
|
<a href="javascript:;" onClick={this.handleSend} title="Send"><i className="material-icons">send</i></a>}
|
||||||
<input type="file" ref={function(ref) {instance.attachFile = ref;}}
|
<input type="file" ref={function(ref) {instance.attachFile = ref;}}
|
||||||
onChange={this.handleAttachFile} style={{display: 'none'}} />
|
onChange={this.handleAttachFile} style={{display: 'none'}} />
|
||||||
<input type="file" ref={function(ref) {instance.attachImage = ref;}} accept="image/*"
|
<input type="file" ref={function(ref) {instance.attachImage = ref;}} accept="image/*"
|
||||||
@@ -3676,10 +3694,10 @@
|
|||||||
<div id="image-preview" ref={function(ref) {instance.container = ref;}}
|
<div id="image-preview" ref={function(ref) {instance.container = ref;}}
|
||||||
onClick={this.props.onClose}>
|
onClick={this.props.onClose}>
|
||||||
<div id="image-preview-caption-panel">
|
<div id="image-preview-caption-panel">
|
||||||
<a href="#" download={this.props.content.filename}>
|
<a href="javascript:;" download={this.props.content.filename}>
|
||||||
<i className="material-icons">file_download</i> download
|
<i className="material-icons">file_download</i> download
|
||||||
</a>
|
</a>
|
||||||
<a href="#" onClick={this.props.onClose}><i className="material-icons gray">close</i></a>
|
<a href="javascript:;" onClick={this.props.onClose}><i className="material-icons gray">close</i></a>
|
||||||
</div>
|
</div>
|
||||||
<div id="image-preview-container">
|
<div id="image-preview-container">
|
||||||
<img src={this.props.content.url} style={size} />
|
<img src={this.props.content.url} style={size} />
|
||||||
@@ -3772,7 +3790,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
handleHashRoute: function(e) {
|
handleHashRoute: function(e) {
|
||||||
console.log("hashchange", location.hash);
|
console.log("hashchange", parseUrlHash(window.location.hash));
|
||||||
},
|
},
|
||||||
handleOnline: function(online) {
|
handleOnline: function(online) {
|
||||||
var newState = {liveConnection: online};
|
var newState = {liveConnection: online};
|
||||||
@@ -3846,6 +3864,7 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleCredentialsRequest: function(params) {
|
handleCredentialsRequest: function(params) {
|
||||||
|
window.location.hash = "validation/" + this.state.topicSelected + "/" + params.cred;
|
||||||
this.setState({
|
this.setState({
|
||||||
sidePanelSelected: 'validation',
|
sidePanelSelected: 'validation',
|
||||||
validation: params.cred
|
validation: params.cred
|
||||||
@@ -3861,6 +3880,7 @@
|
|||||||
// Logged in fine, subscribe to 'me' attaching callbacks from the contacts view.
|
// Logged in fine, subscribe to 'me' attaching callbacks from the contacts view.
|
||||||
var me = Tinode.getMeTopic();
|
var me = Tinode.getMeTopic();
|
||||||
me.onMetaDesc = instance.tnMeMetaDesc;
|
me.onMetaDesc = instance.tnMeMetaDesc;
|
||||||
|
window.location.hash = "";
|
||||||
instance.setState({
|
instance.setState({
|
||||||
connected: true,
|
connected: true,
|
||||||
sidePanelSelected: "contacts",
|
sidePanelSelected: "contacts",
|
||||||
@@ -3954,7 +3974,9 @@
|
|||||||
handleTopicSelected: function(topicName, unused_index, online, acs) {
|
handleTopicSelected: function(topicName, unused_index, online, acs) {
|
||||||
if (topicName) {
|
if (topicName) {
|
||||||
// Contact selected
|
// Contact selected
|
||||||
location.hash = topicName;
|
if (this.state.topicSelected != topicName) {
|
||||||
|
window.location.hash = this.state.sidePanelSelected + "/" + topicName;
|
||||||
|
}
|
||||||
this.setState({
|
this.setState({
|
||||||
topicSelected: topicName,
|
topicSelected: topicName,
|
||||||
mobilePanel: 'topic-view',
|
mobilePanel: 'topic-view',
|
||||||
@@ -3965,7 +3987,10 @@
|
|||||||
infoPanelShowMembers: Tinode.getTopicType(topicName) === "grp"
|
infoPanelShowMembers: Tinode.getTopicType(topicName) === "grp"
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
location.hash = null;
|
if (this.state.topicSelected) {
|
||||||
|
console.log("topic deleted");
|
||||||
|
window.history.replaceState({}, "", this.state.sidePanelSelected);
|
||||||
|
}
|
||||||
// Currently selected contact deleted
|
// Currently selected contact deleted
|
||||||
this.setState({
|
this.setState({
|
||||||
topicSelected: null,
|
topicSelected: null,
|
||||||
@@ -4014,6 +4039,7 @@
|
|||||||
},
|
},
|
||||||
// User chose a Sign Up menu item.
|
// User chose a Sign Up menu item.
|
||||||
handleNewAccount: function() {
|
handleNewAccount: function() {
|
||||||
|
window.location.hash = "register";
|
||||||
this.setState({sidePanelSelected: 'register'});
|
this.setState({sidePanelSelected: 'register'});
|
||||||
},
|
},
|
||||||
// Actual registration of a new account.
|
// Actual registration of a new account.
|
||||||
@@ -4057,6 +4083,7 @@
|
|||||||
|
|
||||||
// User chose Settings menu item.
|
// User chose Settings menu item.
|
||||||
handleSettings: function() {
|
handleSettings: function() {
|
||||||
|
window.location.hash = this.state.myUserId ? 'edit' : 'settings';
|
||||||
this.setState({sidePanelSelected: this.state.myUserId ? 'edit-account' : 'settings'});
|
this.setState({sidePanelSelected: this.state.myUserId ? 'edit-account' : 'settings'});
|
||||||
},
|
},
|
||||||
// User updated connection parameters - transport and server address
|
// User updated connection parameters - transport and server address
|
||||||
@@ -4069,13 +4096,16 @@
|
|||||||
// User clicked Cancel button in Setting or Sign Up panel.
|
// User clicked Cancel button in Setting or Sign Up panel.
|
||||||
handleSidepanelCancel: function() {
|
handleSidepanelCancel: function() {
|
||||||
if (this.state.myUserId) {
|
if (this.state.myUserId) {
|
||||||
|
window.location.hash = "/" + this.state.topicSelected;
|
||||||
this.setState({sidePanelSelected: 'contacts', errorText: '', errorLevel: null});
|
this.setState({sidePanelSelected: 'contacts', errorText: '', errorLevel: null});
|
||||||
} else {
|
} else {
|
||||||
|
window.location.hash = '';
|
||||||
this.setState({sidePanelSelected: 'login', errorText: '', errorLevel: null});
|
this.setState({sidePanelSelected: 'login', errorText: '', errorLevel: null});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// User clicked a (+) menu item.
|
// User clicked a (+) menu item.
|
||||||
handleNewTopic: function() {
|
handleNewTopic: function() {
|
||||||
|
window.location.hash = 'new';
|
||||||
this.setState({sidePanelSelected: 'new-topic'});
|
this.setState({sidePanelSelected: 'new-topic'});
|
||||||
},
|
},
|
||||||
// Create of a new topic. New P2P topic requires peer's name.
|
// Create of a new topic. New P2P topic requires peer's name.
|
||||||
@@ -4214,9 +4244,11 @@
|
|||||||
},
|
},
|
||||||
|
|
||||||
handleShowInfoView: function() {
|
handleShowInfoView: function() {
|
||||||
|
window.location.hash = addParamToHash(window.location.hash, 'info', true);
|
||||||
this.setState({showInfoPanel: true, infoPanelShowMembers: false});
|
this.setState({showInfoPanel: true, infoPanelShowMembers: false});
|
||||||
},
|
},
|
||||||
handleHideInfoView: function() {
|
handleHideInfoView: function() {
|
||||||
|
window.location.hash = removeParamFromHash(window.location.hash, 'info');
|
||||||
this.setState({showInfoPanel: false, infoPanelShowMembers: false});
|
this.setState({showInfoPanel: false, infoPanelShowMembers: false});
|
||||||
},
|
},
|
||||||
handleMemberUpdateRequest: function(topicName, added, removed) {
|
handleMemberUpdateRequest: function(topicName, added, removed) {
|
||||||
|
|||||||
Reference in New Issue
Block a user